#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
using i64 = long long;
using i32 = int;
using f64 = long double;
template <class T>
using vec = vector<T>;
using str = string;
using p64 = pair<i64, i64>;
using v64 = vec<i64>;
using vv64 = vec<v64>;
using s64 = set<i64>;
using m64 = map<i64, i64>;
template <size_t Size1>
using a64 = array<i64, Size1>;
template <size_t Size1, size_t Size2>
using aa64 = array<a64<Size2>, Size1>;
template <class T>
using hash_set = unordered_set<T>;
template <class T, class U>
using hash_map = unordered_map<T, U>;
mt19937 gen(998244353);
const i64 inf = numeric_limits<i64>::max() / 2;
template <class T>
inline i64 len(const T& a) {
  return (i64)(a.size());
}
inline void fast() { ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
template <class T, class S>
inline bool check_min(T& a, S b) {
  if (a > b) return a = b, 1;
  return 0;
}
template <class T, class S>
inline bool check_max(T& a, S b) {
  if (a < b) return a = b, 1;
  return 0;
}
void read() {}
template <class T, class... U>
void read(T& a, U&... b) {
  cin >> a;
  read(b...);
}
void print() {}
template <class T, class... U>
void print(const T& a, const U&... b) {
  cout << a << " ";
  print(b...);
}
void println() { cout << "\n"; }
template <class T, class... U>
void println(const T& a, const U&... b) {
  cout << a << " ";
  println(b...);
}
struct Problem {
  void files(str in, str out) {
    freopen(in.c_str(), "r", stdin), freopen(out.c_str(), "w", stdout);
  }
  void solve(), input();
  void many() {
    i64 t;
    cin >> t;
    while (t--) input(), solve();
  }
  void make(bool mt = 0) {
    if (mt)
      many();
    else
      input(), solve();
  }
} problem;
signed main() {
  fast();
  problem.make();
  return 0;
}
const i64 R = 1e9 + 7;
i64 n;
vec<p64> a;
vec<p64> ns;
i64 gcd(i64 a, i64 b) {
  while (b) {
    a %= b;
    swap(a, b);
  }
  return a;
}
i64 binary_power(i64 a, i64 n) {
  a %= R;
  if (n == 0) return 1;
  i64 ans = binary_power(a, n / 2);
  ans = ans * ans % R;
  if (n % 2 == 1) ans = ans * a % R;
  return ans;
}
i64 inv(i64 a) { return binary_power(a, R - 2); }
i64 prisoner_zero() {
  i64 to_add = 0;
  vec<p64> b;
  for (int i = 0; i < (n); i++) {
    if (a[i] != p64(0, 0)) {
      b.push_back(a[i]);
    } else {
      ++to_add;
    }
  }
  a = b;
  n = len(a);
  return to_add;
}
void Problem::solve() {
  i64 to_add = prisoner_zero();
  for (int i = 0; i < (n); i++) {
    i64 g = gcd(a[i].first, a[i].second);
    a[i].first /= g, a[i].second /= g;
    if (a[i].first < 0) {
      a[i].first = -a[i].first;
      a[i].second = -a[i].second;
    }
    if (a[i].first == 0 && a[i].second < 0) {
      a[i].second = -a[i].second;
    }
  }
  map<p64, i64> ms;
  for (int i = 0; i < (n); i++) {
    i64 v = a[i].first, u = a[i].second;
    ++ms[{v, u}];
  }
  i64 ans = 1;
  for (pair<p64, i64> p : ms) {
    if (!p.second) continue;
    i64 v, u;
    tie(v, u) = p.first;
    i64 nv = -u, nu = v;
    if (nv < 0) {
      nv = -nv, nu = -nu;
    }
    if (nv == 0 && nu < 0) {
      nu = -nu;
    }
    i64 bad = ms[{nv, nu}];
    i64 cur = binary_power(2, p.second);
    cur = (cur + binary_power(2, bad)) % R;
    cur = (cur + R - 1) % R;
    ans = ans * cur % R;
    ms[{nv, nu}] = 0;
  }
  ans = (ans - 1) % R;
  ans = (ans + to_add) % R;
  println(ans);
}
void Problem::input() {
  read(n);
  a.resize(n);
  for (int i = 0; i < (n); i++) read(a[i].first, a[i].second);
}
