using System;
using System.Collections.Generic;

public class Hello
{
    public static void Main()
    {

        int  n = int.Parse(System.Console.ReadLine());
        var iwashi = new Dictionary<Tuple<long, long>, Tuple<long,long>>();
        long sum = 1;
        long zero = 0;

        for(int i=0; i < n; i++)
        {
            long[] ab = Array.ConvertAll(Console.ReadLine().Split(' '), long.Parse);
            long tmp,gcd = 0;
            int sign = Math.Sign(ab[0])*Math.Sign(ab[1]);
            ab[0] = Math.Abs(ab[0]);
            ab[1] = Math.Abs(ab[1]);


            switch (sign)
            {
                case 0:


                    if (ab[0] == 0 && ab[1] != 0) { ab[0] = (long)1; ab[1] = (long)0; sign = 1; }
                    else if (ab[0] != 0 && ab[1] == 0) {ab[0] = (long)1; ab[1] = (long)0; sign = -1; }
                    else if (ab[0] == 0 && ab[1] == 0) {  sign = 0; zero += 1; }
                    if (!iwashi.ContainsKey(Tuple.Create(ab[0], ab[1])))
                    {
                        iwashi.Add(Tuple.Create(ab[0], ab[1]), Tuple.Create((long)0, (long)0));
                    }
                    break;

                case -1:
                    tmp = ab[0];
                    ab[0] = ab[1];
                    ab[1] = tmp;
                    gcd = Gcd(ab[0], ab[1]);
                    ab[0] /= gcd;
                    ab[1] /= gcd;
                    if (!iwashi.ContainsKey(Tuple.Create(ab[0], ab[1])))
                    {
                        iwashi.Add(Tuple.Create(ab[0], ab[1]), Tuple.Create((long)0, (long)0));
                    }
                    break;
                case 1:
                    gcd = Gcd(ab[0], ab[1]);
                    ab[0] /= gcd;
                    ab[1] /= gcd;
                    if (!iwashi.ContainsKey(Tuple.Create(ab[0], ab[1])))
                    {
                        iwashi.Add(Tuple.Create(ab[0], ab[1]), Tuple.Create((long)0, (long)0));
                    }
                    break;
            }



            (long a, long b) = iwashi[Tuple.Create(ab[0], ab[1])];
            switch (sign)
            {
                case 1:
                    a++;
                    iwashi[Tuple.Create(ab[0], ab[1])] = Tuple.Create(a, b);
                    break;
                case -1:
                    b++;
                    iwashi[Tuple.Create(ab[0], ab[1])] = Tuple.Create(a, b);
                    break;
            }
        }
        
        foreach(KeyValuePair<Tuple<long,long>,Tuple<long,long>> kvp in iwashi)
        {
            long sum1 = 0;
            checked
            {
                sum1 = (Pow(2, kvp.Value.Item1) - 1) % 1000000007;
                sum1 += (Pow(2, kvp.Value.Item2) - 1) % 1000000007;
          
                sum1 += 1 % 1000000007;
                sum = sum % 1000000007;
                sum = sum * (sum1 % 1000000007);
            }
        }
        checked
        {
            System.Console.WriteLine(((sum - 1 )% 1000000007 +zero)% 1000000007);
        }
    }

    public static long Gcd(long a,long b)
    {
        var v = new[] { a, b };
        while(v[1] !=0)
        {
            v = new[] { v[1], v[0] % v[1] };
        }
        return v[0];
    }

    public static long Pow(long a, long pow)
    {
        a = a % 1000000007;
        checked
        {
            if (pow == 1)
            {
                return a % 1000000007;
            }
            else if (pow == 0)
            {
                return 1;
            }
            else if (pow % 2 == 1)
            {
                return (a * Pow(a, pow - 1));
            }
            else if (pow % 2 == 0)
            {
                return Pow((a % 1000000007) * (a % 1000000007), pow / 2);
            }
            else
            {
                return 1;
            }
        }
    }

    public struct ab
    {
        public long a;
        public long b;
        public long qu;
    }
}