#if 1
#include <bits/stdc++.h>
using namespace std;

//------------------------------------------------------------
using ll = long long;
#define int ll

#define FOR(i, s, e) for (ll i = ll(s); i < (ll)e; ++i)
#define RFOR(i, s, e) for (ll i = ll(e) - 1; i >= ll(s); --i)
#define REP(i, n) for (ll i = 0, i##_size = n; i < i##_size; ++i)
#define RREP(i, n) for (ll i = ll(n) - 1; i >= 0; --i)

//------------------------------------------------------------
template <class T>
struct arr : public vector<T> {
	arr() {}
	arr(ll n, T v = T()) : vector<T>(n, v) {}
	void init(ll n, T v = T()) {
		this->clear();
		this->resize(n, v);
	}
	ll sz() const { return (ll)this->size(); }
	void pb(T v) { this->push_back(v); }
	void sort() { std::sort(this->begin(), this->end()); }
	void rsort() { std::sort(this->begin(), this->end(), greater<T>()); }
};
using ints = arr<ll>;
using intss = arr<arr<ll>>;

template <class T>
struct que : public queue<T> {
	ll sz() const { return (ll)this->size(); }
	T popfront() {
		T v = this->front();
		this->pop();
		return v;
	}
};

//template <class A, class B>
//struct pr : public pair<A, B> {
//	A& a;
//	B& b;
//
//	pr() : a(first), b(second) {}
//	pr(A a_, B b_) : pair(a_, b_), a(first), b(second) {}
//	pr(pr const& r) : pair(r), a(first), b(second) {}
//	pr& operator = (pr const& r) {
//		a = r.a;
//		b = r.b;
//		return *this;
//	}
//
//	friend istream& operator>>(istream& is, pr& p) {
//		is >> p.a >> p.b;
//		return is;
//	}
//};
using pint = pair<ll, ll>;

//------------------------------------------------------------
#if defined(TEST)
extern istream& myInputStream;
extern ostream& myOutputStream;
#else
istream& myInputStream = cin;
ostream& myOutputStream = cout;
#endif

struct input {
	template <class A, class B>
	void exec(pair<A, B>& var) {
		myInputStream >> var.first >> var.second;
	}

	template <class T>
	void exec(T& var) {
		myInputStream >> var;
	}

	template <class T>
	operator T() {
		T var;
		exec(var);
		return var;
	}
} input;

struct inputs {
	ll n;
	inputs(ll n_) : n(n_) {}

	template <class T>
	operator arr<T>() {
		arr<T> var(n);
		REP(i, n) {
			var[i] = (T)input;
		};
		return var;
	}
};

template <class T>
void output(T var) {
	myOutputStream << (var) << '\n';
}

//------------------------------------------------------------
template <class T> void chmin(T& a, T b) { if (b < a) { a = b; } }
template <class T> void chmax(T& a, T b) { if (b > a) { a = b; } }

int gcd(int a, int b) {
	if (a < b) {
		return gcd(b, a);
	}

	int r;
	for (;;) {
		if (b == 0) {
			break;
		}
		r = a % b;
		a = b;
		b = r;
	}
	return a;
}

//------------------------------------------------------------
struct bfs {
	ints froms;
	ints steps;

	bfs(int N, intss const& adjacency) {
		froms.init(N, -1);
		steps.init(N, -1);

		que<ll> queue;
		queue.push(0);
		froms[0] = 0;
		steps[0] = 0;

		while (queue.empty() == false) {
			ll p = queue.popfront();

			for (ll n : adjacency[p]) {
				if (froms[n] != -1) {
					continue;
				}

				froms[n] = p;
				steps[n] = steps[p] + 1;
				queue.push(n);
			}
		}
	}
};

//------------------------------------------------------------
template <int MOD>
struct modint {
	int raw;

	modint() { raw = 0; }
	modint(int v) {
		raw = v;
		if (raw >= MOD) { raw %= MOD; }
	}
	modint operator + (modint v) const { return modint(raw) += v; }
	modint operator - (modint v) const { return modint(raw) -= v; }
	modint operator * (modint v) const { return modint(raw) *= v; }

	modint& operator += (modint v) {
		raw += v.raw;
		if (raw >= MOD) { raw -= MOD; }
		return *this;
	}
	modint& operator -= (modint v) {
		raw -= v.raw;
		if (raw < 0) { raw += MOD; }
		return *this;
	}
	modint& operator *= (modint v) {
		raw = (raw * v.raw) % MOD;
		return *this;
	}

	friend ostream& operator<<(ostream& os, modint const& m) {
		return os << m.raw;
	}
};

//------------------------------------------------------------
#if defined(TEST)
#include "test.hpp"
#else
void myMain();
signed main() {
	cin.tie(0);
	ios::sync_with_stdio(0);
	cout << fixed << setprecision(16);
	myMain();
	return 0;
}
#endif
#endif

#define a first
#define b second

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

#define MOD 1000000007
using mint = modint<MOD>;

void myMain() {
	int N;
	arr<pint> iwashis;
	map<pint, int> rateCounts;

	N = input;
	iwashis = inputs(N);

	int zeroCount = 0;
	REP(i, N) {
		auto const& W = iwashis[i];

		if (W.a == 0 && W.b == 0) {
			++zeroCount;
		}
		else if (W.a == 0) {
			pint rate;
			rate.a = 0;
			rate.b = 1;
			rateCounts[rate] += 1;
		}
		else if (W.b == 0) {
			pint rate;
			rate.a = 1;
			rate.b = 0;
			rateCounts[rate] += 1;
		}
		else {
			int d = gcd(abs(W.a), abs(W.b));
			pint rate;
			rate.a = W.a / d;
			rate.b = W.b / d;
			if (rate.b < 0) {
				rate.a = -rate.a;
				rate.b = -rate.b;
			}
			rateCounts[rate] += 1;
		}
	}

	arr<mint> powTbl(N+1);
	powTbl[0] = 1;
	REP(i, N) {
		powTbl[i + 1] = (powTbl[i] * 2);
	}

	mint ans = 1;
	while (rateCounts.size()) {
		auto const& W = rateCounts.begin();

		pint rate = W->first;
		pint badRate(-rate.b, rate.a);
		if (badRate.a == 0) {
			badRate.b = 1;
		}
		else if (badRate.b == 0) {
			badRate.a = 1;
		}
		else if (badRate.b < 0) {
			badRate.a = -badRate.a;
			badRate.b = -badRate.b;
		}

		auto it = rateCounts.find(badRate);
		if (it == rateCounts.end()) {
			ans *= powTbl[W->second];
			rateCounts.erase(W);
			continue;
		}

		ans *= powTbl[W->second + it->second] - (powTbl[W->second] - 1) * (powTbl[it->second] - 1);

		rateCounts.erase(W);
		rateCounts.erase(it);
	}

	ans += zeroCount;
	ans -= 1;

	output(ans);
}


Measured memory_bytes: 20224