### BUGGY CODE ###

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction
from collections import defaultdict

MOD = 1000000007

class Sardine:
    def __init__(self, a, b):
        if a == 0 and b == 0:
            self.type_ = 0
        elif a == 0:
            self.type_ = 'a'
        elif b == 0:
            self.type_ = 'b'
        else:
            self.type_ = Fraction(a, b)

def combi(x, y):
    res = pow(2, x, MOD) - 1 + pow(2, y, MOD) - 1 + 1
    #print('res', x, y) # debug
    #print(res) # debug
    return res

def calc_cross_type(frac):
    cross = Fraction(-1 * frac.denominator, frac.numerator)
    #print('cross', frac, cross) # debug
    return cross

def count_up(types):
    ans = 0
    seed = 1
    seed *= combi(types['a'], types['b'])
    keys = list(types.keys())
    for type_ in keys:
        if not (type(type_) == Fraction and type_ > 0):
            continue
        count = types[type_]
        cross_type = calc_cross_type(type_)
        cross_count = types[cross_type]
        seed = (seed * combi(count, cross_count)) % MOD
    ans += seed
    ans += types[0]
    return ans - 1 # remove no sellect

if __name__ == '__main__':
    n = int(input())
    types = defaultdict(lambda: 0)
    for _ in range(n):
        a, b = list(map(int, input().split()))
        sardine = Sardine(a, b)
        types[sardine.type_] += 1
        if type(sardine.type_) is Fraction:
            cross_type = calc_cross_type(sardine.type_)
            types[cross_type]
    #print('types') # debug
    #pp(types) # debug
    ans = count_up(types)
    #print('ans') # debug
    print(ans)




    #print('\33[32m' + 'end' + '\033[0m') # debug


### FIXED CODE ###

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
sys.setrecursionlimit(10**7)
from pprint import pprint as pp
from pprint import pformat as pf
# @pysnooper.snoop()
#import pysnooper # debug

import math
#from sortedcontainers import SortedList, SortedDict, SortedSet # no in atcoder
import bisect
from fractions import Fraction
from collections import defaultdict

def is_same_sign(a, b):
    if a > 0 and b > 0:
        return True
    if a < 0 and b < 0:
        return True
    return False

def fraction_taple(a, b):
    g = math.gcd(a, b)
    if is_same_sign(a, b):
        s = 1
    else:
        s = -1
    a = abs(a) // g
    b = abs(b) // g
    return (s, a, b)

def mode(a, b):
    # retrun dict_key, arr_key
    if a == 0 and b == 0:
        return 0, 0
    if a == 0:
        return 'ab', 0
    if b == 0:
        return 'ab', 1
    x = fraction_taple(a, b)
    y = fraction_taple(-1 * b, a)
    if x > y:
        return x, 0
    else:
        return y, 1

MOD = 1000000007

if __name__ == '__main__':

    n = int(input())

    d = defaultdict(lambda: [0, 0])
    zero = 0
    for _ in range(n):
        a, b = list(map(int, input().split()))
        dkey, akey = mode(a, b)
        if dkey == 0:
            zero += 1
        else:
            d[dkey][akey] += 1
    #print('d') # debug
    #pp(d) # debug

    ans = 1
    for pair in d.values():
        tmp = pow(2, pair[0], MOD) - 1 + pow(2, pair[1], MOD) - 1 + 1
        ans *= tmp
    ans += zero - 1
    ans %= MOD
    #print('ans') # debug
    print(ans)

    #print('\33[32m' + 'end' + '\033[0m') # debug