#[allow(unused_imports)]
use std::char::from_digit;
use std::cmp::{max, min};
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
use std::error::Error;
use std::fmt::Debug;
use std::io::prelude::*;
use std::io::{stdin, stdout, BufReader, BufWriter, Stdin, Stdout, Write};
use std::mem::swap;
use std::str::FromStr;

type BoxResult<T> = Result<T, Box<std::error::Error>>;

const MOD: u64 = 1000000007;

fn main() {
    let mut scanner = Scanner::new(stdin());
    let n = scanner.read::<usize>().unwrap();
    let mut items = vec![];
    for _ in 0..n {
        items.push(scanner.read_two::<i64, i64>().unwrap());
    }
    let ans = solve(n, &items);
    println!("{}", ans);
}

fn solve(_n: usize, items: &[(i64, i64)]) -> u64 {
    let mut map = HashMap::new();
    for &(a, b) in items {
        let key = encode(a, b);
        if map.contains_key(&key) {
            *map.get_mut(&key).unwrap() += 1;
        } else {
            map.insert(key, 1u64);
        }
    }
    // println!("{:?}", map);
    let mut count = 1u64;
    let mut used = HashSet::new();
    for (&key, &value) in map.iter() {
        if used.contains(&key) {
            continue;
        }
        used.insert(key);
        if key == (0, 0) {
            continue;
        }
        let mut total = power(2, value, MOD);
        let anti_key = calc_anti(key);
        if map.contains_key(&anti_key) {
            let c = map.get(&anti_key).unwrap();
            total = (total + power(2, *c, MOD) + MOD - 1) % MOD;
            used.insert(anti_key);
        }
        count = (count * total) % MOD;
    }
    let zeros = map.get(&(0, 0)).unwrap_or(&0);
    (count + MOD - 1 + *zeros) % MOD
}

fn encode(a: i64, b: i64) -> (i64, i64) {
    let (c, d) = if a == 0 && b != 0 {
        (0, 1)
    } else if b == 0 && a != 0 {
        (1, 0)
    } else if a < 0 {
        (-a, -b)
    } else {
        (a, b)
    };
    let g = gcd(c.abs(), d.abs());
    (c / g, d / g)
}

fn gcd(x: i64, y: i64) -> i64 {
    if x == 0 || y == 0 {
        return 1;
    }
    let z = x % y;
    if z == 0 {
        y
    } else {
        gcd(y, z)
    }
}

fn power(x: u64, mut k: u64, modulo: u64) -> u64 {
    let mut pows = vec![x];
    for i in 0..63 {
        let square = (pows[i] * pows[i]) % modulo;
        pows.push(square);
    }
    let mut pow = 1;
    for i in 0..63 {
        let flag = k & 1;
        k >>= 1;
        if flag == 1 {
            pow = (pow * pows[i]) % modulo;
        }
    }
    pow
}

fn calc_anti((x, y): (i64, i64)) -> (i64, i64) {
    let mut a = -y;
    let mut b = x;
    if a < 0 {
        a *= -1;
        b *= -1;
    }
    (a, b)
}

pub struct Scanner<R> {
    reader: BufReader<R>,
    buffer: String,
}
impl<R> Scanner<R>
where
    R: Read,
{
    pub fn new(inner: R) -> Scanner<R> {
        let reader = BufReader::new(inner);
        let buffer = String::new();
        Scanner {
            reader: reader,
            buffer: buffer,
        }
    }
    pub fn with_capacity(capacity: usize, inner: R) -> Scanner<R> {
        let reader = BufReader::with_capacity(capacity, inner);
        let buffer = String::new();
        Scanner {
            reader: reader,
            buffer: buffer,
        }
    }
    pub fn read_line(&mut self) -> BoxResult<String> {
        self.reader.read_line(&mut self.buffer)?;
        let cloned = self.buffer.trim().to_string();
        self.buffer.clear();
        Ok(cloned)
    }

    pub fn read<T>(&mut self) -> BoxResult<T>
    where
        T: FromStr,
        T::Err: Debug + Error + 'static,
    {
        self.reader.read_line(&mut self.buffer)?;
        let parsed = self.buffer.trim().parse()?;
        self.buffer.clear();
        Ok(parsed)
    }
    pub fn read_two<T, U>(&mut self) -> BoxResult<(T, U)>
    where
        T: FromStr + Copy,
        T::Err: Debug + Error + 'static,
        U: FromStr + Copy,
        U::Err: Debug + Error + 'static,
    {
        self.reader.read_line(&mut self.buffer)?;
        let (a, b) = {
            let params = self.buffer.trim().split_whitespace().collect::<Vec<_>>();
            let a = params[0].parse()?;
            let b = params[1].parse()?;
            (a, b)
        };
        self.buffer.clear();
        Ok((a, b))
    }
    pub fn read_three<T, U, V>(&mut self) -> BoxResult<(T, U, V)>
    where
        T: FromStr + Copy,
        T::Err: Debug + Error + 'static,
        U: FromStr + Copy,
        U::Err: Debug + Error + 'static,
        V: FromStr + Copy,
        V::Err: Debug + Error + 'static,
    {
        self.reader.read_line(&mut self.buffer)?;
        let (a, b, c) = {
            let params = self.buffer.trim().split_whitespace().collect::<Vec<_>>();
            let a = params[0].parse()?;
            let b = params[1].parse()?;
            let c = params[2].parse()?;
            (a, b, c)
        };
        self.buffer.clear();
        Ok((a, b, c))
    }
    pub fn read_four<T, U, V, W>(&mut self) -> BoxResult<(T, U, V, W)>
    where
        T: FromStr + Copy,
        T::Err: Debug + Error + 'static,
        U: FromStr + Copy,
        U::Err: Debug + Error + 'static,
        V: FromStr + Copy,
        V::Err: Debug + Error + 'static,
        W: FromStr + Copy,
        W::Err: Debug + Error + 'static,
    {
        self.reader.read_line(&mut self.buffer)?;
        let (a, b, c, d) = {
            let params = self.buffer.trim().split_whitespace().collect::<Vec<_>>();
            let a = params[0].parse()?;
            let b = params[1].parse()?;
            let c = params[2].parse()?;
            let d = params[3].parse()?;
            (a, b, c, d)
        };
        self.buffer.clear();
        Ok((a, b, c, d))
    }
    pub fn read_vector<T>(&mut self) -> BoxResult<Vec<T>>
    where
        T: FromStr + Copy,
        T::Err: Debug + Error + 'static,
    {
        self.reader.read_line(&mut self.buffer)?;
        let parsed_vec = self
            .buffer
            .trim()
            .split_whitespace()
            .map(|s| s.parse())
            .collect::<Result<Vec<_>, _>>()?;
        self.buffer.clear();
        Ok(parsed_vec)
    }
    pub fn read_matrix<T>(&mut self, lines: u64) -> BoxResult<Vec<Vec<T>>>
    where
        T: FromStr + Copy,
        T::Err: Debug + Error + 'static,
    {
        let mut parsed_matrix = vec![];
        for _ in 0..lines {
            self.reader.read_line(&mut self.buffer)?;
            parsed_matrix.push(
                self.buffer
                    .trim()
                    .split_whitespace()
                    .map(|s| s.parse())
                    .collect::<Result<Vec<_>, _>>()?,
            );
            self.buffer.clear();
        }
        Ok(parsed_matrix)
    }
    pub fn read_chars(&mut self) -> BoxResult<Vec<char>> {
        self.reader.read_line(&mut self.buffer)?;
        let chars = self.buffer.trim().chars().collect::<Vec<_>>();
        self.buffer.clear();
        Ok(chars)
    }
}


Measured memory_bytes: 20152