use proconio::{input, fastout};
use std::collections::HashMap;
use std::collections::HashSet;
use num::Integer;

fn modpow(x: i64, y: i64, m: i64) -> i64 {
  if y == 0 { return 1; }
  if y == 1 { return x; }
  let mut ans = modpow(x, y>>1, m);
  ans = ans * ans % m;
  if y & 1 == 1 {
    ans = ans * x % m;
  }
  ans
}

fn gcd<T: Integer+Copy>(x: &T, y: &T) -> T {
  if y == &T::zero() {
    *x
  } else {
    let t = *x % *y;
    gcd(y, &t)
  }
}

fn norm(x: i64, y: i64) -> (i64, i64) {
  let (ax, ay) = (x.abs(), y.abs());
  let g = gcd(&ax, &ay);
  (x / g, y / g)
}

#[fastout]
fn main() {
  let mmm = 1000000007;
  input!{
    n: usize,
    ab: [(i64, i64); n]
  };
  let mut h : HashMap<(i64, i64), i64> = HashMap::new();
  let mut zerozero = 0;
  for (a, b) in &ab {
    let (a, b) = if *b < 0 {
      (*a * -1, *b * -1)
    } else {
      (*a, *b)
    };
    if a == 0 && b == 0 {
      zerozero += 1;
    } else if a == 0 {
      *h.entry((0, 1)).or_insert(0) += 1;
    } else if b == 0 {
      *h.entry((1, 0)).or_insert(0) += 1;
    } else {
      *h.entry(norm(a, b)).or_insert(0) += 1;
    }
  }
  // dbg!(&h);

  let mut ans : i64 = 1;
  let mut s : HashSet<(i64, i64)> = HashSet::new();
  for (r, v) in &h {
    let r = *r;
    let v = *v;
    if !s.contains(&r) {
      let r2 = if r.0 <= 0 {
        (r.1, r.0 * -1)
      } else {
        (r.1 * -1, r.0)
      };
      let v2  = match h.get(&r2) {
        Some(vv2) => *vv2,
        None => 0
      };
      let mut pow = (modpow(2, v, mmm) + modpow(2, v2, mmm) - 1) % mmm;
      while pow < 0 {
        pow += mmm;
      }
      // dbg!(&r, &s, &pow, v, v2);
      s.insert(r);
      s.insert(r2);
      ans = ans * pow % mmm;
    }
  }
  ans -= 1;
  ans += modpow(2, zerozero, mmm) - 1;
  while ans < 0 {
    ans += mmm;
  }
  println!("{}", ans % mmm);
}
