using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;

class Program
{
    const string Yes = "Yes";
    const string No = "No";
    const char White = '.';
    const char Black = '#';
    const long Mod = 1000000007;

    static void Main(string[] args) {
#if DEBUG
        MyDebugger.Test(process, "../TextFile1.txt");
#else
        object ret = process(new StreamReader(Console.OpenStandardInput()));
        Console.WriteLine(ret);
#endif
    }

    static object process(TextReader input) {
        var n = int.Parse(input.ReadLine());
        
        var tbl = new long[n][];
        for (int i = 0; i < tbl.Length; i++) {
            tbl[i] = ToIntArray(input.ReadLine(), 2);
        }

        var dicAB = new DefaultDectionary<RationalNumber, long>(0);
        long Azero = 0;
        long Bzero = 0;
        long ABzero = 0;

        foreach (var ab in tbl) {
            var a = ab[0];
            var b = ab[1];
            if (a != 0 && b != 0) {
                //dicAB[new RationalNumber(a, b)]++;
                var z = new RationalNumber(a, b);
                dicAB[z]++;
            }
            else if(a == 0 && b == 0) {
                ABzero++;
            }else if(a == 0) {
                Azero++;
            }else if(b == 0) {
                Bzero++;
            }
        }

        long sum = 1;

        HashSet<RationalNumber> counted = new HashSet<RationalNumber>();

        foreach(var x in dicAB) {
            //Debug.WriteLine(x);
            if(counted.Contains(x.Key)) continue;

            var z = x.Key.Inverse() * -1;
            counted.Add(z);

            var x1 = x.Value;
            var x2 = dicAB[z];

            long ss1 = ModPow(2, x1);
            long ss2 = ModPow(2, x2);
            long add = (ss1 + ss2 - 1) % Mod;
            sum *= add;
            sum %= Mod;
        }

        long zeroadd = (ModPow(2, Azero) + ModPow(2, Bzero) - 1) % Mod;
        sum *= zeroadd;
        sum %= Mod;

        sum += ABzero;
        sum %= Mod;

        sum -= 1; //All zero
        if(sum < 0) sum += Mod;
        return sum;
    }

    static long[] ToIntArray(string strs, int n) {
        var ret = new long[n];
        var spl = strs.Split(' ');
        for (int i = 0; i < n; i++)
            ret[i] = long.Parse(spl[i]);
        return ret;
    }

    static long ModPow(long x1, long x2) {
        long ans = 1;
        while (x2 > 0) {
            if (x2 % 2 == 1) {
                ans = (ans * x1) % Mod;
            }
            x1 = (x1 * x1) % Mod;
            x2 /= 2;
        }
        return ans % Mod;
    }
}

class DefaultDectionary<Tkey, TValue> : Dictionary<Tkey, TValue>
{
    TValue DefaultValue;
    public DefaultDectionary(TValue defaultvalue) {
        this.DefaultValue = defaultvalue;
    }
    public new TValue this[Tkey key] {
        get {
            if (this.ContainsKey(key)) return base[key];
            else return DefaultValue;
        }
        set {
            base[key] = value;
        }
    }
}

class RationalNumber : IEquatable<RationalNumber>, IEquatable<long>
{
    private bool sign = true;
    private long a = 0;
    private long b = 1;

    private static Regex Pattern
        = new Regex("\\s*(-?[0-9]+)\\s*(/\\s*([0-9]+)\\s*)?");

    //--------------------

    /// <summary>
    /// 分子の絶対値を取得します。
    /// </summary>
    public long Numerator {
        get { return a; }
    }

    /// <summary>
    /// 分母の絶対値を取得します。
    /// </summary>
    public long Denominator {
        get { return b; }
    }

    /// <summary>
    /// 小数値を取得します。
    /// </summary>
    public double DoubleValue {
        get {
            var v = (double)a / (double)b;
            return SignValue * v;
        }
    }
    /// <summary>
    /// 値が0であるかを取得します。
    /// </summary>
    public bool IsZero {
        get { return a == 0; }
    }

    /// <summary>
    /// 正の数の場合1、負の数の場合-1を取得します。
    /// </summary>
    public int SignValue {
        get { return this.sign ? 1 : -1; }
    }

    //--------------------

    /// <summary>
    /// 0を生成します。
    /// </summary>
    public RationalNumber() {
    }

    /// <summary>
    /// 分子と分母を指定して数を生成します。
    /// </summary>
    /// <param name="a">分子</param>
    /// <param name="b">分母</param>
    public RationalNumber(long a, long b = 1) {
        if (b == 0) {
            throw new DivideByZeroException("分母が0に指定されました。");
        }
        if (a == 0) {
            sign = true;
            this.a = 0;
            this.b = 1;
        } else {
            sign = IsSign(a, b);
            this.a = Math.Abs(a);
            this.b = Math.Abs(b);
            Reduction();
        }
    }

    //--------------------

    /// <summary>
    /// 分数形式で表記されたの文字列から数を生成します。
    /// </summary>
    /// <param name="s">分数または整数式の文字列</param>
    public static RationalNumber Parse(string s) {
        var mc = Pattern.Match(s);
        if (!mc.Success) {
            throw new FormatException("文字列が分数の形式ではありません。");
        }
        var a = long.Parse(mc.Groups[1].Value);
        var b = mc.Groups[3].Success ? long.Parse(mc.Groups[3].Value) : 1;
        return new RationalNumber(a, b);
    }

    /// <summary>
    /// 符号を検証します。
    /// </summary>
    private bool IsSign(long a, long b) {
        if (a >= 0 && b >= 0) return true;
        if (a < 0 && b < 0) return true;
        return false;
    }

    /// <summary>
    /// 約分します。
    /// </summary>
    private void Reduction() {
        var c = Gcd(a, b);
        a /= c;
        b /= c;
    }

    /// <summary>
    /// 逆数を取得します。
    /// </summary>
    /// <returns>この有理数の逆数を表すオブジェクト</returns>
    public RationalNumber Inverse() {
        return new RationalNumber(b * SignValue, a);
    }

    /// <summary>
    /// 約分された分数の文字列表現を取得します。
    /// </summary>
    public override string ToString() {
        return $"{(sign ? "" : "-")}{a}{(b > 1 ? $"/{b}" : "")}";
    }

    /// <summary>
    /// 数値の一致を評価します。
    /// </summary>
    public bool Equals(RationalNumber other) {
        return sign == other.sign
            && a == other.a && b == other.b;
    }

    /// <summary>
    /// オブジェクトがこのクラスのインスタンスかつ数値が一致するかを評価します。
    /// </summary>
    public override bool Equals(object obj) {
        var x = obj as RationalNumber;
        return x != null && Equals(x);
    }

    /// <summary>
    /// 数値の一致を評価します。
    /// </summary>
    public bool Equals(long v) {
        if (b != 1) return false;
        var aa = SignValue * a;
        return aa == v;
    }

    public override int GetHashCode() {
        //return sign.GetHashCode()
        //    ^ a.GetHashCode() 
        //    ^ b.GetHashCode();
        //return ToString().GetHashCode();
        return sign.GetHashCode() ^ ((0x5555555555555555 & a) ^ (0x2AAAAAAAAAAAAAAA & b)).GetHashCode();
    }

    //--------------------

    //演算
    public static RationalNumber operator +(RationalNumber x1, RationalNumber x2) {
        var c = Lcm(x1.b, x2.b);
        var x1a = x1.a * (c / x1.b) * x1.SignValue;
        var x2a = x2.a * (c / x2.b) * x2.SignValue;
        return new RationalNumber(x1a + x2a, c);
    }
    public static RationalNumber operator -(RationalNumber x1, RationalNumber x2) {
        var c = Lcm(x1.b, x2.b);
        var x1a = x1.a * (c / x1.b) * x1.SignValue;
        var x2a = x2.a * (c / x2.b) * x2.SignValue;
        return new RationalNumber(x1a - x2a, c);
    }
    public static RationalNumber operator *(RationalNumber x1, RationalNumber x2) {
        var x1a = x1.a * x1.SignValue;
        var x2a = x2.a * x2.SignValue;
        return new RationalNumber(x1a * x2a, x1.b * x2.b);
    }
    public static RationalNumber operator /(RationalNumber x1, RationalNumber x2) {
        var x1a = x1.a * x1.SignValue;
        var x2a = x2.a * x2.SignValue;
        return new RationalNumber(x1a * x2.b, x2a * x1.b);
    }
    public static bool operator ==(RationalNumber x1, RationalNumber x2) {
        return x1.Equals(x2);
    }
    public static bool operator !=(RationalNumber x1, RationalNumber x2) {
        return !x1.Equals(x2);
    }
    public static bool operator >(RationalNumber x1, RationalNumber x2) {
        var c = Lcm(x1.b, x2.b);
        var x1a = x1.a * x1.SignValue * c;
        var x2a = x2.a * x2.SignValue * c;
        return x1a > x2a;
    }
    public static bool operator >=(RationalNumber x1, RationalNumber x2) {
        return x1 == x2 || x1 > x2;
    }
    public static bool operator <(RationalNumber x1, RationalNumber x2) {
        return !(x1 >= x2);
    }
    public static bool operator <=(RationalNumber x1, RationalNumber x2) {
        return !(x1 > x2);
    }

    //整数との演算
    public static RationalNumber operator +(RationalNumber x1, long i) {
        var x1a = x1.a * x1.SignValue;
        return new RationalNumber(x1a + i * x1.b, x1.b);
    }
    public static RationalNumber operator -(RationalNumber x1, long i) {
        var x1a = x1.a * x1.SignValue;
        return new RationalNumber(x1a - i * x1.b, x1.b);
    }
    public static RationalNumber operator *(RationalNumber x1, long i) {
        var x1a = x1.a * x1.SignValue;
        return new RationalNumber(x1a * i, x1.b);
    }
    public static RationalNumber operator /(RationalNumber x1, long i) {
        if (i == 0) throw new DivideByZeroException("0で除算を行いました。");
        var x1a = x1.a * x1.SignValue;
        return new RationalNumber(x1a, x1.b * i);
    }
    public static bool operator ==(RationalNumber x1, long i) {
        return x1.Equals(i);
    }
    public static bool operator !=(RationalNumber x1, long i) {
        return !x1.Equals(i);
    }
    public static bool operator >(RationalNumber x1, long i) {
        return x1.a * x1.SignValue > i * x1.b;
    }
    public static bool operator >=(RationalNumber x1, long i) {
        return x1 == i || x1 > i;
    }
    public static bool operator <(RationalNumber x1, long i) {
        return !(x1 >= i);
    }
    public static bool operator <=(RationalNumber x1, long i) {
        return !(x1 > i);
    }

    /// <summary>
    /// 最大公約数
    /// </summary>
    private static long Gcd(long m, long n) {
        var x1 = Math.Max(m, n);
        var x2 = Math.Min(m, n);

        while (true) {
            var mod = x1 % x2;
            if (mod == 0) return x2;
            x1 = x2;
            x2 = mod;
        }
    }

    /// <summary>
    /// 最小公倍数
    /// </summary>
    private static long Lcm(long m, long n) {
        var x1 = Math.Max(m, n);
        var x2 = Math.Min(m, n);

        var gcd = Gcd(x1, x2);
        return x1 / gcd * x2;
    }
}


Measured memory_bytes: 71260