#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>  
#include <ext/pb_ds/tree_policy.hpp>   
using namespace std;
using namespace __gnu_pbds;  
typedef tree<int, null_type, less<int>, rb_tree_tag,  tree_order_statistics_node_update>  ordered_set; 
#define num 1000000007
//#define num 998244353
#define REP(i,a,n) for(ll i=a;i<n;i++)
#define inarr(i,a,n,A) for(ll i=a;i<n;i++) { cin>>A[i]; }
#define vll vector<long long>
#define pii pair <int,int>
#define pll pair<long long, long long>
#define vpii vector< pair <int,int>>
#define vpll vector< pair<long long, long long>>
//#define max(a,b) ((a>b)?a:b)
//#define min(a,b) ((a>b)?b:a)
#define max3(a,b,c) ((a>b)?(a>c)?a:c:(b>c)?b:c)
#define min3(a,b,c) ((a<b)?(a<c)?a:c:(b<c)?b:c)
#define avg(a,b) ((a)+(b))/2
#define pb push_back
#define pob pop_back
#define sf int flag=0     //Remember semicolon
// #define assmin(a,b) if(b<=a) { a=b; }
// #define assmax(a,b) if(b>=a) { a=b; }
#define f first
#define s second
#define fix(f,n) std::fixed<<std::setprecision(n)<<f
#define all(x) x.begin(), x.end()
#define M_PI 3.14159265358979323846
#define epsilon (double)(0.00000000001)
#define side 1e9
#define watch(x) cout << (#x) << " is " << (x) << endl
typedef long long ll;
 
ll mod_exp(ll a, ll b, ll c)
{
	ll res=1;
	a=a%c;
	while(b>0)
	{
		if(b%2==1)
		{
			res=(res*a)%c;
		}
		b/=2;
		a=(a*a)%c;
	}
	return res;
}
ll mymod(ll a,ll b)
{
    return ((a%b)+b)%b;
}
// bool prime[200001];
// void SieveOfEratosthenes() 
// { 
//     memset(prime, true, sizeof(prime)); 
//     prime[1]=false;
//     for (int p=2; p*p<=200000; p++) 
//     { 
//         if (prime[p] == true) 
//         { 
//             for (int i=p*p; i<=200000; i += p) 
//                 prime[i] = false; 
//         } 
//     } 
//     return;
// }
// ll powe[200005];
// void power()
// {
//     powe[0]=1;
//     REP(i,1,200005)
//     {
//         powe[i]=mymod(2*powe[i-1],num);
//     }
// }
// ll gcdExtended(ll,ll,ll *,ll *);
// ll modInverse(ll a, ll m) 
// { 
//     ll x, y; 
//     ll g = gcdExtended(a, m, &x, &y); 
//         ll res = (x%m + m) % m;
//         return res;
// } 
// ll gcdExtended(ll a, ll b, ll *x, ll *y) 
// { 
//     if (a == 0) 
//     { 
//         *x = 0, *y = 1; 
//         return b; 
//     } 
//     ll x1, y1; 
//     ll gcd = gcdExtended(b%a, a, &x1, &y1); 
//     *x = y1 - (b/a) * x1; 
//     *y = x1; 
//     return gcd; 
// }
// struct node
// {
// 	vll adj;
//     ll indegree;
// };

ll seg_tree[487348];

void build(ll pre[], ll v, ll left, ll right)
{
    if(left==right)
    {
        seg_tree[v] = pre[left];
        return;
    }
    else
    {
        ll mid = (left+right)/2;
        build(pre, 2*v, left, mid);
        build(pre,2*v+1, mid+1, right);
        seg_tree[v] = max(seg_tree[2*v], seg_tree[2*v+1]);
    }
}
ll query(ll v, ll left, ll right, ll l, ll r)
{
    if(l>r)
    {
        return LLONG_MIN;
    }
    if(left==l && right==r)
    {
        return seg_tree[v];
    }
    ll mid=(left+right)/2;
    ll a = query(2*v, left, mid, l, min(r,mid));
    ll b = query(2*v+1, mid+1, right, max(l,mid+1), r);
    return max(a,b);
}

ll solve(vector<vll> v, ll x)
{
    ll n = v.size();
    ll m = v[0].size();
    ll dp[n][m];
    REP(i,0,n)
    {
        REP(j,0,m)
        {
            dp[i][j] = 1e18;
        }
    }
    dp[0][0]=v[0][0] - x;
    REP(i,0,n)
    {
        REP(j,0,m)
        {
            if(v[i][j]<x) continue;
            if(!i && !j) continue;
            else if(i==0)
            {
                dp[i][j] = (dp[i][j-1] + v[i][j] - x);
            }
            else if(j==0)
            {
                dp[i][j] = (dp[i-1][j] + v[i][j] - x);
            }
            else
            {
                dp[i][j] = min(dp[i][j-1], dp[i-1][j]) + v[i][j] - x;
            }
        }
    }
    return dp[n-1][m-1];
}

double solve(ll h, ll m)
{
    double a1 = h*30.0 + (m/60.0)*30.0;
    double a2 = 6.0*m;
    return abs(a2-a1);
}
void reduce(ll &a, ll &b)
{
    if(a==0 && b==0) return;
    ll g=__gcd(a,b);
    a/=g;
    b/=g;
    if(b<0) { a*=-1; b*=-1;}
    return;
}
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    ll n;
    cin>>n;
    map<pll,ll> m;
    map<pll,ll> done;
    REP(i,0,n)
    {
        ll a,b;
        cin>>a>>b;
        reduce(a,b);
        m[{a,b}]++;
    }
    vpll v;
    ll ind=0;
    for(auto itr=m.begin(); itr!=m.end(); ++itr)
    {
        if(done[itr->first])
        {
            continue;
        }
        pll search = {-itr->first.s, itr->first.f};
        if(itr->first.f<0)
        {
            search.f*=-1;
            search.s*=-1;
        }
        if(m.find(search)==m.end())
        {
            ind+=itr->second;
            done[itr->first]=true;
        }
        else
        {
            v.pb({itr->second, m[search]});
            done[search] = done[itr->first] = 1;
        }
        done[itr->first] = 1;
    }
    ll ans = mod_exp(2, ind, num);
    for(auto x: v)
    {
        ll temp = mymod(mod_exp(2,x.f,num) + mod_exp(2,x.s,num) -1, num);
        ans = mymod(ans*temp, num);
    }
    ans--;
    cout<<ans<<"\n";
    return 0;
}