//Use valgrind once if the submission doesn't go through. It can detect uninitialized variables and see where they could be an issue.
#include <bits/stdc++.h>
#include<numeric>
using namespace std;
long long pow2(long long n)
{
	if(n==0)
	{
		return 1;
	}
	else if(n%2==1)
	{
		return (2*pow2(n-1))%1000000007;
	}
	else
	{
		long long temp=pow2(n/2);
		return (temp*temp)%1000000007;
	}
}
int main(){

	ios_base::sync_with_stdio(false);
    	cin.tie(NULL);

	int N;
	long long count=1;
	cin>>N;
	vector<long long> a(N), b(N);
	map<pair<long long,long long>,pair<long long,long long>> m;
	m.insert({{0LL,0LL},{0LL,0LL}});
	for(int i=0;i<N;i++)
	{
		cin>>a[i]>>b[i];
		long long GCD=gcd(a[i],b[i]);
		if(GCD==0) GCD=1;
		if(m.find({a[i]/GCD,b[i]/GCD})!=m.end())
		{
			++m[{a[i]/GCD,b[i]/GCD}].first;
		}
		else if(m.find({-a[i]/GCD,-b[i]/GCD})!=m.end())
		{
			++m[{-a[i]/GCD,-b[i]/GCD}].first;
		}
		else if(m.find({-b[i]/GCD,a[i]/GCD})!=m.end())
		{
			m[{-b[i]/GCD,a[i]/GCD}].second+=1;
		}
		else if(m.find({b[i]/GCD,-a[i]/GCD})!=m.end())
		{
			++m[{b[i]/GCD,-a[i]/GCD}].second;
		}
		else
		{
			m.insert({{a[i]/GCD,b[i]/GCD},{1,0}});
		}
	}
	cout<<endl;
	for(auto i:m)
	{
		if(i.first.first==0&&i.first.second==0) continue;
		long long temp=count,t1=pow2(i.second.first),t2=pow2(i.second.second);
		count*=t1;
		count%=1000000007;
		temp*=t2-1;
		temp%=1000000007;
		count+=temp;
		count%=1000000007;
		cout<<count<<endl;
	}
	count+=m[{0,0}].first;
	//count%=1000000007;
	if(count!=0)
	cout<<count-1<<endl;
	else cout<<1000000006<<endl;
	return 0;
}