#![allow(unused_imports)]
use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;

#[allow(unused_macros)]
macro_rules! read {
    ([$t:ty] ; $n:expr) =>
        ((0..$n).map(|_| read!([$t])).collect::<Vec<_>>());
    ($($t:ty),+ ; $n:expr) =>
        ((0..$n).map(|_| read!($($t),+)).collect::<Vec<_>>());
    ([$t:ty]) =>
        (rl().split_whitespace().map(|w| w.parse().unwrap()).collect::<Vec<$t>>());
    ($t:ty) =>
        (rl().parse::<$t>().unwrap());
    ($($t:ty),*) => {{
        let buf = rl();
        let mut w = buf.split_whitespace();
        ($(w.next().unwrap().parse::<$t>().unwrap()),*)
    }};
}

#[allow(dead_code)]
fn rl() -> String {
    let mut buf = String::new();
    std::io::stdin().read_line(&mut buf).unwrap();
    buf.trim_end().to_owned()
}

trait IteratorExt: Iterator + Sized {
    fn vec(self) -> Vec<Self::Item> {
        self.collect()
    }
}

impl<T: Iterator> IteratorExt for T {}

fn main() {
    const MOD: usize = 1000000007;

    let mut map = HashMap::<(isize, isize), usize>::new();

    let n = read!(usize);
    for _ in 0..n {
        let (a, b) = read!(isize, isize);
        let (a, b) = normalize(a, b);

        if let Some(n) = map.get(&(a, b)) {
            let next = n + 1;
            map.insert((a, b), next);
        } else {
            map.insert((a, b), 1);
        }
    }

    let mut ans = 1;
    if let Some(n) = map.get(&(0,0)) {
        ans += n;
        map.remove(&(0,0));
    }

    while let Some((&(a, b), &n)) = map.iter().next() {
        let pair = normalize(b, -a);
        let mut add = mod_exp(2, n, MOD);
        if let Some(&o) = map.get(&pair) {
            add += mod_exp(2, o, MOD);
        } else {
            add += mod_exp(2, 0, MOD);
        }


        ans *= (add + MOD - 1) % MOD;
        ans %= MOD;

        map.remove(&(a,b));
        map.remove(&pair);
    }

    println!("{}", (ans + MOD - 1) % MOD);
}

fn normalize(a: isize, b: isize) -> (isize, isize) {
    match (a, b) {
        (0, 0) => { (0, 0) },
        (0, _) => { (0, 1) },
        (_, 0) => { (1, 0) },
        (mut alpha, mut beta) => {
            let sign = (alpha * beta) / (alpha * beta).abs();
            alpha = alpha.abs();
            beta = beta.abs();

            let gcd = gcd(alpha as usize, beta as usize);
            alpha /= gcd as isize;
            beta /= gcd as isize;

            (alpha, beta * sign)
        }
    }
}

fn gcd(mut a: usize, mut b: usize) -> usize {
    std::mem::swap(&mut a, &mut b);
    while b != 0 {
        let r = a%b;
        a = b;
        b = r;
    }
    a
}

// b**exp % m
fn mod_exp(base: usize, exp: usize, m: usize) -> usize {
    match exp {
        0 => 1,
        1 => base % m,
        n if n%2 == 0 => {
            let sqrt = mod_exp(base, exp/2, m);
            (sqrt * sqrt) % m
        },
        _ => {
            (base * mod_exp(base, exp-1, m)) % m
        }
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn mod_exp_test() {
        assert_eq!(16, crate::mod_exp(2, 4, 32));
        assert_eq!(1, crate::mod_exp(2, 4, 5));
        assert_eq!(24, crate::mod_exp(2, 10, 1000));
    }
}