#include <bits/stdc++.h>
constexpr long long int MOD = 1000000007;
struct Coordinate {
  long long int a, b;
  bool operator<(const Coordinate& that) const {
    return a == that.a ? b < that.b : a < that.a;
  }
};
long long int gcd(const long long int a, const long long int b) {
  return b == 0 ? a : gcd(b, a % b);
}
long long int power(const long long int base, const long long int exp) {
  switch (exp) {
    case 0:
      return 1L;
    case 1:
      return base % MOD;
    default:
      return power(base * base % MOD, exp >> 1) * power(base, exp & 1) % MOD;
  }
}
int main() {
  std::cin.tie(nullptr);
  std::cin.sync_with_stdio(false);
  int n;
  std::cin >> n;
  std::vector<Coordinate> points(n);
  for (auto& point : points) {
    long long int a, b;
    std::cin >> a >> b;
    const auto g = gcd(a, b);
    point.a = a / g;
    point.b = b / g;
  }
  std::map<Coordinate, long long int> appear;
  long long int both_zero{0}, a_zero{0}, b_zero{0};
  for (const auto& point : points) {
    if (point.a == 0 && point.b == 0) {
      ++both_zero;
    } else if (point.a == 0) {
      ++a_zero;
    } else if (point.b == 0) {
      ++b_zero;
    } else {
      appear[point]++;
    }
  }
  long long int valid_pattern = (power(2, a_zero) + power(2, b_zero) - 1) % MOD;
  while (!appear.empty()) {
    const auto first = *appear.begin();
    const auto origin = first.first;
    const auto opposite = Coordinate{-origin.a, -origin.b};
    const auto rightA = Coordinate{-origin.b, origin.a};
    const auto rightB = Coordinate{origin.b, -origin.a};
    const auto parallel = first.second + appear[opposite];
    const auto right = appear[rightA] + appear[rightB];
    valid_pattern *= (power(2, parallel) + power(2, right) - 1) % MOD;
    valid_pattern %= MOD;
    appear.erase(origin);
    appear.erase(opposite);
    appear.erase(rightA);
    appear.erase(rightB);
  }
  valid_pattern += both_zero - 1;
  std::cout << (valid_pattern % MOD + MOD) % MOD << '\n';
}
