#include <bits/stdc++.h>
using namespace std;

struct init_ { init_(){ cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(10); } } init_;

template<class C> using iodef_rng_t = typename enable_if<decltype(declval<C>().begin(), true_type{})::value && !is_same<C, string>::value>::type;
template<class C, class = iodef_rng_t<C>> istream& operator>>(istream& in, C& c) { for (auto& v : c) { in >> v; } return in; }
template<class C, class = iodef_rng_t<C>> ostream& operator<<(ostream& out, const C& c) { int i = 0; for (const auto& v : c) { if (i++) { out << ' '; } out << v; } return out; }
template<size_t N, class T, class R> using when_last = typename enable_if<N == tuple_size<remove_reference_t<T>>::value - 1, R>::type;
template<size_t N, class T, class R> using when_init = typename enable_if<N != tuple_size<remove_reference_t<T>>::value - 1, R>::type;
template<size_t N = 0, class T> auto operator>>(istream& in, T&& t) -> when_last<N, T, istream&> { return in >> get<N>(t); }
template<size_t N = 0, class T> auto operator>>(istream& in, T&& t) -> when_init<N, T, istream&> { return operator>><N + 1>(in >> get<N>(t), forward<T>(t)); }
template<size_t N = 0, class T> auto operator<<(ostream& out, const T& t) -> when_last<N, T, ostream&> { return out << get<N>(t); }
template<size_t N = 0, class T> auto operator<<(ostream& out, const T& t) -> when_init<N, T, ostream&> { return operator<<<N + 1>(out << get<N>(t) << ' ', t); }

#ifdef LOCAL
template<class T> void trace_(const char* s, const T& v) { cerr << s << "=" << v; }
template<class T, class... Ts> void trace_(const char* s, const T& v, const Ts&... vs) { for (; *s != ','; ++s) { cerr << *s; } cerr << "=" << v << ","; trace_(++s, vs...); }
#define TRACE(...) (cerr << "\033[2m\033[33m", trace_(#__VA_ARGS__, __VA_ARGS__), cerr << "\033[0m\n")
#else
#define TRACE(...)
#endif

template<u_int32_t Mod = 1000000007> class Modint {
    int64_t val;
public:
    static constexpr u_int32_t mod = Mod;
    Modint(int64_t v = 0) noexcept : val(v % mod) { if (val < 0) val += mod; }
    int64_t value() const noexcept { return val; }
    friend istream& operator>>(istream &is, Modint<mod>& x) { int64_t v; is >> v; x = v; return is; }
    friend ostream& operator<<(ostream &os, const Modint<mod>& x) { return os << x.val; }
    bool operator==(const Modint<mod>& r) const noexcept { return val == r.val; }
    bool operator!=(const Modint<mod>& r) const noexcept { return val != r.val; }
    Modint<mod> operator-() const noexcept { return val ? mod - val : 0; }
    Modint<mod> operator+(const Modint<mod>& r) const noexcept { return Modint(*this) += r; }
    Modint<mod> operator-(const Modint<mod>& r) const noexcept { return Modint(*this) -= r; }
    Modint<mod> operator*(const Modint<mod>& r) const noexcept { return Modint(*this) *= r; }
    Modint<mod> operator/(const Modint<mod>& r) const noexcept { return Modint(*this) /= r; }
    Modint<mod>& operator+=(const Modint<mod>& r) noexcept { val += r.val; if (val >= mod) val -= mod; return *this; }
    Modint<mod>& operator-=(const Modint<mod>& r) noexcept { val -= r.val; if (val < 0) val += mod; return *this; }
    Modint<mod>& operator*=(const Modint<mod>& r) noexcept { val = val * r.val % mod; return *this; }
    Modint<mod>& operator/=(const Modint<mod>& r) noexcept {
        int64_t a = r.val, b = mod, u = 1, v = 0, t = 0;
        while (b) { t = a / b; a -= t * b; swap(a, b); u -= t * v; swap(u, v); }
        val = val * u % mod;
        if (val < 0) val += mod;
        return *this;
    }
    Modint<mod> pow(u_int32_t n) const noexcept {
        Modint<mod> r = 1, t = *this;
        for (;n > 0;  n >>= 1) { if (n & 1) { r *= t; } t *= t; }
        return r;
    }
};

int main() {
    int n;
    cin >> n;
    vector<pair<int64_t, int64_t>> AB(n);
    cin >> AB;
    map<pair<int64_t, int64_t>, int> abc;
    for (auto [a, b] : AB) {
        if (a == 0 && b == 0) {
            abc[pair(0, 0)]++;
        } else if (b == 0) {
            abc[pair(1, 0)]++;
        } else if (a == 0) {
            abc[pair(0, 1)]++;
        } else {
            auto g = gcd(abs(a), abs(b));
            if (b < 0) {
                abc[pair(-a / g, -b / g)]++;
            } else {
                abc[pair(a / g, b / g)]++;
            }
        }
    }
    TRACE(abc);
    Modint ans = 1;
    for (auto [p, c] : abc) {
        auto [a, b] = p;
        if (a == 0 && b == 0) {
            continue;
        }
        auto it = (a == 0) ? abc.find(pair(1, 0))
                : (a < 0) ? abc.find(pair(b, -a))
                : abc.find(pair(-b, a));
        if (it != abc.end()) {
            if (a * b >= 0 && b != 0) {
                ans *= Modint(2).pow(c) + Modint(2).pow(it->second) - 1;
            }
        } else {
            ans *= Modint(2).pow(c);
        }
        TRACE(a, b, ans);
    }
    cout << ans - 1 + abc[pair(0, 0)] << '\n';
}


Measured memory_bytes: 18608