#include <bits/stdc++.h>
using namespace std;
using ll=long long;
#define rep(i,n) for (ll i=0; i<n; ++i)
#define all(c) begin(c),end(c)
template<typename T1, typename T2>
bool chmax(T1 &a,T2 b){if(a<b){a=b;return true;}else return false;}
template<typename T1, typename T2>
bool chmin(T1 &a,T2 b){if(a>b){a=b;return true;}else return false;}
/*
まず1匹ずつ。
3
1 2
-1 1
2 -1

13
1*2 + 2*-1 = 0
123
1*-1*2 + 2*1*-1 =-4
ああ、13がだめだから。

1 2
とりあえず1引数を正に。
1 2

-2 1
2 -1
がだめ。

gcdでいれる
2^N - 1 が全通り。
OKのやつ同士の組み合わせ数


1 = 1
2 = +2
3 = +4
2 = 2がだめ。+4

ちがう
DPか
*/
int main(){
  cin.tie(0);
  ios::sync_with_stdio(0);
  
  ll MOD = 1e9+7, N; cin >> N;
  vector<ll> DP(200010, 0);
  vector<pair<ll, ll>> fish(N, {0,0});
  rep(i, N){
    ll a, b; cin >> a >> b;
    if (a < 0){
      a *= -1;
      b *= -1;
    }
    ll c = gcd(a, b);
    if (c){
      a /= c;
      b /= c;
    }
    fish[i] = {a, b};
  }
  
  map<pair<ll,ll>, ll> M;//だめなやつカウントかな
  ll ans = 0;
  rep(i, N){
    ans %= MOD;
    auto now = fish[i];
    ll n1 = now.first;
    ll n2 = now.second;
//cout<<n1<<" "<<n2<<" ans:"<<ans<<endl;
    if (n1 == 0 && n2 == 0){
      ans++;
      DP[i+1] = ans;
      continue;
    }
    if (n1 == 0){
      ans += DP[i-M[{1,0}]] + 1;
      M[{0, 1}]++;
      DP[i+1] = ans;
      continue;
    }
    if (n2 == 0){
      ans += DP[i-M[{0,1}]] + 1;
      M[{1, 0}]++;
      DP[i+1] = ans;
      continue;
    }
    ll nn2 = n2;
    ll nn1 = n1;
    if (nn2 < 0)
      nn2 *= -1;
    else
      nn1 *= -1;
//cout<<"ant:"<< nn2<<" " << nn1<<"M:"<<M[{nn2,nn1}]<<" i:"<<i<<endl;    
    ans += DP[i-M[{nn2, nn1}]] + 1;
    DP[i+1] = ans;
    M[{n1, n2}]++;
  }
  ans %= MOD;
  cout<<ans<<endl;
//  rep(i, N)cout<<" DP["<<i<<"]:"<<DP[i]<<endl;
}
