#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <tuple>
#include <cstdio>
#include <cmath>
#define rep(i, n) for(i = 0; i < n; i++)
#define int long long
using namespace std;
typedef tuple<int, int, int> T;

int powmod(int a, int n, int mod) {
	a %= mod;
	if (n == 0) return 1;
	if (n % 2 == 0) return powmod((a * a) % mod, n / 2, mod);
	return (a * powmod(a, n - 1, mod)) % mod;
}

int Mod(int a, int p) {
	return (a % p + p) % p;
}

/*void allSearch(vector<int> a, vector<int> b) {
	int i, j, k;
	int n = a.size();
	int ret = 0;
	
	rep(i, (1 << n)) {
		if (i == 0) continue;
		vector<int> vec;
		rep(j, n) {
			if ((i >> j) % 2 == 1) {
				vec.push_back(j);
			}
		}
		
		bool flag = true;
		rep(j, vec.size()) {
			for (k = j + 1; k < vec.size(); k++) {
				int u = vec[j];
				int v = vec[k];
				if (a[u] * a[v] + b[u] * b[v] == 0) { flag = false; break; }
			}
			if (k < vec.size()) break;
		}
		if (flag) ret++;
	}
	return ret;
}*/

int p1 = 1000000403;
int p2 = 900000287;
int p3 = 998244353;
int n;
vector<int> a;
vector<int> b;
vector<int> A1, A2, A3;
vector<int> B1, B2, B3;

signed main() {
	int i;
	
	cin >> n;
	int genten = 0;
	
	rep(i, n) {
		int x, y;
		cin >> x >> y;
		if (x == 0 && y == 0) genten++;
		else {
			a.push_back(x);
			b.push_back(y);
		}
	}
	n = a.size();
	
	rep(i, n) {
		A1.push_back(Mod(a[i], p1));
		A2.push_back(Mod(a[i], p2));
		A3.push_back(Mod(a[i], p3));
		B1.push_back(Mod(b[i], p1));
		B2.push_back(Mod(b[i], p2));
		B3.push_back(Mod(b[i], p3));
	}
	
	/*rep(i, n) {
		int j;
		for (j = i + 1; j < n; j++) {
			if (a[i] * a[j] + b[i] * b[j] == 0) {
				cout << "(" << i << ", " << j << ")" << endl;
			}
		}
	}*/
	
	int group_x = 0;
	int group_y = 0;
	map<T, vector<int>> ps;
	
	rep(i, n) {
		if (b[i] == 0) { //x軸上
			group_x++;
		}
		else if (a[i] == 0) { //y軸上
			group_y++;
		}
		else { //それ以外
			//(a[i] / b[i])でグループを識別. ハッシュで管理.
			int h1 = A1[i] * powmod(B1[i], p1 - 2, p1) % p1;
			int h2 = A2[i] * powmod(B2[i], p2 - 2, p2) % p2;
			int h3 = A3[i] * powmod(B3[i], p3 - 2, p3) % p3;
			T _hash = T(h1, h2, h3);
			ps[_hash].push_back(i);
		}
	}
	
	int mod = 1000000007;
	int ans = 1;
	set<T> seen;
	
	for (map<T, vector<int>>::iterator it = ps.begin(); it != ps.end(); it++) {
		if (seen.find(it->first) != seen.end()) { continue; }
		
		vector<int> group = it->second;
		int id = group[0];
		
		//cout << "a / b = " << (double)a[id] / b[id] << endl;
		//cout << "-b / a = " << -(double)b[id] / a[id] << endl;
		
		//cout << "group : " << endl;
		//rep(i, group.size()) { cout << group[i] << " "; }
		//cout << endl;
		
		//(-b[id] / a[id]) == (a[i] / b[i])なる他のグループを探す
		int h1 = (p1 - B1[id]) % p1 * powmod(A1[id], p1 - 2, p1) % p1;
		int h2 = (p2 - B2[id]) % p2 * powmod(A2[id], p2 - 2, p2) % p2;
		int h3 = (p3 - B3[id]) % p3 * powmod(A3[id], p3 - 2, p3) % p3;
		T hsh = T(h1, h2, h3);
		
		map<T, vector<int>>::iterator it2 = ps.find(hsh);
		if (it2 != ps.end()) {	//見つかった場合
			vector<int> &group2 = it2->second;
			
			//cout << "find group:" << endl;
			//rep(i, group2.size()) { cout << group2[i] << " "; }
			//cout << endl;
			
			int res = powmod(2, group.size(), mod) + powmod(2, group2.size(), mod) % mod + mod - 1;
			res %= mod;
			ans *= res;
			ans %= mod;
			
			T tup = it2->first;
			seen.insert(tup);
		}
		else {
			ans *= powmod(2, group.size(), mod);
			ans %= mod;
		}
	}
	ans *= (powmod(2, group_x, mod) + powmod(2, group_y, mod) + mod - 1) % mod;
	ans %= mod;
	ans = (ans + mod - 1) % mod;
	ans = (ans + genten) % mod;
	cout << ans << endl;
	return 0;
}

Measured memory_bytes: 42228