use std::error::Error;
use std::{
    collections::{HashMap, HashSet},
    io,
};

pub fn main() {
    if let Err(_e) = run() {
        panic!("failed.");
    }
}

fn run() -> Result<(), Box<dyn Error>> {
    let mut input = String::new();
    io::stdin().read_line(&mut input)?;
    let n = input.trim().parse::<i32>()?;
    input.clear();

    let mut all_zero_count = 0;
    let mut a_zero_count = 0;
    let mut b_zero_count = 0;
    let mut g_map: HashMap<i64, HashMap<i64, i64>> = HashMap::new();
    let mut result = 1;
    for _ in 0..n {
        io::stdin().read_line(&mut input)?;
        let line: Vec<i64> = input
            .trim()
            .split_whitespace()
            .map(|s| s.parse::<i64>().unwrap())
            .collect();
        let mut a = line[0];
        let mut b = line[1];
        input.clear();

        if a == 0 && b == 0 {
            all_zero_count += 1;
        } else if a == 0 {
            a_zero_count += 1;
        } else if b == 0 {
            b_zero_count += 1;
        } else {
            if a < 0 {
                a = -a;
                b = -b;
            }
            let g = gcd(a.abs(), b.abs());
            let count = g_map
                .entry(a / g)
                .or_insert_with(|| HashMap::new())
                .entry(b / g)
                .or_insert(0);
            *count += 1;
        }
    }
    // println!("{:?}", g_map);
    let mut visited_map: HashMap<i64, HashSet<i64>> = HashMap::new();

    for (&a, bs) in g_map.iter() {
        for (&b, &count) in bs.iter() {
            if visited_map.contains_key(&a) {
                if visited_map.get(&a).unwrap().contains(&b) {
                    continue;
                }
            }
            let mut variation = 0; // either is zero may count twice
            variation += pow(2, count);
            variation %= 1_000_000_007;
            let mut aj = -b;
            let mut bj = a;

            if aj < 0 {
                aj = -aj;
                bj = -bj;
            }

            if let Some(map) = g_map.get(&aj) {
                if let Some(&count) = map.get(&bj) {
                    variation += pow(2, count);
                    variation %= 1_000_000_007;
                    variation = (variation + 1_000_000_007 - 1) % 1_000_000_007;
                    let set = visited_map.entry(aj).or_insert_with(HashSet::new);
                    set.insert(bj);
                }
            }
            // println!("{}, {}>>>{}, {} = {}", a, b, aj, bj, variation);
            result *= variation;
            result %= 1_000_000_007;
        }
    }
    // println!(">>>>>{}", result);
    // TODO, how to handle a or b is 0.
    let mut variation = 0;
    if a_zero_count > 0 {
        variation += pow(2, a_zero_count);
        variation %= 1_000_000_007;
        if b_zero_count > 0 {
            variation += pow(2, b_zero_count);
            variation %= 1_000_000_007;
            variation = (variation + 1_000_000_007 - 1) % 1_000_000_007;
        }
        result *= variation;
        result %= 1_000_000_007;
    } else if b_zero_count > 0 {
        variation += pow(2, b_zero_count);
        variation %= 1_000_000_007;
        result *= variation;
        result %= 1_000_000_007;
    }

    result += all_zero_count;
    result %= 1_000_000_007;
    result = (result + 1_000_000_007 - 1) % 1_000_000_007;

    println!("{}", result);
    Ok(())
}
fn pow(base: i64, exponent: i64) -> i64 {
    if exponent == 0 {
        return 1;
    }
    if exponent == 1 {
        return base;
    }

    let temp = pow(base, exponent / 2);
    if exponent % 2 == 0 {
        return (temp * temp) % 1_000_000_007;
    }

    return (base * temp * temp) % 1_000_000_007;
}

fn gcd(mut a: i64, b: i64) -> i64 {
    if a < b {
        return gcd(b, a);
    }
    if b == 0 {
        return a;
    }
    a %= b;
    return gcd(b, a);
}


Measured memory_bytes: 34156