// dfmt off
T lread(T=long)(){return readln.chomp.to!T;}T[] lreads(T=long)(long n){return iota(n).map!((_)=>lread!T).array;}
T[] aryread(T=long)(){return readln.split.to!(T[]);}void arywrite(T)(T a){a.map!text.join(' ').writeln;}
void scan(L...)(ref L A){auto l=readln.split;foreach(i,T;L){A[i]=l[i].to!T;}}alias sread=()=>readln.chomp();
void dprint(L...)(lazy L A){debug{auto l=new string[](L.length);static foreach(i,a;A)l[i]=a.text;arywrite(l);}}
static immutable MOD=10^^9+7;alias PQueue(T,alias l="b<a")=BinaryHeap!(Array!T,l);import std;
// dfmt on

void main()
{
    long N = lread();
    auto A = new long[](N);
    auto B = new long[](N);
    foreach (i; 0 .. N)
        scan(A[i], B[i]);
    auto C = new long[](N);
    foreach (i; 0 .. N)
        C[i] = A[i] * B[i];
    auto I = iota(N).array;
    zip(C, I).sort();
    long m = C[0];
    long M = C[$ - 1];
    auto SC = assumeSorted(C);
    long cnt;
    foreach (i; 0 .. N)
    {
        long c = C[i];
        long k = 1;
        long tmp = ((k * k) / c);
        while (m <= tmp && tmp <= M)
        {
            if (k * k % c != 0)
            {
                k++;
                tmp = -((k * k) / c);
                continue;
            }
            long num;
            if (tmp * c < 0 && c < tmp)
            {
                num += SC.upperBound(tmp - 1).lowerBound(tmp + 1).length;
            }
            if (0 < -tmp * c && -tmp < c)
            {
                num += SC.upperBound(-tmp - 1).lowerBound(-tmp + 1).length;
                // dprint(num);
            }
            if (0 < num)
            {
                // dprint(i, c, num, SC.upperBound(tmp - 1).lowerBound(tmp + 1),
                //         SC.upperBound(-tmp - 1).lowerBound(-tmp + 1));
                cnt += num;
            }
            k++;
            tmp = -((k * k) / c);
        }
    }
    long ans = powmod(2, N);
    auto comb = Combination_mod(N);
    foreach (i; 1 .. N)
    {
        if (i <= cnt)
        {
            dprint(i, N - i);
            if (i % 2 == 0)
            {
                ans += powmod(2, N - i - 1) * comb(cnt, i) - 1;
                ans %= MOD;
            }
            else
            {
                ans += MOD - powmod(2, N - i - 1) * comb(cnt, i) - 1;
                ans %= MOD;
            }
        }
    }
    writeln(ans);
}

/// x^^n % m
T powmod(T = long)(T x, T n, T m = 10 ^^ 9 + 7)
{
    if (n < 1)
        return 1;
    if (n & 1)
    {
        return x * powmod(x, n - 1, m) % m;
    }
    T tmp = powmod(x, n / 2, m);
    return tmp * tmp % m;
}

/// Number of k-combinations % m (precalculated)
alias Combination_mod = Combination_modImpl!long;
struct Combination_modImpl(T)
{
    T _n, _m;
    T[] _fact, _factinv;
    this(T maxnum, T mod = 10 ^^ 9 + 7)
    {
        _n = maxnum, _m = mod, _fact = new T[](_n + 1), _factinv = new T[](_n + 1), _fact[0] = 1;
        foreach (i; 1 .. _n + 1)
            _fact[i] = _fact[i - 1] * i % _m;
        T powmod(T x, T n, T m)
        {
            if (n < 1)
                return 1;
            if (n & 1)
            {
                return x * powmod(x, n - 1, m) % m;
            }
            T tmp = powmod(x, n / 2, m);
            return tmp * tmp % m;
        }

        foreach (i; 0 .. _n + 1)
            _factinv[i] = powmod(_fact[i], _m - 2, _m);
    }

    T opCall(T n, T k, T dummy = 10 ^^ 9 + 7)
    {
        return n < k ? 0 : ((_fact[n] * _factinv[n - k] % _m) * _factinv[k] % _m);
    }
}
