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

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

# WA: sub1_11, sub1_13, sub1_16

require "big"

class Sardine
  def initialize(@taste : Int64, @fragrance : Int64)
  end

  getter :taste, :fragrance

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

  def zero_vector?
    to_a.all?(&.zero?)
  end

  def vertical?
    to_a.first.zero?
  end

  def horizontal?
    to_a.last.zero?
  end

  def to_rational : BigRational | Symbol
    return :zero_vector if zero_vector?
    return :vertical if vertical?
    return :horizontal if horizontal?

    BigRational.new(fragrance, -taste)
  end
end

class Power
  def initialize(@base : Int64, @mod : Int64)
    @array = [1_i64]
  end

  getter :base, :mod
  getter array : Array(Int64)

  def get(n : Int64)
    last_index = array.size - 1

    if n > last_index
      (n - (array.size - 1)).times do
        array.push(array.last * base % mod)
      end
    end

    array[n]
  end
end

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

# filename = read_line
# file = File.new("contests/abc168/e/in/#{filename}.txt")
# content = file.gets_to_end.chomp.split(/\n/)
# file.close

# n = content.shift.to_i64
# sardines = content.map { |row| a, b = row.split.map(&.to_i64); Sardine.new(a, b) }

sardines_with_zero_vector, sardines_with_nonzero_vector = sardines.partition(&.zero_vector?)

# puts "sardines_with_zero_vector: #{sardines_with_zero_vector.inspect}"
# puts "sardines_with_nonzero_vector: #{sardines_with_nonzero_vector.inspect}"

sardine_groups = Hash((Symbol | BigRational), Array(Array(Sardine))).new { [[] of Sardine, [] of Sardine] }
sardines_with_nonzero_vector.each do |sardine|
  r = sardine.to_rational
  # puts "r: #{r}"
  case r
  when :horizontal
    sardine_groups[:on_coordinate][0].push(sardine)
  when :vertical
    sardine_groups[:on_coordinate][1].push(sardine)
  else
    rational = r.as(BigRational)
    # puts "rational: #{rational}"
    if rational > 0
      sardine_group = [
        sardine_groups[rational][0].push(sardine),
        sardine_groups[rational][1]
      ]
      sardine_groups[rational] = sardine_group
    else
      sardine_group = [
        sardine_groups[- (rational ** -1)][0],
        sardine_groups[- (rational ** -1)][1].push(sardine)
      ]
      sardine_groups[- (rational ** -1)] = sardine_group
    end
  end
end

# puts "sardine_groups: #{sardine_groups.inspect}"

mod = 1000000007_i64

def calc_sardine_groups(sardine_group : Array(Array(Sardine)), power_instance : Power, mod : Int64)
  group_plus, group_minus = sardine_group
  j = power_instance.get(group_plus.size.to_i64)
  k = power_instance.get(group_minus.size.to_i64)
  (j + k - 1_i64) % mod
end

i = 0_i64
unless sardine_groups.empty?
  j = 1_i64
  power_instance = Power.new(2_i64, mod)
  sardine_groups.each do |key, sardine_group|
    # puts "j: #{j}"
    j *= calc_sardine_groups(sardine_group, power_instance, mod) % mod
    j %= mod
  end
  # puts "j: #{j}"
  i += (j - 1_i64) % mod
end

unless sardines_with_zero_vector.empty?
  i += sardines_with_zero_vector.size % mod
end

puts i % mod
