use proconio::input;
use std::collections::BTreeMap;

const M: u32 = 1_000_000_007;

fn main() {
    input! {
        n: usize,
        d: [(i64, i64); n],
    }

    let mut z = 0;
    let mut t = BTreeMap::new();
    for e in d {
        if e.0 == 0 && e.1 == 0 {
            z += 1;
        } else if e.0 == 0 {
            *t.entry((0, 1)).or_insert(0) += 1;
        } else if e.1 == 0 {
            *t.entry((1, 0)).or_insert(0) += 1;
        } else {
            let g = num::integer::gcd(e.0.abs(), e.1.abs());
            let e = if e.0 < 0 {
                (-e.0, -e.1)
            } else {
                e
            };
            let e = (e.0 / g, e.1 / g);
            *t.entry((e.0, e.1)).or_insert(0) += 1;
        }
    }
    z %= M;

    let mut ans = 1;
    while let Some((&k, &c)) = t.iter().next() {
        t.remove(&k);
        let inv = if k.1 < 0 {
            (-k.1, k.0)
        } else {
            (k.1, -k.0)
        };

        let c2 = modpow(2, c);
        if let Some(invc) = t.remove(&inv) {
            let i2 = modpow(2, invc);
            ans *= c2 + i2 - 1;
        } else {
            ans *= c2;
        }
        ans %= M;
    }
    ans = (ans + z + M - 1) % M;
    println!("{}", ans);
}

fn modpow(x: u32, y: u32) -> u32 {
    let mut result = 1;
    let mut a = x;
    let mut b = y;
    while b > 0 {
        if b % 2 == 1 {
            result = result * a % M;
        }
        a = a * a % M;
        b /= 2;
    }
    result
}
