#include<stdio.h>
#include<vector>
#include<algorithm>
#include<stdlib.h>
#include<math.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll>pii;
typedef pair<pii,pii>pi4;
typedef pair<pi4,pii>pi6;
ll mod=1000000007;
ll gcd(ll a,ll b)
{
for(;;)
{
if(a<b)
{
swap(a,b);
}
a%=b;
if(a==0)
{
return b;
}
}
}
pii reduct(pii a)
{
if(a.second==0)
{
return make_pair(1LL,0LL);
}
if(a.first==0)
{
return make_pair(0LL,1LL);
}
ll g=gcd(abs(a.first),abs(a.second));
if(a.second<0)
{
a.first=-a.first;
a.second=-a.second;
}
return make_pair(a.first/g,a.second/g);
}
pii pls(pii a,pii b)
{
return reduct(make_pair(a.first*b.second+a.second*b.first,a.second*b.second));
}
pii mins(pii a,pii b)
{
return reduct(make_pair(a.first*b.second-a.second*b.first,a.second*b.second));
}
pii tim(pii a,pii b)
{
return reduct(make_pair(a.first*b.first,a.second*b.second));
}
pii div(pii a,pii b)
{
return reduct(make_pair(a.first*b.second,a.second*b.first));
}
pi4 getsum(pi4 a,pi4 b)
{
return make_pair(pls(a.first,b.first),pls(a.second,b.second));
}
pii getinc(pi4 a,pi4 b)
{
pii dx=mins(b.first,a.first);
pii dy=mins(b.second,a.second);
return div(dy,dx);
}
pi4 inv(ll za,ll zb,ll zc,ll zd)
{
pii dist=pls(tim(make_pair(za,zb),make_pair(za,zb)),tim(make_pair(zc,zd),make_pair(zc,zd)));
return (make_pair(div(make_pair(za,zb),dist),div(make_pair(zc,zd),dist)));
}
vector<int>tov(vector<pii>vec)
{
pii now=make_pair(2000000000000000000LL,2000000000000000000LL);
vector<int>ret;
for(int i=0;i<vec.size();i++)
{
if(now!=vec[i])
{
ret.push_back(1);
now=vec[i];
}
else
{
ret[ret.size()-1]++;
}
}
return ret;
}
ll calc(vector<pii>v)
{
vector<int>vec=tov(v);
ll ret=1;
for(int i=0;i<vec.size();i++)
{
ret*=vec[i]+1;
ret%=mod;
}
ret=(ret+mod-1-int(v.size()))%mod;
return ret;
}
int main()
{
int num;
scanf("%d",&num);
vector<pi4>dat;
for(int i=0;i<num;i++)
{
ll za,zb,zc,zd;
scanf("%I64d%I64d%I64d%I64d",&za,&zb,&zc,&zd);
dat.push_back(inv(za,zb,zc,zd));
}
vector<pi6>vec;
for(int i=0;i<num;i++)
{
for(int j=i+1;j<num;j++)
{
vec.push_back(make_pair(getsum(dat[i],dat[j]),getinc(dat[i],dat[j])));
}
}
sort(vec.begin(),vec.end());
pi4 nowsum=make_pair(make_pair(2000000000000000000LL,2000000000000000000LL),make_pair(2000000000000000000LL,2000000000000000000LL));
vector<pii>now;
ll ret=0;
for(int i=0;i<vec.size();i++)
{
if(nowsum!=vec[i].first)
{
if(!now.empty())
{
ret+=calc(now);
ret%=mod;
}
now.clear();
now.push_back(vec[i].second);
nowsum=vec[i].first;
}
else
{
now.push_back(vec[i].second);
}
}
ret+=calc(now);
ret%=mod;
printf("%I64d\n",ret);
}
I2luY2x1ZGU8c3RkaW8uaD4KI2luY2x1ZGU8dmVjdG9yPgojaW5jbHVkZTxhbGdvcml0aG0+CiNpbmNsdWRlPHN0ZGxpYi5oPgojaW5jbHVkZTxtYXRoLmg+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CnR5cGVkZWYgbG9uZyBsb25nIGxsOwp0eXBlZGVmIHBhaXI8bGwsbGw+cGlpOwp0eXBlZGVmIHBhaXI8cGlpLHBpaT5waTQ7CnR5cGVkZWYgcGFpcjxwaTQscGlpPnBpNjsKbGwgbW9kPTEwMDAwMDAwMDc7CmxsIGdjZChsbCBhLGxsIGIpCnsKCWZvcig7OykKCXsKCQlpZihhPGIpCgkJewoJCQlzd2FwKGEsYik7CgkJfQoJCWElPWI7CgkJaWYoYT09MCkKCQl7CgkJCXJldHVybiBiOwoJCX0KCX0KfQpwaWkgcmVkdWN0KHBpaSBhKQp7CglpZihhLnNlY29uZD09MCkKCXsKCQlyZXR1cm4gbWFrZV9wYWlyKDFMTCwwTEwpOwoJfQoJaWYoYS5maXJzdD09MCkKCXsKCQlyZXR1cm4gbWFrZV9wYWlyKDBMTCwxTEwpOwoJfQoJbGwgZz1nY2QoYWJzKGEuZmlyc3QpLGFicyhhLnNlY29uZCkpOwoJaWYoYS5zZWNvbmQ8MCkKCXsKCQlhLmZpcnN0PS1hLmZpcnN0OwoJCWEuc2Vjb25kPS1hLnNlY29uZDsKCX0KCXJldHVybiBtYWtlX3BhaXIoYS5maXJzdC9nLGEuc2Vjb25kL2cpOwp9CnBpaSBwbHMocGlpIGEscGlpIGIpCnsKCXJldHVybiByZWR1Y3QobWFrZV9wYWlyKGEuZmlyc3QqYi5zZWNvbmQrYS5zZWNvbmQqYi5maXJzdCxhLnNlY29uZCpiLnNlY29uZCkpOwp9CnBpaSBtaW5zKHBpaSBhLHBpaSBiKQp7CglyZXR1cm4gcmVkdWN0KG1ha2VfcGFpcihhLmZpcnN0KmIuc2Vjb25kLWEuc2Vjb25kKmIuZmlyc3QsYS5zZWNvbmQqYi5zZWNvbmQpKTsKfQpwaWkgdGltKHBpaSBhLHBpaSBiKQp7CglyZXR1cm4gcmVkdWN0KG1ha2VfcGFpcihhLmZpcnN0KmIuZmlyc3QsYS5zZWNvbmQqYi5zZWNvbmQpKTsKfQpwaWkgZGl2KHBpaSBhLHBpaSBiKQp7CglyZXR1cm4gcmVkdWN0KG1ha2VfcGFpcihhLmZpcnN0KmIuc2Vjb25kLGEuc2Vjb25kKmIuZmlyc3QpKTsKfQpwaTQgZ2V0c3VtKHBpNCBhLHBpNCBiKQp7CglyZXR1cm4gbWFrZV9wYWlyKHBscyhhLmZpcnN0LGIuZmlyc3QpLHBscyhhLnNlY29uZCxiLnNlY29uZCkpOwp9CnBpaSBnZXRpbmMocGk0IGEscGk0IGIpCnsKCXBpaSBkeD1taW5zKGIuZmlyc3QsYS5maXJzdCk7CglwaWkgZHk9bWlucyhiLnNlY29uZCxhLnNlY29uZCk7CglyZXR1cm4gZGl2KGR5LGR4KTsKfQpwaTQgaW52KGxsIHphLGxsIHpiLGxsIHpjLGxsIHpkKQp7CglwaWkgZGlzdD1wbHModGltKG1ha2VfcGFpcih6YSx6YiksbWFrZV9wYWlyKHphLHpiKSksdGltKG1ha2VfcGFpcih6Yyx6ZCksbWFrZV9wYWlyKHpjLHpkKSkpOwoJcmV0dXJuIChtYWtlX3BhaXIoZGl2KG1ha2VfcGFpcih6YSx6YiksZGlzdCksZGl2KG1ha2VfcGFpcih6Yyx6ZCksZGlzdCkpKTsKfQp2ZWN0b3I8aW50PnRvdih2ZWN0b3I8cGlpPnZlYykKewoJcGlpIG5vdz1tYWtlX3BhaXIoMjAwMDAwMDAwMDAwMDAwMDAwMExMLDIwMDAwMDAwMDAwMDAwMDAwMDBMTCk7Cgl2ZWN0b3I8aW50PnJldDsKCWZvcihpbnQgaT0wO2k8dmVjLnNpemUoKTtpKyspCgl7CgkJaWYobm93IT12ZWNbaV0pCgkJewoJCQlyZXQucHVzaF9iYWNrKDEpOwoJCQlub3c9dmVjW2ldOwoJCX0KCQllbHNlCgkJewoJCQlyZXRbcmV0LnNpemUoKS0xXSsrOwoJCX0KCX0KCXJldHVybiByZXQ7Cn0KbGwgY2FsYyh2ZWN0b3I8cGlpPnYpCnsKCXZlY3RvcjxpbnQ+dmVjPXRvdih2KTsKCWxsIHJldD0xOwoJZm9yKGludCBpPTA7aTx2ZWMuc2l6ZSgpO2krKykKCXsKCQlyZXQqPXZlY1tpXSsxOwoJCXJldCU9bW9kOwoJfQoJcmV0PShyZXQrbW9kLTEtaW50KHYuc2l6ZSgpKSklbW9kOwoJcmV0dXJuIHJldDsKfQppbnQgbWFpbigpCnsKCWludCBudW07CglzY2FuZigiJWQiLCZudW0pOwoJdmVjdG9yPHBpND5kYXQ7Cglmb3IoaW50IGk9MDtpPG51bTtpKyspCgl7CgkJbGwgemEsemIsemMsemQ7CgkJc2NhbmYoIiVJNjRkJUk2NGQlSTY0ZCVJNjRkIiwmemEsJnpiLCZ6YywmemQpOwoJCWRhdC5wdXNoX2JhY2soaW52KHphLHpiLHpjLHpkKSk7Cgl9Cgl2ZWN0b3I8cGk2PnZlYzsKCWZvcihpbnQgaT0wO2k8bnVtO2krKykKCXsKCQlmb3IoaW50IGo9aSsxO2o8bnVtO2orKykKCQl7CgkJCXZlYy5wdXNoX2JhY2sobWFrZV9wYWlyKGdldHN1bShkYXRbaV0sZGF0W2pdKSxnZXRpbmMoZGF0W2ldLGRhdFtqXSkpKTsKCQl9Cgl9Cglzb3J0KHZlYy5iZWdpbigpLHZlYy5lbmQoKSk7CglwaTQgbm93c3VtPW1ha2VfcGFpcihtYWtlX3BhaXIoMjAwMDAwMDAwMDAwMDAwMDAwMExMLDIwMDAwMDAwMDAwMDAwMDAwMDBMTCksbWFrZV9wYWlyKDIwMDAwMDAwMDAwMDAwMDAwMDBMTCwyMDAwMDAwMDAwMDAwMDAwMDAwTEwpKTsKCXZlY3RvcjxwaWk+bm93OwoJbGwgcmV0PTA7Cglmb3IoaW50IGk9MDtpPHZlYy5zaXplKCk7aSsrKQoJewoJCWlmKG5vd3N1bSE9dmVjW2ldLmZpcnN0KQoJCXsKCQkJaWYoIW5vdy5lbXB0eSgpKQoJCQl7CgkJCQlyZXQrPWNhbGMobm93KTsKCQkJCXJldCU9bW9kOwoJCQl9CgkJCW5vdy5jbGVhcigpOwoJCQlub3cucHVzaF9iYWNrKHZlY1tpXS5zZWNvbmQpOwoJCQlub3dzdW09dmVjW2ldLmZpcnN0OwoJCX0KCQllbHNlCgkJewoJCQlub3cucHVzaF9iYWNrKHZlY1tpXS5zZWNvbmQpOwoJCX0KCX0KCXJldCs9Y2FsYyhub3cpOwoJcmV0JT1tb2Q7CglwcmludGYoIiVJNjRkXG4iLHJldCk7Cn0=