#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template <class T>
struct arr : public vector<T> {
  arr() {}
  arr(ll n, T v = T()) : vector<T>(n, v) {}
  void init(ll n, T v = T()) {
    this->clear();
    this->resize(n, v);
  }
  ll sz() const { return (ll)this->size(); }
  void pb(T v) { this->push_back(v); }
  void sort() { std::sort(this->begin(), this->end()); }
  void rsort() { std::sort(this->begin(), this->end(), greater<T>()); }
};
using ints = arr<ll>;
using intss = arr<arr<ll>>;
template <class T>
struct que : public queue<T> {
  ll sz() const { return (ll)this->size(); }
  T popfront() {
    T v = this->front();
    this->pop();
    return v;
  }
};
using pint = pair<ll, ll>;
istream& myInputStream = cin;
ostream& myOutputStream = cout;
struct input {
  template <class A, class B>
  void exec(pair<A, B>& var) {
    myInputStream >> var.first >> var.second;
  }
  template <class T>
  void exec(T& var) {
    myInputStream >> var;
  }
  template <class T>
  operator T() {
    T var;
    exec(var);
    return var;
  }
} input;
struct inputs {
  ll n;
  inputs(ll n_) : n(n_) {}
  template <class T>
  operator arr<T>() {
    arr<T> var(n);
    for (ll i = 0, i_size = n; i < i_size; ++i) {
      var[i] = (T)input;
    };
    return var;
  }
};
template <class T>
void output(T var) {
  myOutputStream << (var) << '\n';
}
template <class T>
void chmin(T& a, T b) {
  if (b < a) {
    a = b;
  }
}
template <class T>
void chmax(T& a, T b) {
  if (b > a) {
    a = b;
  }
}
ll gcd(ll a, ll b) {
  if (a < b) {
    return gcd(b, a);
  }
  ll r;
  for (;;) {
    if (b == 0) {
      break;
    }
    r = a % b;
    a = b;
    b = r;
  }
  return a;
}
struct bfs {
  ints froms;
  ints steps;
  bfs(ll N, intss const& adjacency) {
    froms.init(N, -1);
    steps.init(N, -1);
    que<ll> queue;
    queue.push(0);
    froms[0] = 0;
    steps[0] = 0;
    while (queue.empty() == false) {
      ll p = queue.popfront();
      for (ll n : adjacency[p]) {
        if (froms[n] != -1) {
          continue;
        }
        froms[n] = p;
        steps[n] = steps[p] + 1;
        queue.push(n);
      }
    }
  }
};
template <ll MOD>
struct modint {
  ll raw;
  modint() { raw = 0; }
  modint(ll v) {
    raw = v;
    if (raw >= MOD) {
      raw %= MOD;
    }
  }
  modint operator+(modint v) const { return modint(raw) += v; }
  modint operator-(modint v) const { return modint(raw) -= v; }
  modint operator*(modint v) const { return modint(raw) *= v; }
  modint& operator+=(modint v) {
    raw += v.raw;
    if (raw >= MOD) {
      raw -= MOD;
    }
    return *this;
  }
  modint& operator-=(modint v) {
    raw -= v.raw;
    if (raw < 0) {
      raw += MOD;
    }
    return *this;
  }
  modint& operator*=(modint v) {
    raw = (raw * v.raw) % MOD;
    return *this;
  }
  friend ostream& operator<<(ostream& os, modint const& m) {
    return os << m.raw;
  }
};
void myMain();
signed main() {
  cin.tie(0);
  ios::sync_with_stdio(0);
  cout << fixed << setprecision(16);
  myMain();
  return 0;
}
using mint = modint<1000000007>;
void myMain() {
  ll N;
  arr<pint> iwashis;
  map<pint, ll> rateCounts;
  N = input;
  iwashis = inputs(N);
  ll zeroCount = 0;
  for (ll i = 0, i_size = N; i < i_size; ++i) {
    auto const& W = iwashis[i];
    if (W.first == 0 && W.second == 0) {
      ++zeroCount;
    } else if (W.first == 0) {
      pint rate;
      rate.first = 0;
      rate.second = 1;
      rateCounts[rate] += 1;
    } else if (W.second == 0) {
      pint rate;
      rate.first = 1;
      rate.second = 0;
      rateCounts[rate] += 1;
    } else {
      ll d = gcd(abs(W.first), abs(W.second));
      pint rate;
      rate.first = W.first / d;
      rate.second = W.second / d;
      if (rate.second < 0) {
        rate.first = -rate.first;
        rate.second = -rate.second;
      }
      rateCounts[rate] += 1;
    }
  }
  ints powTbl(N + 1);
  powTbl[0] = 1;
  for (ll i = 0, i_size = N; i < i_size; ++i) {
    powTbl[i + 1] = (powTbl[i] * 2) % 1000000007;
  }
  mint ans = 1;
  while (rateCounts.size()) {
    auto const& W = rateCounts.begin();
    pint rate = W->first;
    pint badRate(-rate.second, rate.first);
    if (badRate.second < 0) {
      badRate.first = -badRate.first;
      badRate.second = -badRate.second;
    }
    if (badRate.first == 0) {
      badRate.second = 1;
    } else if (badRate.second == 0) {
      badRate.first = 1;
    }
    auto it = rateCounts.find(badRate);
    if (it == rateCounts.end()) {
      ans *= powTbl[W->second];
      rateCounts.erase(W);
      continue;
    }
    ans *= powTbl[W->second + it->second] -
           (powTbl[W->second] - 1) * (powTbl[it->second] - 1);
    rateCounts.erase(W);
    rateCounts.erase(it);
  }
  ans += zeroCount;
  ans -= 1;
  output(ans);
}
