using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

class TEST{
	static void Main(){
		Sol mySol =new Sol();
		mySol.Solve();
	}
}

class Sol{
	/*
	struct Pair{
		public long A, B, S;
		
		public Pair(long a, long b, long s){
			A = a; B = b; S = s;
		}
		public override String ToString(){
			return String.Format("[{0},{1},{2}]",A,B,S);
		}
	}
	*/
	
	class Pair: Tuple<long,long,long>{
		public long A,B,S;
		public Pair(long a, long b, long s) : base(a, b, s){
			A = a; B = b; S = s;
		}
	}
	
	long gcd (long a, long b){ return a == 0 ? b : gcd(b % a , a); }
	public void Solve(){
		
		
		var di = new Dictionary<Pair, int>();
		int[] zeros = new int[3];
		for(int i=0;i<N;i++){
			if(A[i] == 0 || B[i] == 0){
				if(A[i] == 0 && B[i] == 0) zeros[0]++;
				if(A[i] == 0 && B[i] != 0) zeros[1]++;
				if(A[i] != 0 && B[i] == 0) zeros[2]++;
				continue;
			}
			int sig = (A[i] > 0 && B[i] < 0) ? -1 :(A[i] < 0 && B[i] > 0) ? -1 :1;
			A[i] = Math.Abs(A[i]);
			B[i] = Math.Abs(B[i]);
			var g = gcd(A[i], B[i]);
			A[i] /= g;
			B[i] /= g;
			var r = new Pair(A[i], B[i], sig);
			if(di.ContainsKey(r) == false) di.Add(r, 0);
			di[r]+=1;
		}
		//foreach(var k in di.Keys) Console.WriteLine("{0} {1}",k, di[k]);
		
		mlong tot = 1;
		mlong[] P2 = new mlong[N + 2];
		P2[0] = 1;
		for(int i=1;i<N+2;i++) P2[i] = 2 * P2[i - 1];
		
		var hs = new HashSet<Pair>();
		foreach(var r in di.Keys){
			Pair nr = new Pair(r.B, r.A, r.S * -1);
			if(hs.Contains(r)) continue;
			if(!di.ContainsKey(nr)){
				tot *= P2[di[r]];
				hs.Add(r);
			} else {
				var c1 = P2[di[r]];
				var c2 = P2[di[nr]];
				tot *= (c1 + c2 - 1);
				hs.Add(r);
				hs.Add(nr);
			}
		}
		
		if(zeros[1] > 0 && zeros[2] > 0){
			var c1 = P2[zeros[1]];
			var c2 = P2[zeros[2]];
			tot *= (c1 + c2 - 1);
		} else if(zeros[1] > 0){
			tot *= P2[zeros[1]];
		} else if(zeros[2] > 0){
			tot *= P2[zeros[2]];
		}
		
		tot -= 1;
		if(zeros[0] > 0) tot += zeros[0];
		
		Console.WriteLine(tot);
		
		
		
		
	}
	int N;
	long[] A,B;
	public Sol(){
		N = ri();
		A = new long[N];
		B = new long[N];
		for(int i=0;i<N;i++){
			var d = rla();
			A[i] = d[0];
			B[i] = d[1];
		}
	}

	static String rs(){return Console.ReadLine();}
	static int ri(){return int.Parse(Console.ReadLine());}
	static long rl(){return long.Parse(Console.ReadLine());}
	static double rd(){return double.Parse(Console.ReadLine());}
	static String[] rsa(char sep=' '){return Console.ReadLine().Split(sep);}
	static int[] ria(char sep=' '){return Array.ConvertAll(Console.ReadLine().Split(sep),e=>int.Parse(e));}
	static long[] rla(char sep=' '){return Array.ConvertAll(Console.ReadLine().Split(sep),e=>long.Parse(e));}
	static double[] rda(char sep=' '){return Array.ConvertAll(Console.ReadLine().Split(sep),e=>double.Parse(e));}
}


struct mlong {
	
	const long mod = (long) 1e9 + 7;
	long V;
	
	public mlong(long _v = 0){
		V = _v;
	}
	
	public static mlong operator+(mlong a, mlong b){
		var v0 = a.V + b.V; if(v0 >= mod) v0 -= mod;
		return new mlong(v0);
	}
	public static mlong operator-(mlong a, mlong b){
		var v0 = mod + a.V - b.V; if(v0 >= mod) v0 -= mod;
		return new mlong(v0);
	}
	public static mlong operator-(mlong b){
		var v0 = mod - b.V; if(v0 >= mod) v0 -= mod;
		return new mlong(v0);
	}
	public static mlong operator*(mlong a, mlong b){
		var v0 = a.V * b.V; if(v0 >= mod) v0 %= mod;
		return new mlong(v0);
	}
	public static mlong operator/(mlong a, mlong b){
		var v0 = a.V * inv(b.V).V; if(v0 >= mod) v0 %= mod;
		return new mlong(v0);
	}
	
	
	public static mlong inv(long x){
		long a = 0, b = 0, c = 0;
		ExtGCD(x, mod, ref a, ref b, ref c);
		return (mlong)((a + mod) % mod);
	}
	
	public static void ExtGCD(long x, long y, ref long a, ref long b, ref long c){
		long r0 = x; long r1 = y;
		long a0 = 1; long a1 = 0;
		long b0 = 0; long b1 = 1;
		long q1, r2, a2, b2;
		while(r1 > 0){
			q1 = r0 / r1;
			r2 = r0 % r1;
			a2 = a0 - q1 * a1;
			b2 = b0 - q1 * b1;
			r0 = r1; r1 = r2;
			a0 = a1; a1 = a2;
			b0 = b1; b1 = b2;
		}
		c = r0;
		a = a0;
		b = b0;
	}
	
	public static mlong ModPow(mlong a, long k){
		if(k == 0) return (mlong) 1;
		if(a == 0) return (mlong) 0;
		mlong x = a;
		mlong ret = 1;
		while(k > 0){
			if(k % 2 == 1) ret *= x;
			x *= x;
			k >>= 1;
		}
		return ret;
	}
	
	
	public static bool operator == (mlong a, mlong b){
		 return a.Equals(b);
	}
	public static bool operator != (mlong a, mlong b){
		 return !(a == b);
	}
	
	public override bool Equals(System.Object obj){
		if(obj  ==  null) return false;
		mlong p  =  (mlong) obj;
		if((System.Object) p  ==  null) return false;
		return p.V  ==  V;
	}
	public override int GetHashCode(){
		return V.GetHashCode();
	}
	
	public static implicit operator mlong(long n){
		long v = n % mod; if(v < 0) v += mod;
		return new mlong(v);
	}
	public static implicit operator mlong(int n){
		long v = n % mod; if(v < 0) v += mod;
		return new mlong(v);
	}
	public static explicit operator long(mlong n){
		return n.V;
	}
	
	public override String ToString(){
		return V.ToString();
	}
	
	
}

struct Q:IComparable<Q> {
	long num;
	long den;
	public static long gcd(long a, long b){
		return a == 0 ? b : gcd(b % a, a);
	}
	public static Q Red(Q x){
		long n = x.Num;
		long d = x.Den;
		long g = gcd(Math.Abs(n), Math.Abs(d));
		n /= g;
		d /= g;
		if(d < 0){n *= -1;d *= -1;}
		return new Q(n, d);
	}
	
	public int CompareTo(Q t){
		var d  =  num * t.den - den * t.num;
		return d > 0 ? 1 : d < 0 ? -1 : 0;
	}
	
	public long Num{
		get{return num;}
		set{this.num = value;}
	}
	public long Den{
		get{return den;}
		set{this.den = value;}
	}
	
	public Q(long n_, long d_){
		if(d_ < 0){ n_ *= -1;d_ *= -1;}
		long g = gcd(Math.Abs(n_), Math.Abs(d_));
		n_ /= g;
		d_ /= g;
		num = n_; den = d_;
	}
	
	public static implicit operator Q(long n){
		return new Q(n, 1);
	}
	
	public static explicit operator long (Q q){
		return q.num / q.den;
	}	
	
	
	public static Q operator+(Q a, Q b){
		 return (new Q(a.Num * b.Den + a.Den * b.Num, a.Den * b.Den));
	}
	public static Q operator-(Q a, Q b){
		 return (new Q(a.Num * b.Den - a.Den * b.Num, a.Den * b.Den));
	}
	public static Q operator-(Q a){
		 return (new Q(-a.Num, a.Den));
	}
	public static Q operator*(Q a, Q b){
		 return (new Q(a.Num * b.Num, a.Den * b.Den));
	}
	public static Q operator/(Q a, Q b){
		 return (new Q(a.Num * b.Den, a.Den * b.Num));
	}
	public static bool operator>(Q a, Q b){
		 return a.CompareTo(b) > 0;
	}
	public static bool operator<(Q a, Q b){
		 return a.CompareTo(b) < 0;
	}
	public static bool operator>= (Q a, Q b){
		 return a.CompareTo(b) >=  0;
	}
	public static bool operator<= (Q a, Q b){
		 return a.CompareTo(b) <=  0;
	}
	
	public static bool operator == (Q a, Q b){
		 return a.Equals(b);
	}
	public static bool operator != (Q a, Q b){
		 return !(a == b);
	}
	
	public override bool Equals(System.Object obj){
		if(obj  ==  null) return false;
		Q p  =  (Q) obj;
		if((System.Object) p  ==  null) return false;
		return den * p.num  ==  num * p.den;
	}
	public override int GetHashCode(){
		return (den * num *(long) 1e9 + 7).GetHashCode();
	}
	
	
	public static Q Min(Q a, Q b){
		 return a < b ? a : b;
	}
	public static Q Max(Q a, Q b){
		 return a > b ? a : b;
	}
	public override String ToString(){
		return this.Num.ToString()+"/"+this.Den.ToString();
	}
}

Measured memory_bytes: 58264