# ABC 168 E
# https://atcoder.jp/contests/contests/abc168/tasks/contests/abc168_e

# WA
# https://atcoder.jp/contests/abc168/submissions/13407143

# WA: sub1_11, sub1_13, sub1_16

n = read_line.to_i64

class Sardine
  def initialize(@taste : Int64, @fragrance : Int64)
    @gcd = taste.abs.gcd(fragrance.abs)
  end

  getter :taste, :fragrance
  getter gcd : Int64

  def to_a : Array(Int64)
    [taste, fragrance]
  end

  def basis_vector : Array(Int64)
    return [0_i64, 0_i64] if to_a.all?(&.zero?)
    return [0_i64, 1_i64] if to_a.first.zero?
    return [1_i64, 0_i64] if to_a.last.zero?

    a = to_a.map { |i| i // gcd }
    if a.first < 0 # [-, +], [-, -] の形のベクトルは [+, -] または [+, +] になるようにする
      a.map { |i| i * -1 }
    else
      a
    end
  end
end

class SardineGroup
  def initialize(@basis_vector : Array(Int64), @sardines : Array(Sardine))
    @invalid_group = nil
    @checked = false
  end

  getter :basis_vector, :sardines

  property invalid_group : SardineGroup | Nil
  property checked : Bool

  def calc(mod) : Int64
    return size if basis_vector.all?(&.zero?)

    sardines_size = size

    j = ((2_i64 ** sardines_size) % mod).to_i64

    if invalid_group.nil?
      # puts "sardines_size: #{sardines_size}, j: #{j}"
      return j
    end

    invalid_group_instance = invalid_group.as(SardineGroup)

    k = (2_i64 ** invalid_size) % mod
    invalid_checked!

    # puts "j + k - 1: #{j} + #{k} - 1 = #{j + k - 1}"

    (j + k - 1).to_i64 % mod
  end

  def size : Int64
    sardines.size.to_i64
  end

  def basis_vector_inverse
    basis_vector[1] < 0 ? [basis_vector[1] * -1, basis_vector[0]] : [basis_vector[1], basis_vector[0] * -1] # [+, -] または [+, +] になるようにする
  end

  private def invalid_size : Int64
    if invalid_group.nil?
      0_i64
    else
      invalid_group.as(SardineGroup).sardines.size.to_i64
    end
  end

  private def invalid_checked!
    invalid_group.as(SardineGroup).checked = true
  end
end

h = Array.new(n) { a, b = read_line.split.map(&.to_i64); Sardine.new(a, b) }.group_by(&.basis_vector)

sardine_groups = Hash(Array(Int64), SardineGroup).new
h.each do |basis_vector, sardines|
  sardine_groups[basis_vector] = SardineGroup.new(basis_vector, sardines)
end

sardine_groups.each do |basis_vector, sardine_group|
  next if basis_vector.all?(&.zero?)
  basis_vector_inverse = sardine_group.basis_vector_inverse
  if sardine_groups.has_key?(basis_vector_inverse)
    # puts "basis_vector: #{basis_vector}, basis_vector_inverse: #{basis_vector_inverse}"
    sardine_groups[basis_vector].invalid_group = sardine_groups[basis_vector_inverse]
  end
end

# sardine_groups.each do |basis_vector, sardine_group|
#   puts "#{basis_vector.inspect}"
#   puts "  (#{sardine_group.sardines.size})"
#   puts "  #{sardine_group.inspect}"
# end

mod = 1000000007_i64
# combination_calculator = Combination.generate(n, mod)

sardine_group_with_zero_basis_vector = sardine_groups.delete([0_i64, 0_i64])

def calc_sardine_groups(sardine_groups : Hash(Array(Int64), SardineGroup), mod) : Int64
  return 0_i64 if sardine_groups.size == 0

  i = 1_i64
  sardine_groups.each do |basis_vector, sardine_group|
    next if sardine_group.checked
    i *= sardine_group.calc(mod)
    i %= mod
  end
  (i - 1_i64) % mod
end

i = 0_i64
i += calc_sardine_groups(sardine_groups, mod)
unless sardine_group_with_zero_basis_vector.nil?
  i += sardine_group_with_zero_basis_vector.size.to_i64 % mod
end

puts i % mod
