//#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <map>
#include <set>
#include <unordered_map>
#include <chrono>
//#include <queue>
//#include <stack>
#include <cstring>
#include <cassert>

using namespace std;

#ifdef LOCAL_DEBUG
#include <local_debug.h>
#define DEBUG(x...) cerr << __LINE__ << ": " << #x << " = "; DBG::_print(x)
#else
#define DEBUG(x...)
#endif

#define SZ(a) int((a).size())
#define REP(i,n) for(int i=0,_n=(n);i<_n;++i)
#define FOR(i,a,b) for(int i=(a),_b=(b);i<=_b;++i)

typedef long long llong;
typedef vector<int> VI;
typedef vector<VI> VVI;

llong gcd(llong a, llong b) {
   if (a < 0) a = -a;
   if (b < 0) b = -b;
   if (a < b) swap(a, b);
   while (b > 0) {
      llong t = b;
      b = a % b;
      a = t;
   }
   return a > 0 ? a : 1;
}

long long powmod(long long x, long long n, unsigned int m) {
   long long res = 1 % m;
   x %= m;
   for (; n > 0; n >>= 1) {
      if (n & 1) {
         res = (res * x) % m;
      // n--;
      }
      x = (x * x) % m;
   }
   return res;
}

const size_t SEED = chrono::high_resolution_clock::now().time_since_epoch().count();


struct Fraction {
   llong num, den;
   Fraction(llong n, llong d) {
      llong g = gcd(n, d);
      num = n / g;
      den = d / g;
      if (den < 0) {
         num = -num;
         den = -den;
      }
      if (den == 0)
         num = 1;
   }
   bool operator==(const Fraction& f) const {
      return num == f.num && den == f.den;
   }
   string to_string() const {
      return std::to_string(num) + "/" + std::to_string(den);
   }
};

struct FractionHash {
   size_t operator()(const Fraction& f) const {
      size_t res = hash<long long>{}(f.num ^ (f.den << 2));
      return hash<int>{}(res ^ SEED);
   }
};

const int MOD = 1e9 + 7;

int solve(int N, const vector<llong>& A, const vector<llong>& B) {
   int cnt_zeros = 0;
   unordered_map< Fraction, int, FractionHash > freq;
   REP(i, N) {
      llong x = A[i], y = B[i];
      if (x == 0 && y == 0)
         ++cnt_zeros;
      else
         ++freq[Fraction(x, y)];
   }

   if (cnt_zeros == N)
      return N;


   llong res = 1;
   while (!freq.empty()) {
      auto it1 = freq.begin();
      Fraction f = it1->first;
      int cnt1 = it1->second;
      freq.erase(it1);

      llong factor = 0;

      // try to match forbidden pairs of sardines
      Fraction invf(-f.den, f.num);
      auto it2 = freq.find(invf);
      if (it2 != freq.end()) {
         int cnt2 = it2->second;
         freq.erase(it2);
         factor = powmod(2, cnt1, MOD)-1 // select non-empty subset of first set of sardines
                + powmod(2, cnt2, MOD)-1  // select non-empty subset of second set of sardines
                + 1;  // select none of sardines
         if (factor >= MOD)
            factor -= MOD;
      }
      else
         factor = powmod(2, cnt1, MOD);  // select a subset of these sardines

      res = (res * factor) % MOD;
   }
  
   res += cnt_zeros;
   if (res >= MOD)
      res -= MOD;
   
   res--;
   if (res < 0)
      res += MOD;
   
   return res;
}

int main(int argc, char* argv[]) {
   ios_base::sync_with_stdio(false); 
   cin.tie(nullptr);

   int N;
   cin >> N;
   vector<llong> A(N), B(N);
   REP(i, N)
      cin >> A[i] >> B[i];

   int res = solve(N, A, B);
   cout << res << '\n';

   return 0;
}


Measured memory_bytes: 17740