use proconio::{fastout, input};

#[allow(unused_imports)]
use std::cmp::*;
#[allow(unused_imports)]
use std::collections::*;

const MOD: usize = 1000000007;

// mod p で x^n
fn repeated_squaring(x: usize, n: usize, p: usize) -> usize {
    if n == 0 {
        1
    } else if n % 2 == 0 {
        repeated_squaring(x * x % p, n / 2, p)
    } else {
        (x * repeated_squaring(x * x % p, n / 2, p)) % p
    }
}

#[fastout]
fn main() {
    input! {
        n: usize,
        ab: [(isize, isize); n],
    }

    let gcd = num::integer::gcd;

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

    let mut zero = 0;
    for (a, b) in &ab {
        if *a == 0 && *b == 0 {
            zero += 1;
        } else {
            let c = gcd(*a, *b);
            let mut aa: isize = (*a).abs() / c;
            let mut bb: isize = (*b).abs() / c;

            let mut plus = true;
            if (*a < 0 && *b > 0) || (*a > 0 && *b < 0) {
                plus = false;
                let tmp = aa;
                aa = bb;
                bb = tmp;
            }

            if !hash.contains_key(&(aa, bb)) {
                if plus {
                    hash.insert((aa, bb), (1, 0));
                } else {
                    hash.insert((aa, bb), (0, 1));
                }
            } else {
                let (pi, ni) = hash[&(aa, bb)];
                if plus {
                    hash.insert((aa, bb), (pi + 1, ni));
                } else {
                    hash.insert((aa, bb), (pi, ni + 1));
                }
            }
        }
    }

    let mut ans = 1;
    for (_, v) in &hash {
        ans *= repeated_squaring(2, (*v).0, MOD) + repeated_squaring(2, (*v).1, MOD) - 1;
        ans %= MOD;
    }

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