#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
using DD = long double;
ll mod =1e9+7;
#define rep(i,n) for(int i=0;i<n;i++)
#define rep2(i,a,b) for(int i=(a);i<(b);++i)

template<class T> T maxt(T x,T y) {if (x>y) return x;else return y;}
template<class T> T mint(T x,T y) {if (x>y) return y;else return x;}
//sort(v.begin(), v.end(), [](auto& x, auto& y){return x[1] < y[1];});


//小数出力
int print_double(double d){printf("%.15lf\n", d);return 0;}

//vector出力
template <class T>ostream &operator<<(ostream &o,const vector<T>&v){
  o<<"{";
  for(int i=0;i<(int)v.size();i++) o << (i>0?", ":"") << v[i];
  o<<"}";
  return o;
}

//約数列挙
vector<ll> divisor(ll n) {
  vector<ll> ret;
  for(ll i = 1; i * i <= n; i++) {
    if(n % i == 0) {
      ret.push_back(i);
      if(i * i != n) ret.push_back(n / i);
    }
  }
  sort(begin(ret), end(ret));
  return (ret);
}

//逆元　a/b の modをとるとき -> a*modinv(b)%mod
long long modinv(long long a, long long m = 1e9+7) {
  long long b = m, u = 1, v = 0;
  while (b) {
    long long t = a / b;
    a -= t * b; swap(a, b);
    u -= t * v; swap(u, v);
  }
  u %= m; 
  if (u < 0) u += m;
  return u;
}

// ll combination_mod(int n, int k) {
//   k = mint(k,n-k);
//   ll ans = 1;
//   if (n==0 || k ==0) return ans;
//   rep(i,k) {
//     ans = ans*(n-i)%mod;
//     ans = ans*modinv(i+1)%mod;
//   }
//   return ans;
// }



struct edge {
  int from; //出発点
  int to;   //到達点
  ll cost; //移動コスト
};

//ベルマンフォード法
vector<ll> bellman_ford (vector<edge> edges, int V, int E, int r, ll INF = 100000000000) {  
  vector<ll> cost_to(V,INF);
  cost_to[r] = 0;
  rep(i,V) {
    rep(j,E) {
      edge e = edges[j];
      if (cost_to[e.from]==INF) continue;
      if (cost_to[e.to] > cost_to[e.from] + e.cost) {
        cost_to[e.to] = cost_to[e.from] + e.cost;
        if (i==V-1) {
          printf("NEGATIVE CYCLE\n");
          return {};
        }
      }

    }
  }
  return cost_to;
}

// combination
const int MAX = 510000;
const int MOD = 1000000007;
 
long long fac[MAX], finv[MAX], inv[MAX];
 
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

// べき乗
int64_t modpow(int64_t x, int64_t n) {
    x = x%MOD;
    if(n==0) return 1;  //再帰の終了条件

    else if(n%2==1) {
        return (x*modpow(x, n-1))%MOD;  //nが奇数ならnを1ずらす
    }
    else return modpow((x*x)%MOD, n/2)%MOD;  //nが偶数ならnが半分になる
}

//素因数分解
vector<pair<long long, long long> > prime_factorize(long long n) {
    vector<pair<long long, long long> > res;
    for (long long p = 2; p * p <= n; ++p) {
        if (n % p != 0) continue;
        int num = 0;
        while (n % p == 0) { ++num; n /= p; }
        res.push_back(make_pair(p, num));
    }
    if (n != 1) res.push_back(make_pair(n, 1));
    return res;
}

template<class T> inline void chmin(T& a, T b) {if (a > b) a = b;}
template<class T> inline void chmax(T& a, T b) {if (a < b) a = b;}


// 木上の探索
vector<int> cnt;
void dfs(const vector<vector<int>> &G, int v, int p) {
    for (auto nv : G[v]) {
        if (nv == p) continue; // nv が親 p だったらダメ
        dfs(G, nv, v);
    }

    // 帰りがけ時に、部分木サイズを求める
    cnt[v] = 1; // 自分自身
    for (auto c : G[v]) {
        if (c == p) continue;
        cnt[v] += cnt[c]; // 子のサイズを加える
    }
}


// dfs2
// int seen[2000000];  // 1:現在探索中のパスで行きがけ 2:探索後の頂点
// int d[2000000];     // d[i]:= 始点から i への距離
// int dfs(const vector<vector<int>> &G, int now) {
//     if (seen[now] == 2) return d[now];
//     seen[now] = 1;
//     for (auto e : G[now]) {
//         if (seen[e] == 1) {  // 閉路を検出
//             cout << -1 << endl;
//             exit(0);
//         }
//         chmax(d[now], dfs(G, e) + 1);
//     }
//     seen[now] = 2;
//     return d[now];
// }


int main() {
  int N,cnt0=0,jg;
  ll ix1,ix2,ans=1,a,b;
  cin >> N;
  vector<vector<ll>> ab;

  rep(i,N) {
    cin >> a >> b;
    if (a==0&&b==0) cnt0++;
    else{
      if (b==0) a=1;
      else if (a==0) b=1;
      else {
        ll t = __gcd(a,b);
        a/=t;b/=t;
      }
      if (b<0) {a*=-1;b*=-1;}
    }
    if (a<=0 && b>0) ab.push_back({b,-a,1});
    else if (a>0&&b>=0) ab.push_back({a,b,0});
  }
  sort(ab.begin(),ab.end());

  // cout << ab << endl;
  ll b1=-1,b2=-1,bjg=-1,tmp0=0,tmp1=0;
  for (auto i:ab) {
    if (i[0]==b1 && i[1]==b2) {
      // cout << "##\n";
      if (bjg==i[2]) {
        if (bjg==0) tmp0++;
        else tmp1++;
      }
      else {
        if (i[2]==1) tmp1++;
        else tmp0++;
      }
    }
    else {
      // cout << tmp0 << ' ' << tmp1 << endl;
      ans *= (modpow(2,tmp0) + modpow(2,tmp1) -1)%mod;
      ans%=mod;
      b1=i[0];b2=i[1];bjg=i[2];
      tmp0=0;tmp1=0;
      if (bjg==0) tmp0++;
      else tmp1++;
    }
  }
  ans *= (modpow(2,tmp0) + modpow(2,tmp1) -1)%mod;
  ans%=mod;
  ans--;
  ans += cnt0;
  cout << ans%mod << endl;
}
