#include<iostream>
#include<algorithm>
#include<vector>
#include<functional>
#include<queue>
#include<tuple>
#include<string>
#include<iomanip>
#include<cmath>
#include<map>

using namespace std;

typedef long long ll;
typedef tuple<ll, ll, ll> T3;

//このnamespace内のMODという値を、問題の要求に応じて変更すること
namespace Mint {

	//このMODという値を、問題の要求に応じて変更すること
	const ll MOD = 1000000007;

		template<ll Mod> struct Modint {
		ll val = 0;

		//コンストラクタ long long, 空, Modintを受け取れる
		Modint() = default;
		Modint(const Modint&) = default;
		Modint(ll _x) {
			val = _x >= 0 ? _x % Mod : ((_x % Mod) + Mod) % Mod;
		}

		//繰り返し二乗法、逆元　基本的に外部からいじるのやめたほうがよさそう。
		ll modpow(ll a, ll b) const {
			ll ret = 1, kakeru = a;
			while (b > 0) {
				if (b & 1)ret *= kakeru, ret %= Mod;
				kakeru *= kakeru, kakeru %= Mod;
				b >>= 1;
			}
			return ret;
		}
		Modint inv() const {
			return modpow((*this).val, MOD - 2);
		}

		//代入演算子　Modintとlong longの2通りある
		Modint operator= (const Modint& p) {
			val = p.val;
			return (*this);
		}

		//二項演算＋代入演算子　二項演算子、同値演算子はクラス外で定義する
		Modint& operator+= (const Modint& p) {
			val += p.val;
			if (val >= Mod)val -= Mod;
			return (*this);
		}
		Modint& operator-= (const Modint& p) {
			val -= p.val;
			if (val < 0)val += Mod;
			return (*this);
		}
		Modint& operator*= (const Modint& p) {
			val *= p.val;
			val %= Mod;
			return (*this);
		}
		Modint& operator/= (const Modint& p) {
			//なんか,p.inv()を使うとthisのポインターが変換できませんって出る
			//Modint tmp(p.inv());
			Modint tmp(modpow(p.val, MOD - 2));
			(*this) *= tmp;
			return (*this);
		}
	};

	//加算
	const Modint<MOD> operator+ (const Modint<MOD>& l, const Modint<MOD>& r) {
		Modint<MOD> tmp = l;
		tmp += r;
		return tmp;
	}
	const Modint<MOD> operator+ (const Modint<MOD>& l, const ll r) {
		Modint<MOD> tmp = l;
		tmp += Modint<MOD>(r);
		return tmp;
	}
	const Modint<MOD> operator+ (const ll l, const Modint<MOD>& r) {
		Modint<MOD> tmp = l;
		tmp += r;
		return tmp;
	}
	//減算
	const Modint<MOD> operator- (const Modint<MOD>& l, const Modint<MOD>& r) {
		Modint<MOD> tmp = l;
		tmp -= r;
		return tmp;
	}
	const Modint<MOD> operator- (const Modint<MOD>& l, const ll r) {
		Modint<MOD> tmp = l;
		tmp -= Modint<MOD>(r);
		return tmp;
	}
	const Modint<MOD> operator- (const ll l, const Modint<MOD>& r) {
		Modint<MOD> tmp = l;
		tmp -= r;
		return tmp;
	}
	//乗算
	const Modint<MOD> operator* (const Modint<MOD>& l, const Modint<MOD>& r) {
		Modint<MOD> tmp = l;
		tmp *= r;
		return tmp;
	}
	const Modint<MOD> operator* (const Modint<MOD>& l, const ll r) {
		Modint<MOD> tmp = l;
		tmp *= Modint<MOD>(r);
		return tmp;
	}
	const Modint<MOD> operator* (const ll l, const Modint<MOD>& r) {
		Modint<MOD> tmp = l;
		tmp *= r;
		return tmp;
	}
	//除算
	const Modint<MOD> operator/ (const Modint<MOD>& l, const Modint<MOD>& r) {
		Modint<MOD> tmp = l;
		tmp /= r;
		return tmp;
	}
	const Modint<MOD> operator/ (const Modint<MOD>& l, const ll r) {
		Modint<MOD> tmp = l;
		tmp /= Modint<MOD>(r);
		return tmp;
	}
	const Modint<MOD> operator/ (const ll l, const Modint<MOD>& r) {
		Modint<MOD> tmp = l;
		tmp /= r;
		return tmp;
	}
	//同値演算子
	const bool operator== (const Modint<MOD>& l, const Modint<MOD>& r) {
		return l.val == r.val;
	}
	const bool operator== (const Modint<MOD>& l, const ll r) {
		return l.val == r;
	}
	const bool operator== (const ll l, const Modint<MOD>& r) {
		return l == r.val;
	}
	const bool operator!= (const Modint<MOD>& l, const Modint<MOD>& r) {
		return !(l.val == r.val);
	}
	const bool operator!= (const Modint<MOD>& l, const ll r) {
		return !(l.val == r);
	}
	const bool operator!= (const ll l, const Modint<MOD>& r) {
		return !(l == r.val);
	}
	//istream ostream での入出力サポート
	std::ostream& operator<<(std::ostream& stream, const Modint<MOD>& p) {
		stream << p.val;
		return stream;
	}
	std::istream& operator>>(std::istream& stream, Modint<MOD>& p) {
		stream >> p.val;
		return stream;
	}
	//使う用の繰り返し二乗法 bはlong long に注意
	Modint<MOD> modpow(const Modint<MOD> a, ll b) {
		ll ret = 1, kakeru = a.val;
		while (b > 0) {
			if (b & 1)ret *= kakeru, ret %= MOD;
			kakeru *= kakeru, kakeru %= MOD;
			b >>= 1;
		}
		Modint<MOD> tmpret(ret);
		return tmpret;
	}
}

using namespace Mint;
using mint = Mint::Modint<MOD>;

namespace comb {
	ll fact[500001];
	ll fact_inv[500001];
	const ll MOD = 1000000007;

	ll modpow(ll a, ll b) {
		ll base = 1, kakeru = a;
		while (b > 0) {
			if (b & 1)base *= kakeru, base %= MOD;
			kakeru *= kakeru, kakeru %= MOD;
			b >>= 1;
		}
		return base;
	}

	void setup() {
		fact[0] = 1, fact[1] = 1;
		for (int i = 2; i <= 500000; i++) {
			fact[i] = (fact[i - 1] * i) % MOD;
		}

		fact_inv[500000] = modpow(fact[500000], MOD - 2);

		for (int i = 499999; i >= 0; i--) {
			fact_inv[i] = fact_inv[i + 1] * (i + 1);
			fact_inv[i] %= MOD;
		}

	}

	ll combination(int a, int b) {
		if (a - b < 0)return 0;
		ll ret = fact[a];
		ret *= fact_inv[b], ret %= MOD;
		ret *= fact_inv[a - b], ret %= MOD;
		return ret;
	}

	ll permutation(int a, int b) {
		if (a - b < 0)return 0;
		ll ret = fact[a];
		ret *= fact_inv[a - b], ret %= MOD;
		return ret;
	}

	ll homogeneous(int a, int b) {
		return combination(a + b - 1, b);
	}

}


ll gcd(ll a, ll b) {
	if (a % b == 0)return b;
	return gcd(b, a % b);
}

ll A[200000 + 10], B[200000 + 10];

int main() {
	comb::setup();
	int N;
	cin >> N;
	for (int i = 0; i < N; i++)cin >> A[i] >> B[i];

	ll zeroa = 0, azero = 0;
	map<T3, ll> M;
	ll cntwzero = 0;
	for (int i = 0; i < N; i++) {
		if (A[i] == 0 || B[i] == 0) {
			
			if (A[i] == 0 && B[i] == 0)cntwzero++;
			else if (A[i] == 0 && B[i] != 0)zeroa++;
			else azero++;
			continue;
		}
		int sgn = 0;
		if ((A[i] > 0 && B[i] > 0) || (A[i] < 0 && B[i] < 0))sgn = +1;
		else sgn = -1;
		M[make_tuple(sgn, abs(A[i]) / gcd(abs(A[i]), abs(B[i])), abs(B[i]) / gcd(abs(A[i]), abs(B[i])))]++;
		
	}

	mint ans = 1;
	for (auto it = M.begin(); it != M.end(); it++) {
		if ((*it).second == 0)continue;
		T3 val = (*it).first;
		int sgn = get<0>(val);
		ll bunsi = get<1>(val);
		ll bunbo = get<2>(val);
		ans *= (comb::modpow(2, (*it).second) + comb::modpow(2, M[make_tuple(sgn * -1, bunbo, bunsi)]) - 1 + comb::MOD) % comb::MOD,
			M[make_tuple(sgn * -1, bunbo, bunsi)] = 0;
		//cout << (*it).second + M[make_tuple(sgn * -1, bunbo, bunsi)] + 1 << endl;
	}
	
	//片方に0があるものたちについて

	ans *= (comb::modpow(2, azero) + comb::modpow(2, zeroa) - 1 + comb::MOD) % comb::MOD;

	cout << (ans - 1 + cntwzero).val << endl;

	return 0;
}

Measured memory_bytes: 45792