#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <cmath>
#include <climits>
#include <map>
#include <set>

constexpr int SINT_MAX = std::numeric_limits<int>::max();
constexpr int SINT_MIN = std::numeric_limits<int>::min();

using namespace std;
using vi = vector<int>;
using vvi = vector<vi>;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;

template<class T>
T choose(bool b, T t, T f)
{
    if (b) return t;
    else return f;    
}

const char *YesNo(bool b)
{
    return choose(b, "Yes", "No");
}

const char *YESNO(bool b)
{
    return choose(b, "YES", "NO");
}

template<template<class...> class ContT, class ValueT, size_t Dim>
struct vec_type
{
    using type = ContT<typename vec_type<ContT, ValueT, Dim-1>::type>;
};

template<template<class...> class ContT, class ValueT>
struct vec_type<ContT, ValueT, 0>
{
    using type = ValueT;
};

template<class ValueT, size_t Dim = 1>
using vec_t = typename vec_type<std::vector, ValueT, Dim>::type;


template<class ValueT, size_t Dim, class = typename std::enable_if<Dim == 0>::type>
auto make_vec(ValueT value = ValueT()) -> ValueT
{
    return value;
}

template<class ValueT, size_t Dim, class... Rest>
auto make_vec(size_t size0, Rest... rest)
{
    auto vec = make_vec<ValueT, Dim-1>(rest...);
    return std::vector(size0, vec);
}

int diffabs(int l, int r)
{
    if (l < r) return r-l;
    else return l-r;    
}

 
constexpr uint_fast64_t MOD = 1e9 + 7;
 
template<class StoreT, class AddT, class MulT, StoreT MOD>
class ModInt
{
    using self_type = ModInt<StoreT, AddT, MulT, MOD>;
    StoreT i;
 
public:
    ModInt()
        : i(0)
    {}
    ModInt(StoreT i)
    {
        while(i < 0) i += MOD;
        this->i = i;
    }
 
    ModInt(const self_type& i) = default;
    constexpr self_type &operator=(const self_type& i) = default;
 
    constexpr uint_fast32_t getI() const noexcept
    {
        return i;
    }
 
    ModInt& operator +=(self_type rhs)
    {
        AddT i64 = static_cast<AddT>(i);
        StoreT a32 = static_cast<StoreT>((i64 + rhs.i) % MOD);
        i = a32;
        return *this;
    }
 
    constexpr ModInt operator +(self_type rhs) const noexcept
    {
        self_type newInt(*this);
        newInt += rhs;
        return newInt;
    }
 
    ModInt& operator -=(self_type rhs)
    {
        AddT i64 = static_cast<AddT>(i);
        StoreT a32 = static_cast<StoreT>((i64 + MOD - rhs.i) % MOD);
        i = a32;
        return *this;
    }
 
    constexpr ModInt operator -(self_type rhs) const noexcept
    {
        self_type newInt(*this);
        newInt -= rhs;
        return newInt;
    }
 
    ModInt& operator *=(self_type rhs)
    {
        MulT i64 = static_cast<MulT>(i);
        StoreT a32 = static_cast<StoreT>((i64 * rhs.i) % MOD);
        i = a32;
        return *this;
    }
 
    constexpr ModInt operator *(self_type rhs) const noexcept
    {
        self_type newInt(*this);
        newInt *= rhs;
        return newInt;
    }
 
    constexpr ModInt operator /(self_type rhs) const noexcept
    {
        self_type newInt(*this);
        self_type rhsInv = rhs.inv();
        newInt *= rhsInv;
        return newInt;
    }
 
    constexpr bool operator ==(self_type rhs) const noexcept
    {
        return i == rhs.i;
    }
 
    constexpr bool operator <(self_type rhs) const noexcept
    {
        return i < rhs.i;
    }
 
    constexpr bool operator >(self_type rhs) const noexcept
    {
        return rhs < *this;
    }
 
    constexpr ModInt pow(int n) const noexcept
    {
        ModInt a = *this;
        ModInt res = 1;
 
        while (n > 0)
        {
            if (n & 1)
            {
                res *= a;
            }
            a *= a;
            n >>= 1;
        }
        return res;
    }
 
    constexpr self_type inv() const noexcept
    {
        return pow(MOD - 2);
    }
};
 
template<class StoreT, class AddT, class MulT, StoreT MOD>
std::ostream& operator <<(std::ostream& ost, ModInt<StoreT, AddT, MulT, MOD> i)
{
    ost << i.getI();
    return ost;
}
 
using UModInt = ModInt<uint_fast32_t, uint_fast32_t, uint_fast64_t, MOD>;
using SModInt = ModInt<int_fast32_t, int_fast32_t, int_fast64_t, MOD>;
 

template<class ModIntT>
class BinomialFactory
{
    std::vector<ModIntT> stock;
    std::vector<ModIntT> inv;
 
public:
    explicit BinomialFactory(int N)
    {
        stock.resize(N + 1);
        inv.resize(N + 1);
        stock[0] = 1;
        inv[0] = 1;
        for (int i = 1; i <= N; i++)
        {
            stock[i] = stock[i - 1] * i;
            inv[i] = stock[i].inv();
        }
    }
 
    ModIntT bi(int n, int r) const
    {
        if (r == 0 || r == n) return 1;
 
        return stock[n] * inv[n - r] * inv[r];
    }
};


///////////////////////////////////////////////////

int main()
{
    int N;
    cin >> N;

    int nop_count = 0;
    map<pair<ll,ll>,int> g;
    for (int i = 0; i < N; i++)
    {
        ll a, b;
        cin >> a >> b;

        if (a == 0 && b == 0)
        {
            ++nop_count;
            continue;
        }

        ll l;
        if (a == 0)
            l = abs(b);
        else if (b == 0)
            l = abs(a);
        else
            l = gcd(a, b);

        a /= l;
        b /= l;
        
        if (a < 0 || (a == 0 && b < 0))
        {
            a = -a;
            b = -b;
        }
        
        g[{a, b}]++;
    }

    UModInt ans = 1;
    const UModInt t = 2;
    for (auto p : g)
    {
        if (auto it = g.find({p.first.second, -p.first.first}); it != g.end() && p.first.second > 0)
        {
            ans *= (t.pow(p.second) + t.pow(it->second) - 1);
        }
        else if (auto it = g.find({-p.first.second, p.first.first}); it != g.end())
        {
            // skip
        }
        else
        {
            ans *= t.pow(p.second);
        }
    }
    ans += nop_count;
    ans -= 1;

    cout << ans << endl;
}

Measured memory_bytes: 15992