//package abc168

import java.io.*
import java.math.*
import java.util.*
import kotlin.math.*

var reader: BufferedReader = System.`in`.bufferedReader()
var writer: PrintWriter = PrintWriter(System.`out`)

fun next() = reader.readLine()!!
fun nextInt() = next().toInt()
fun nextLong() = next().toLong()
fun nextDouble() = next().toDouble()
fun nextStrings() = next().split(" ")
fun nextInts() = nextStrings().map { it.toInt() }
fun nextLongs() = nextStrings().map { it.toLong() }
fun nextDoubles() = nextStrings().map { it.toDouble() }

fun put(v: Any?) = writer.print(v)
fun puts() = writer.println()
fun puts(v: Any?) = writer.println(v)

var debug = false
fun dprintln(v: Any?) {
    if (debug) println(v)
}
fun dprintln() {
    if (debug) println()
}

class ModInt(
    val value: Long
) {
    private val POW = mutableMapOf<Int, ModInt>()

    constructor (value: Int): this(value.toLong())

    operator fun plus(rhs: ModInt): ModInt {
        return ModInt((value + rhs.value) % M)
    }
    operator fun minus(rhs: ModInt): ModInt {
        return ModInt((value - rhs.value + M) % M)
    }
    operator fun times(rhs: ModInt): ModInt {
        return ModInt((value * rhs.value) % M)
    }
    operator fun div(rhs: ModInt): ModInt {
        return ModInt(value * inv(rhs.value) % M)
    }
    private fun inv(v: Long): Long {
        return INV.computeIfAbsent(v) {
            M - (((M / v) * inv(M % v)) % M)
        }
    }
    fun pow(v: Int): ModInt {
        return POW.computeIfAbsent(v) {
            var result = 1L
            var x = v
            var vv = value
            while (x != 0) {
                if ((x and 1) != 0) {
                    result = (result * vv) % M
                }
                vv = (vv * vv) % M
                x = x ushr 1
            }
            ModInt(result)
        }
    }

    override fun toString(): String {
        return value.toString()
    }

    companion object {
        private const val M = 1000000007L

        private val INV = mutableMapOf<Long, Long>().also {
            it[1] = 1
        }

        val ZERO = ModInt(0)
        val ONE = ModInt(1)
    }
}

fun test(case: Int, input: String, expected: String) {
    reader = input.trimIndent().reader().buffered()

    val stringWriter = StringWriter()
    writer = PrintWriter(stringWriter)

    solve()
    writer.flush()

    val actual = stringWriter.toString()

    println("[test $case]")
    if ("${expected}" == actual) {
        println("OK")
    } else {
        println("NG")
        println()
        println("expected: \"${expected}\"")
        println("actual:   \"${actual}\"")
    }
    println()
}

fun main(args: Array<String>) {
    if ((args.size == 1) && (args[0] == "test")) {
        testAll()
    } else {
        solve()
        writer.flush()
    }
}

///////////////////////////////////////////////////////////

fun testAll() {
    debug = true

    test(1,
        """
        3
        1 2
        -1 1
        2 -1
        """,
        "5"
    )
    test(2,
        """
        10
        3 2
        3 2
        -1 1
        2 -1
        -3 -9
        -8 12
        7 7
        8 1
        8 2
        8 4
        """,
        "479"
        )
        test(3,
        """
        4
        0 3
        0 -3
        1 0
        -1 0
        """,
        "6"
        )
}


val TWO = ModInt(2)

tailrec fun gcd(a: Long, b: Long): Long {
    if(b == 0L) return a
    return gcd(b, a % b)
}

fun solve() {

    val TWO = ModInt(2)
    val N = nextInt()
    val fishes = mutableMapOf<Pair<Long, Long>, Int>()
    var numZero = 0

    repeat(N) {
        var (a, b) = nextLongs()

        if ((a == 0L) && (b == 0L)) {
            ++numZero
        } else if (a == 0L) {
            fishes.merge(Pair(0L, 1L), 1) { x, y -> x + y }
        } else if (b == 0L) {
            fishes.merge(Pair(-1L, 0L), 1) { x, y -> x + y }
        } else {
            val g = gcd(a, b)
            a /= g
            b /= g

            fishes.merge(Pair(a, b), 1) { x, y -> x + y }
        }
    }
    dprintln(fishes)

    val result = fishes.entries.fold(ModInt(1)) { acc, (fish, c) ->

        if (fishes.containsKey(Pair(fish.second, -fish.first))) {
            return@fold acc
        }

        val oc = fishes.getOrDefault(Pair(-fish.second, fish.first), 0)

        acc * (TWO.pow(c) + TWO.pow(oc) - ModInt.ONE)
    }
    dprintln(result)

    put(result + ModInt(numZero) - ModInt.ONE)
}


Measured memory_bytes: 85728