{-# LANGUAGE TupleSections #-}

import qualified Data.ByteString.Char8 as B
import           Data.Maybe (fromJust)
import qualified Data.Map.Strict as M
import           Control.Monad (replicateM)

modT :: Integer
modT = 1000000007

main :: IO ()
main = do
  n <- getInt
  m <- M.fromListWith (+) . fmap ((, 1) . convert) <$> replicateM n getIntegers
  print . solve $ m

convert [a, b]
  | a == 0 && b == 0 = (0, 0)
  | a == 0 = (0, 1)
  | b == 0 = (1, 0)
  | otherwise = let gcd' = gcd a b
                in if b < 0
                   then (-div a gcd', -div b gcd')
                   else (div a gcd', div b gcd')

solve :: M.Map (Integer, Integer) Integer -> Integer
solve map = let zero = M.findWithDefault 0 (0, 0) map
                ans = solve' . M.delete (0, 0) $ map
            in (ans + fromIntegral zero - 1) `mod` modT

solve' :: M.Map (Integer, Integer) Integer -> Integer
solve' map =
  if M.null map
  then 1
  else let ((a, b), count) = M.elemAt 0 map
           inv = if a < 0
                 then (b, -a)
                 else (-b, a)
           count' = M.findWithDefault 0 inv map
           ncount = solve' . M.delete (a, b) . M.delete inv $ map
           ccount = 2 ^ count + 2 ^ count' - 1
       in (ncount * ccount) `mod` modT

getInt = fst . fromJust . B.readInt <$> B.getLine

getIntegers = fmap (fst . fromJust . B.readInteger) . B.words <$> B.getLine
