#include <bits/stdc++.h>
using namespace std;
int n;
double eps = 1e-8;
double pi = atan(1) * 4;
long long mod = 1000000007;
long long F[1000001];
struct vect2D {
  double x, y;
  double ang;
  int rep;
  vect2D() { x = y = 0; }
  vect2D(double _x, double _y) { x = _x, y = _y; }
  vect2D operator+(vect2D u) { return vect2D(x + u.x, y + u.y); }
  vect2D operator-(vect2D u) { return vect2D(x - u.x, y - u.y); }
  vect2D to(vect2D& u) { return vect2D(u.x - x, u.y - y); }
  vect2D operator*(double u) { return vect2D(x * u, y * u); }
  vect2D operator/(double u) { return vect2D(x / u, y / u); }
  bool operator==(vect2D that) {
    return abs(x - that.x) + abs(y - that.y) < eps;
  }
  double dotProd(vect2D u) { return x * u.x + y * u.y; }
  double crossProd(vect2D u) { return x * u.y - y * u.x; }
  double len() { return sqrt(x * x + y * y); }
  double len2() { return x * x + y * y; }
  double dist() { return sqrt(x * x + y * y); }
  double signedAngleRad(vect2D u) {
    if (dotProd(u) < 0) return pi - asin(crossProd(u) / (len() * u.len()));
    return asin(crossProd(u) / (len() * u.len()));
  }
  double signedAngleDeg(vect2D u) { return signedAngleRad(u) / pi * 180; }
  vect2D resize(double u) { return (*this) * (u / len()); }
  vect2D normalize() { return resize(1); }
  vect2D projectTo(vect2D u) { return u.resize(dotProd(u.normalize())); }
  vect2D tangentTo(vect2D u) { return (*this) - projectTo(u); }
  friend ostream& operator<<(ostream& os, const vect2D& v) {
    return os << "(" << v.x << ", " << v.y << ")";
  }
  bool operator<(vect2D that) const {
    if (abs(x - that.x) < eps) {
      return y < that.y;
    }
    return x < that.x;
  }
} P[1001];
vector<vect2D> mids;
bool dircmp(vect2D A, vect2D B) {
  if (A.to(B).len() < eps) return A.ang < B.ang;
  return A < B;
}
int MAIN() {
  F[0] = 1;
  F[1] = 2;
  for (int i = 2; i <= 1000000; i++) F[i] = (F[i - 1] * 2) % mod;
  cin >> n;
  for (int i = 1; i <= n; i++) {
    double a, b, c, d;
    cin >> a >> b >> c >> d;
    P[i].x = a / b;
    P[i].y = c / d;
    P[i] = P[i].resize(100 / P[i].len());
  }
  for (int i = 1; i <= n; i++)
    for (int j = i + 1; j <= n; j++) {
      vect2D mid = (P[i] + P[j]) / 2;
      vect2D dir = P[i].to(P[j]);
      if (abs(dir.x) < eps) {
        if (dir.y < 0) dir.y *= -1;
      } else {
        if (dir.x < 0) {
          dir.x *= -1;
          dir.y *= -1;
        }
      }
      mid.ang = atan2(dir.y, dir.x);
      mid.rep = 1;
      mids.push_back(mid);
    }
  sort(mids.begin(), mids.end(), dircmp);
  int last = 0, rep = 1, thisCase = 0;
  long long ans = 0;
  long long muls = 1;
  vector<vect2D> setAns;
  for (int i = 0; i < mids.size(); i++) {
    if (i > 1 && (mids[i] - mids[i - 1]).len() < eps &&
        (mids[i].ang - mids[i - 1].ang) < eps)
      setAns[setAns.size() - 1].rep++;
    else
      setAns.push_back(mids[i]);
  }
  for (int i = 0; i < setAns.size(); i++) {
    int j = i;
    long long sum = setAns[j].rep;
    long long mul = setAns[j].rep + 1;
    while (j + 1 < setAns.size() && (setAns[j + 1] - setAns[i]).len() < eps) {
      j++;
      sum += setAns[j].rep;
      mul *= setAns[j].rep + 1;
      mul %= mod;
    }
    ans += mul;
    ans -= sum;
    ans -= 1;
    ans %= mod;
    i = j;
  }
  ans %= mod;
  ans += mod;
  ans %= mod;
  cout << ans << endl;
  return 0;
}
int main() {
  ios ::sync_with_stdio(false);
  cout << fixed << setprecision(16);
  return MAIN();
}
