#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3fffffff;
const int SINF = 0x7fffffff;
const long long LINF = 0x3fffffffffffffff;
const long long SLINF = 0x7fffffffffffffff;
const long double DINF = pow(2, 100);
const int MAXN = 1007;
const int MOD = static_cast<int>(1e9 + 7);
const long double EPS = 1e-11;
struct cT {
  cT() : x(0), y(0) {}
  cT(long double _x, long double _y) : x(_x), y(_y) {}
  cT operator+(const cT &a) const { return cT(x + a.x, y + a.y); }
  cT operator-(const cT &a) const { return cT(x - a.x, y - a.y); }
  cT operator/(const int a) { return cT(x / a, y / a); }
  bool operator==(const cT &a) const {
    return ((((x - a.x) >= 0) ? (x - a.x) : (-(x - a.x))) < EPS &&
            (((y - a.y) >= 0) ? (y - a.y) : (-(y - a.y))) < EPS);
  }
  bool operator!=(const cT &a) const { return !((*this) == a); }
  bool operator<(const cT &a) const {
    return ((((x - a.x) >= 0) ? (x - a.x) : (-(x - a.x))) > EPS)
               ? x < a.x
               : y < a.y - EPS;
  }
  long double getk() {
    return (((x) >= 0) ? (x) : (-(x))) < EPS ? DINF : (y / x);
  }
  long double x, y;
} cr[MAXN];
struct dT {
  dT() : k(0) {}
  dT(cT _cr, long double _k) : cr(_cr), k(_k) {}
  bool operator<(const dT &a) const {
    return (cr != a.cr) ? cr < a.cr : k < a.k - EPS;
  }
  cT cr;
  long double k;
} med[MAXN * MAXN];
int n;
int km;
void init();
void input();
void work();
int getans(int l, int r);
int add(int x, int y) {
  x += y;
  if (x >= MOD) x -= MOD;
  return x;
}
void addv(int &x, int y) {
  x += y;
  if (x >= MOD) x -= MOD;
}
int dec(int x, int y) {
  x -= y;
  if (x < 0) x += MOD;
  return x;
}
void decv(int &x, int y) {
  x -= y;
  if (x < 0) x += MOD;
}
int main() {
  init();
  input();
  work();
}
void init() { ios::sync_with_stdio(false); }
void input() {
  scanf("%d", &n);
  int a, b, c, d;
  for (int i = 1; i <= n; ++i) {
    scanf("%d%d%d%d", &a, &b, &c, &d);
    cr[i].x = static_cast<long double>(a * b * d * d) /
              (a * a * d * d + b * b * c * c);
    cr[i].y = static_cast<long double>(c * d * b * b) /
              (a * a * d * d + b * b * c * c);
  }
}
void work() {
  for (int i = 1; i <= n; ++i) {
    for (int j = i + 1; j <= n; ++j) {
      med[++km] = dT((cr[i] + cr[j]) / 2, (cr[j] - cr[i]).getk());
    }
  }
  sort(med + 1, med + 1 + km);
  med[km + 1] = dT(cT(DINF, DINF), 1);
  int pre = 1, ans = 0;
  for (int i = 1; i <= km + 1; ++i) {
    if (med[i].cr != med[pre].cr) {
      addv(ans, getans(pre, i - 1));
      pre = i;
    }
  }
  cout << ans << endl;
}
int getans(int l, int r) {
  int pre = l;
  int ans = 1;
  for (int i = l; i <= r; ++i) {
    if ((((med[i].k - med[pre].k) >= 0) ? (med[i].k - med[pre].k)
                                        : (-(med[i].k - med[pre].k))) > EPS) {
      ans = static_cast<long long>(ans) * (i - pre + 1) % MOD;
      pre = i;
    }
  }
  ans = static_cast<long long>(ans) * (r - pre + 2) % MOD;
  return dec(ans, r - l + 2);
}
