#ifndef DBG
//#define NDEBUG
#pragma GCC optimize("Ofast")
#pragma GCC target("popcnt")
#endif // DBG
#include <bits/stdc++.h>
using namespace std;

#define cn const
#define cauto cn auto
#define FOR(i, from, to) for (int i = (from); i <= int(to); ++i)
#define FORN(i, n) FOR(i, 0, (n) - 1)
#define endl '\n'
#define mp make_pair
#define pb push_back
#define F first
#define S second
#define X F
#define Y S
#define CONT(c) begin(c), end(c)
#define ARR(a, sz) (a), ((a) + (sz))

using ll = long long;
using ull = unsigned long long;
using ulong = unsigned long;
using uint = unsigned;


//#undef DBG
#ifdef DBG
cn bool dbg = true;
#else
cn bool dbg = false;
#endif // DBG

#ifdef MY
cn bool my = true;
#else
cn bool my = false;
#endif // MY

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
template<typename Key>
using ordered_set = __gnu_pbds::tree<Key, __gnu_pbds::null_type, less<Key>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
template<typename Key, typename Value>
using ordered_map = __gnu_pbds::tree<Key, Value, less<Key>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;

template<typename T>
constexpr T sqr(const T& x)
{
    return x * x;
}

template<typename T>
bool rMin(T& v, const T& rval)
{
    if (rval < v) {
        v = rval;
        return true;
    }
    return false;
}

template<typename T>
bool rMax(T& v, const T& rval)
{
    if (v < rval) {
        v = rval;
        return true;
    }
    return false;
}

ll rd()
{
    ll x;
    cin >> x;
    assert(cin);
    return x;
}

template<int Modulo>
struct MOD {
    static cn int M = Modulo;
    uint x;
    constexpr MOD(int val = 0) : x(val) { assert(0 <= val && val < M); }

    constexpr MOD& operator +=(MOD r) {
        x += r.x;
        if (x >= M)
            x -= M;
        return *this;
    }
    friend constexpr MOD operator +(MOD l, MOD r) { return l += r; }

    constexpr MOD& operator *=(MOD r) {
        x = (ll(x) * r.x) % M;
        return *this;
    }
    friend constexpr MOD operator *(MOD l, MOD r) { return l *= r; }

    constexpr MOD& operator -=(MOD r) {
        x -= r.x;
        if (x >= M)
            x += M;
        return *this;
    }
    friend constexpr MOD operator -(MOD l, MOD r) { return l -= r; }

    friend constexpr MOD operator -(MOD a) {
        if (a.x)
            return M - a.x;
        return 0;
    }

    friend ostream& operator <<(ostream& os, MOD x) { return os << x.x; }
    friend constexpr bool operator ==(MOD l, MOD r) { return l.x == r.x; }
    friend constexpr bool operator <(MOD l, MOD r) { return l.x < r.x; }
};

namespace std {
template<int Modulo>
struct hash<MOD<Modulo>> {
    size_t operator ()(MOD<Modulo> a) const noexcept { return a.x; }
};
}

using Mersen32Mod = MOD<(1LL << 31) - 1>;
template<>
Mersen32Mod& Mersen32Mod::operator *=(Mersen32Mod r) {
    cauto mul = ll(x) * r.x;
    x = (mul >> 31) + (mul & M);
    if (x >= M)
        x -= M;
    return *this;
}

template<int M>
constexpr MOD<M> binpow(MOD<M> a, ll p)
{
    MOD<M> res = 1;
    while (p != 0) {
        if (p % 2)
            res *= a;
        a *= a;
        p /= 2;
    }
    return res;
}

struct DoubleHash {
    uint r1;
    Mersen32Mod r2;

    DoubleHash(int x = 0) {
        r1 = x;
        r2 = x;
    }
    DoubleHash(initializer_list<int> lst) {
        assert(lst.size() == 2);
        auto it = lst.begin();
        r1 = *it++;
        r2 = *it;
    }

    DoubleHash& operator +=(DoubleHash R) {
        r1 += R.r1;
        r2 += R.r2;
        return *this;
    }
    friend DoubleHash operator +(DoubleHash L, DoubleHash R) {
        return L += R;
    }

    DoubleHash& operator -=(DoubleHash R) {
        r1 -= R.r1;
        r2 -= R.r2;
        return *this;
    }
    friend DoubleHash operator -(DoubleHash L, DoubleHash R) {
        return L -= R;
    }

    DoubleHash& operator *=(DoubleHash R) {
        r1 *= R.r1;
        r2 *= R.r2;
        return *this;
    }
    friend DoubleHash operator *(DoubleHash L, DoubleHash R) {
        return L *= R;
    }

    friend bool operator ==(DoubleHash L, DoubleHash R) {
        return L.r1 == R.r1 && L.r2 == R.r2;
    }

    friend bool operator <(DoubleHash L, DoubleHash R) {
        return mp(L.r1, L.r2) < mp(R.r1, R.r2);
    }

    size_t hash() const {
        return r2.x;
    }
};

namespace std {
template<>
struct hash<DoubleHash> {
    auto operator ()(DoubleHash h) const noexcept { return h.hash(); }
};
}

//#include "limits.h"

using Mod = MOD<1000000007>;

map<pair<ll, ll>, int> cnt;

#define abs abs1
#define gcd gcd1

ll abs(ll x)
{
    if (x < 0)
        return -x;
    return x;
}

ll gcd(ll x, ll y)
{
    while (y != 0) {
        cauto t = x % y;
        x = y;
        y = t;
    }
    return x;
}

pair<ll, ll> norm(ll x, ll y)
{
    if (x == 0)
        y = abs(y);
    if (x < 0) {
        x = -x;
        y = -y;
    }
    cauto d = gcd(abs(x), abs(y));
    if (d != 0) {
        x /= d;
        y /= d;
    }
    return {x, y};
}

pair<ll, ll> col(pair<ll, ll> p)
{
    return norm(-p.Y, p.X);
}

int main()
{
#ifdef MY
    freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
#else
    #define FILEIO(TASK) do { freopen(TASK".in", "r", stdin); freopen(TASK".out", "w", stdout); } while (false)
    //FILEIO("penguins");
    ios_base::sync_with_stdio(false);
    cin.tie(0);
#endif // MY
    int n = rd();
    FORN(i, n) {
        ll x, y;
        cin >> x >> y;
        cauto dr = norm(x, y);
        ++cnt[dr];
    }
    Mod sp = cnt[{0, 0}];
    cnt.erase({0, 0});
    Mod ans = 1;
    while (cnt.size()) {
        cauto p = *cnt.begin();
        cauto cp = col(p.F);
        Mod cur = binpow(Mod(2), p.S) + binpow(Mod(2), cnt[cp]) - 1;
        ans *= cur;
        cnt.erase(p.F);
        cnt.erase(cp);
    }
    ans -= 1;
    cout << ans + sp;
}




Measured memory_bytes: 16092