import java.util.*

class Scanner(`in`: java.io.InputStream) {
    private val reader = java.io.BufferedReader(java.io.InputStreamReader(`in`))
    private var tokenizer: StringTokenizer? = null

    fun next(): String {
        if (tokenizer?.hasMoreTokens() != true) {
            tokenizer = StringTokenizer(reader.readLine())
        }
        return tokenizer!!.nextToken()
    }

    fun nextInt() = next().toInt()

    fun nextLong() = next().toLong()

    fun nextLine(): String {
        return if (tokenizer?.hasMoreTokens() != true) {
            reader.readLine()
        } else tokenizer!!.nextToken("\n")
    }
}

fun main(args: Array<String>) {
    val pw = java.io.PrintWriter(System.out)
    Problem.solve(Scanner(System.`in`), pw)
    pw.flush()
}

fun gcd(a: Long, b: Long): Long = if (b == 0L) a else gcd(b, a % b)

data class P(val a: Long, val b: Long)

data class ModInt(var value: Long) {
    init {
        assert(value in 0 until MOD)
    }

    override fun toString(): String = value.toString()

    // 加減乗算は結果を毎回 mod P すれば良い
    operator fun plus(b: Long): ModInt =
        ModInt((this.value + b) % MOD)

    operator fun plus(b: Int): ModInt =
        ModInt((this.value + b) % MOD)

    operator fun plus(b: ModInt): ModInt =
        ModInt((this.value + b.value) % MOD)

    operator fun plusAssign(b: Long) {
        this.value += b
        this.value %= MOD
    }

    operator fun plusAssign(b: Int) {
        this.value += b
        this.value %= MOD
    }

    operator fun plusAssign(b: ModInt) {
        this.value += b.value
        this.value %= MOD
    }

    operator fun minus(b: Long): ModInt =
        ModInt((this.value + MOD - b) % MOD)

    operator fun minus(b: Int): ModInt =
        ModInt((this.value + MOD - b) % MOD)

    operator fun minus(b: ModInt): ModInt =
        ModInt((this.value + (MOD - b.value)) % MOD)

    operator fun minusAssign(b: Long) {
        this.value += MOD - b
        this.value %= MOD
    }

    operator fun minusAssign(b: Int) {
        this.value += MOD - b
        this.value %= MOD
    }

    operator fun minusAssign(b: ModInt) {
        this.value += MOD - b.value
        this.value %= MOD
    }

    operator fun times(b: Long): ModInt =
        ModInt((this.value * b) % MOD)

    operator fun times(b: Int): ModInt =
        ModInt((this.value * b) % MOD)

    operator fun times(b: ModInt): ModInt =
        ModInt((this.value * b.value) % MOD)

    operator fun timesAssign(b: Long) {
        this.value *= b
        this.value %= MOD
    }

    operator fun timesAssign(b: Int) {
        this.value *= b
        this.value %= MOD
    }

    operator fun timesAssign(b: ModInt) {
        this.value *= b.value
        this.value %= MOD
    }

    // b で割る = 1/b を掛ける
    // フェルマーの小定理から、b の逆数 1/b (mod P) = b^(P-2)
    operator fun div(b: Long): ModInt =
        this * ModInt(b).pow(MOD - 2)

    operator fun div(b: Int): ModInt =
        this * ModInt(b.toLong()).pow(MOD - 2)

    operator fun div(b: ModInt): ModInt =
        this * b.pow(MOD - 2)

    operator fun divAssign(b: Long) {
        this *= ModInt(b).pow(MOD - 2)
    }

    operator fun divAssign(b: Int) {
        this *= ModInt(b.toLong()).pow(MOD - 2)
    }

    operator fun divAssign(b: ModInt) {
        this *= b.pow(MOD - 2)
    }

    fun inv() = pow(MOD - 2)

    // 累乗 (mod P)
    // 計算量は O(log p)
    fun pow(p: Long): ModInt = when {
        p == 0L -> ModInt(1)
        p % 2 == 1L -> this * this.pow(p - 1)
        else -> {
            val half = this.pow(p / 2)
            half * half
        }
    }

    companion object {
        const val MOD = 1000000007L
    }
}

object Problem {
    fun toP(a0: Long, b0: Long): Pair<P, Boolean> {
        var a = a0
        var b = b0
        when {
            b == 0L -> a = 1 // (x, 0) => (1, 0)
            a == 0L -> b = 1 // (0, x) => (0, 1)
            b < 0 -> { // b は必ず正にそろえる
                a = -a; b = -b
            }
        }
        val rot = a <= 0
        if (rot) {
            val tmp = -a
            a = b
            b = tmp
        }
        val g = Math.abs(gcd(a, b))
        return Pair(P(a / g, b / g), rot)
    }

    fun solve(sc: Scanner, pw: java.io.PrintWriter) {
        val N = sc.next().toInt()
        var z = 0L
        val count = mutableMapOf<P, Pair<Long, Long>>()
        repeat(N) {
            val a = sc.next().toLong()
            val b = sc.next().toLong()
            if (a == 0L && b == 0L) {
                // (0,0) だけ特別
                z++
            } else {
                val (p, rot) = toP(a, b)
                if (!count.containsKey(p)) count[p] = Pair(0L, 0L)
                var (c1, c2) = count[p]!!
                if (!rot) c1++ else c2++
                count[p] = Pair(c1, c2)
            }
        }
//        dprint(count)
        val ans = ModInt(1L)
        count.forEach { c ->
            val n = ((ModInt(2L).pow(c.value.first)) - 1) +
                    ((ModInt(2L).pow(c.value.second)) - 1) + 1
            ans *= n
        }
        ans += z
        ans -= 1
        pw.println(ans)
    }
}


Measured memory_bytes: 81388