use proconio::{fastout, input};
// use proconio::marker::*;
use std::collections::BTreeMap;

fn gcd(a: i64, b: i64) -> i64 {
   if a == 0 {
      b
   } else if b == 0 {
      a
   } else {
      gcd(b, a % b)
   }
}

#[fastout]
fn main() {
   input! {
      mut n: usize,
      ab: [(i64, i64); n]
   }
   let mut zero = 0;
   let mut hm = BTreeMap::<(i64, i64), (usize, usize)>::new();
   for (_a, _b) in ab {
      if _a == 0 && _b == 0 {
         zero += 1;
         continue;
      }

      let m = gcd(_a.abs(), _b.abs());
      let a = _a.abs() / m;
      let b = _b.abs() / m;

      if a == 0 {
         if let Some(v) = hm.get_mut(&(a, b)) {
            v.0 += 1;
         } else {
            hm.insert((a, b), (1usize, 0usize));
         }
      } else if b == 0 {
         if let Some(v) = hm.get_mut(&(b, a)) {
            v.1 += 1;
         } else {
            hm.insert((b, a), (0usize, 1usize));
         }
      } else if (_a / _a.abs()) * (_b / _b.abs()) > 0 {
         if let Some(v) = hm.get_mut(&(a, b)) {
            v.0 += 1;
         } else {
            hm.insert((a, b), (1usize, 0usize));
         }
      } else {
         if let Some(v) = hm.get_mut(&(b, a)) {
            v.1 += 1;
         } else {
            hm.insert((b, a), (0usize, 1usize));
         }
      }
   }

   let mut ans = Mint::new(1);
   for &(l, r) in hm.values() {
      ans *= Mint::new(2).pow(l) + Mint::new(2).pow(r) - Mint::new(1);
   }
   ans -= Mint::new(1);
   ans += Mint::new(zero);
   println!("{}", ans);
}

use std::ops::*;
const MOD: i64 = 1000000007;
#[derive(Copy, Clone, Debug)]
pub struct Mint {
   x: i64,
}
impl Mint {
   fn new(x: i64) -> Self { Mint { x: x } }
   fn pow(self, n: usize) -> Self {
      let mut x = Mint::new(1);
      let mut r = self;
      let mut n = n;
      while n > 0 {
         if n & 1 == 1 {
            x *= r;
         }
         r *= r;
         n >>= 1;
      }
      x
   }
   fn inv(self) -> Self { self.pow((MOD - 2) as usize) }
}
impl AddAssign for Mint {
   fn add_assign(&mut self, rhs: Self) {
      self.x += rhs.x;
      self.x %= MOD;
   }
}
impl Add for Mint {
   type Output = Self;
   fn add(self, other: Self) -> Self {
      let mut res = self;
      res += other;
      res
   }
}
impl SubAssign for Mint {
   fn sub_assign(&mut self, rhs: Self) {
      self.x -= rhs.x;
      if self.x < 0 {
         self.x += MOD;
      }
   }
}
impl Sub for Mint {
   type Output = Self;
   fn sub(self, other: Self) -> Self {
      let mut res = self;
      res -= other;
      res
   }
}
impl MulAssign for Mint {
   fn mul_assign(&mut self, rhs: Self) {
      self.x *= rhs.x;
      self.x %= MOD;
   }
}
impl Mul for Mint {
   type Output = Self;
   fn mul(self, other: Self) -> Self {
      let mut res = self;
      res *= other;
      res
   }
}
impl DivAssign for Mint {
   fn div_assign(&mut self, rhs: Self) { *self *= rhs.inv(); }
}
impl Div for Mint {
   type Output = Self;
   fn div(self, other: Self) -> Self {
      let mut res = self;
      res *= other;
      res
   }
}
impl From<i64> for Mint {
   fn from(num: i64) -> Self { Mint { x: num } }
}
impl From<i32> for Mint {
   fn from(num: i32) -> Self { Mint { x: num as i64 } }
}
impl From<usize> for Mint {
   fn from(num: usize) -> Self { Mint { x: num as i64 } }
}
use std::fmt;
impl fmt::Display for Mint {
   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.x) }
}


Measured memory_bytes: 23104