#include <bits/stdc++.h>
using namespace std;
/* typedef */
typedef long long ll;
typedef pair<ll, ll> pll;
/* constant */
const int INF = 1 << 30;
const ll LINF = 1LL << 50;
const int NIL = -1;
const int MAX = 10000;
const int mod = 1000000007;
const double pi = 3.141592653589;
struct mint {
    ll x;
    mint(ll x = 0):x((x % mod + mod) % mod) {}
    mint operator-() const { return mint(-x); }
    mint& operator+=(const mint a) {
        if ((x += a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator-=(const mint a) {
        if ((x += mod - a.x) >= mod) x -= mod;
        return *this;
    }
    mint& operator*=(const mint a) {
        (x *= a.x) %= mod;
        return *this;
    }
    mint operator+(const mint a) const {
        mint res(*this);
        return res += a;
    }
    mint operator-(const mint a) const {
        mint res(*this);
        return res -= a;
    }
    mint operator*(const mint a) const {
        mint res(*this);
        return res *= a;
    }
    mint pow(ll t) const {
        if (!t) return 1;
        mint a = pow(t >> 1);
        a *= a;
        if (t & 1) a *= *this;
        return a;
    }
    // for prime mod
    mint inv() const {
        return pow(mod - 2);
    }
    mint& operator/=(const mint a) {
        return (*this) *= a.inv();
    }
    mint operator/(const mint a) const {
        mint res(*this);
        return res /= a;
    }
};
istream& operator>>(istream& is, const mint& a) { return is >> a.x;}
ostream& operator<<(ostream& os, const mint& a) { return os << a.x;}
struct combination {
    // vector size : n + 1
    vector<mint> fact, ifact;
    // precaliculation O(n)
    combination(int n):fact(n+1), ifact(n+1) {
        assert(n < mod);
        // 0! = 1;
        fact[0] = 1;
        // 1! = 0! * 1 ... n! = (n-1)! * n
        for (int i = 1; i <= n; i++) fact[i] = fact[i-1] * i;
        // 1/n! = n!^(-1)
        ifact[n] = fact[n].inv();
        // (n-1)!^(-1) = n!^(-1) * n ... 0!^(-1) = 1!^(-1) * 1
        for (int i = n; i >= 1; --i) ifact[i-1] = ifact[i] * i;
    }
    // combination O(1)
    // nCk = n! / (k! * (n-k)!)
    //     = n! * k!^(-1) * (n-k)!^(-1)
    mint operator()(int n, int k) {
        if (k < 0 || k > n) return 0;
        return fact[n] * ifact[k] * ifact[n-k];
    }
};
/* global variables */
/* function */
ll gcd(ll a, ll b) {
    ll tmp;
    while (b) { tmp = a; a = b; b = tmp % b; }
    return a;
}
/* main */
int main(){
    int N;
    cin >> N;
    // 以下は別々にカウント
    // (Ai, Bi) == (0, 0)
    // (Ai, Bi) == (Ai, 0)
    // (Ai, Bi) == (0, Bi)
    int cntABZero = 0, cntAZero = 0, cntBZero = 0;
    vector<pll> p;
    ll a, b;
    for (int i = 0; i < N; i++) {
        cin >> a >> b;
        if (a == 0 && b == 0) { cntABZero++; }
        else if (a == 0) cntAZero++;
        else if (b == 0) cntBZero++;
        else p.push_back(pll(a, b));
    }
    for (int i = 0; i < p.size(); i++) {
        ll d = gcd(p[i].first, p[i].second);
        p[i].first /= d; p[i].second /= d;
    }
    // Ai / Bi or Bj / Aj を引数とするが
    // gcd(Ai, Bi)で割ってから入れるので桁崩れるのを防ぐ
    map<pll, pll> mp;
    for (int i = 0; i < p.size(); i++) {
        ll x, y; tie(x, y) = p[i];
        int cnt = (x < 0) + (y < 0);
        if (cnt == 1) mp[pll(abs(x), abs(y))].first++;
        else mp[pll(abs(y), abs(x))].second++;
    }
    mint two = 2;
    mint ans = 1;
    for (auto m : mp) {
        ll x, y;
        tie(x, y) = m.second;
        // 基本的に各イワシについて選ぶか選ばないかの2通り
        // 被っているイワシはその中のいくつかを選ぶかで 2^(被り数)
        // 同じカゴに入れてはいけないイワシの集合も同様に計算
        // 一匹も選ばない選び方が2回計算されるので1引く
        ans *= two.pow(x) + two.pow(y) - 1;
    }
    // 片方が0の場合も計算
    ans *= two.pow(cntAZero) + two.pow(cntBZero) - 1;
    // (0, 0)の場合はどれとも一緒に選べないのでその個数分加算
    ans += cntABZero;
    // どのイワシも選ばない1通りを引いておく
    ans -= 1;
    cout << ans << '\n';
}


Measured memory_bytes: 21712