// Template Headers {{{
#include <bits/stdc++.h>
using namespace std;

using pii = pair<int, int>; using vpii = vector<pii>;
using vi = vector<int>; using vvi = vector<vi>;
using ll = long long;
using pll = pair<ll, ll>; using vpll = vector<pll>;
using vll = vector<long long>; using vvll = vector<vll>;
template <class T> using min_queue = priority_queue<T, vector<T>, greater<T>>;
template <class T> istream &operator>>(istream &, vector<T> &);
template <class T> ostream &operator<<(ostream &, const vector<T> &);
template <class T, class U> istream &operator>>(istream &, pair<T, U> &);
template <class T, class U> ostream &operator<<(ostream &, const pair<T, U> &);
template <class T> struct Inf { static constexpr T inf() { return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : std::numeric_limits<T>::max(); } };
template <> struct Inf<int> { static constexpr int inf() { return 0x3f3f3f3f; } };
template <> struct Inf<long long> { static constexpr long long inf() { return 0x3f3f3f3f3f3f3f3fLL; } };
constexpr int INF = Inf<int>::inf(); constexpr ll BINF = Inf<ll>::inf();
// mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
// }}}
// Preprocessing & "Global" variables {{{
struct Solver {
	Solver() {}
	int solve();
};
// }}}

// Automod Integer Template {{{
class mint {
private:
	int x;
	static constexpr int MOD = 1'000'000'007;

public:
	friend inline std::ostream &operator<<(std::ostream &os, const mint &arg) {
		return os << arg.x;
	}
	friend inline std::istream &operator>>(std::istream &is, mint &arg) {
		is >> arg.x;
		if (arg.x >= MOD) arg.x -= MOD;
		return is;
	}
	mint(const int &x) : x(x) {
		if (this->x >= MOD) this->x -= MOD;
		if (this->x < 0) this->x += MOD;
	}
	mint(const long long &x) : x(x % MOD) {}
	mint() : x(0) {}

	mint &operator+=(const mint &rhs) {
		x += rhs.x;
		if (x >= MOD) x -= MOD;
		return *this;
	}
	mint &operator++() { return *this += 1; }
	mint operator+(const mint &rhs) const { return mint(*this) += rhs; }
	mint operator++(int) {
		mint cpy(*this);
		++*this;
		return cpy;
	}

	mint &operator-=(const mint &rhs) {
		x -= rhs.x;
		if (x < 0) x += MOD;
		return *this;
	}
	mint &operator--() { return *this -= 1; }
	mint operator-(const mint &rhs) const { return mint(*this) -= rhs; }
	mint operator-() const { return mint() - *this; }
	mint operator--(int dummy) {
		mint cpy(*this);
		--*this;
		return cpy;
	}

	mint &operator*=(const mint &rhs) {
		x = 1LL * x * rhs.x % MOD;
		return *this;
	}
	mint operator*(const mint &rhs) const { return mint(*this) *= rhs; }

	mint pow(long long p) const {
		mint rt = 1, b = *this;
		for (;p;p>>=1,b*=b) if (p & 1) rt *= b;
		return rt;
	}

	mint operator^(long long p) const { return pow(p); }
	mint &operator^=(long long p) { return *this = pow(p); }

	mint &operator/=(const mint &rhs) { return *this *= rhs.pow(MOD - 2); }
	mint operator/(const mint &rhs) const { return mint(*this) /= rhs; }

	constexpr bool operator<(const mint &rhs) const { return x < rhs.x; }
	constexpr bool operator>(const mint &rhs) const { return x > rhs.x; }
	constexpr bool operator<=(const mint &rhs) const { return x <= rhs.x; }
	constexpr bool operator>=(const mint &rhs) const { return x >= rhs.x; }
	constexpr bool operator==(const mint &rhs) const { return x == rhs.x; }
	constexpr bool operator!=(const mint &rhs) const { return x != rhs.x; }

	constexpr explicit operator int() const { return x; }

};
constexpr int mint::MOD;
using vm = std::vector<mint>;
using vvm = std::vector<vm>;
using pmm = std::pair<mint, mint>;
// }}}

int Solver::solve() {
	int n; cin >> n;
	vpll e(n); cin >> e;
	int fz = 0, sz = 0, bz = 0;
	vpll f;
	for (auto pr : e) {
		if (pr.first == 0 && pr.second == 0) {
			bz++;
		} else if (pr.first == 0) {
			fz++;
		} else if (pr.second == 0) {
			sz++;
		} else {
			f.push_back(pr);
		}
	}
	auto normalize = [] (pll &f) {
		ll cf = gcd(abs(f.first), abs(f.second));
		f.first /= cf; f.second /= cf;
		if (f.second < 0) f.first *= -1, f.second *= -1;
	};
	for (auto &pr : f) normalize(pr);
	auto getInv = [] (const pll &f) {
		pll g(f);
		swap(g.first, g.second);
		g.first *= -1;
		if (g.second < 0) g.first *= -1, g.second *= -1;
		return g;
	};

	map<pll, pii> gps;
	for (auto pr : f) {
		pll ir = getInv(pr);
		if (gps.count(pr)) {
			gps[pr].first++;
		} else if (gps.count(ir)) {
			gps[ir].second++;
		} else {
			gps[pr].first++;
		}
	}
	vm p2(n + 1);
	p2[0] = 1;
	for (int i = 1; i <= n; i++) p2[i] = p2[i - 1] * 2;
	mint ans = 1;
	for (auto [k, v] : gps) {
		auto [l, r] = v;
		ans *= p2[l] + p2[r] - 1;
	}
	ans *= p2[fz] + p2[sz] - 1;
	ans += bz;
	cout << ans - 1 << endl;
	return 0;
}

// Template Main {{{
int main() {
	ios::sync_with_stdio(0); cin.tie(0);
	Solver solver;
	#ifdef JUDGE_MULTI_CASE
		int t; cin >> t; for (int i = 1; i <= t; i++)
	#endif
	solver.solve();
	// cout << "Case #" << i << ": ", solve();
	return 0;
}

template <class T> istream &operator>>(istream &is, vector<T> &v) {
	for (auto it=v.begin();it!=v.end();++it) is >> *it;
	return is;
}

template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
	for (auto it=v.begin();it!=v.end();) os << *it, os << " \n"[++it==v.end()];
	return os;
}

template <class T, class U> istream &operator>>(istream &is, pair<T, U> &p) {
	return is >> p.first >> p.second;
}

template <class T, class U> ostream &operator<<(ostream &os, const pair<T, U> &p) {
	return os << p.first << ' ' << p.second;
}
// }}}

// vim: fdm=marker


Measured memory_bytes: 22644