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>()

    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"
        )
}

class Fish(
    val a: BigInteger,
    val b: BigInteger
) {
    val cos: Double
    var visited = false

    init {
        val aDouble = a.toDouble()
        val bDouble = b.toDouble()
        val c = (aDouble * aDouble) / (aDouble * aDouble + bDouble * bDouble)
        cos = if (aDouble > 0.0) {
            c
        } else {
            -c
        }
    }

    constructor(a: Long, b: Long): this(BigInteger.valueOf(a), BigInteger.valueOf(b))

    fun opposite(rhs: Fish): BigInteger {
        return ((a * rhs.a) + (b * rhs.b))
    }
    fun sameGroup(rhs: Fish): BigInteger {
        return (a * rhs.b) - (b * rhs.a)
    }

    override fun toString(): String {
        return "($a, $b, $cos)"
    }
}

// 0以上の最初の要素 (入力は降順)
fun bsearch_upper(list: List<Fish>): Int {
    var l = 0
    var u = list.size

    while (l < u) {
        val m = (l + u) / 2
        val mValue = list[m]

        if (mValue.cos <= -0.000001) {
            u = m
        } else {
            l = m + 1
        }
    }

    return u
}

// 0以下の最初の要素 (入力は昇順)
fun bsearch_lower(list: List<Fish>): Int {
    var l = 0
    var u = list.size

    while (l < u) {
        val m = (l + u) / 2
        val mValue = list[m]

        if (mValue.cos >= -0.000001) {
            u = m
        } else {
            l = m + 1
        }
    }

    return u
}

val TWO = ModInt(2)

fun calculate(list: List<Fish>, subList: List<Fish>, listOppositeStart: Int, sublistOppositeStart: Int): ModInt {

    var result = ModInt.ONE

    var index = 0
    var subListIndex = 0
    var listOppsiteIndex = listOppositeStart
    var subListOppsiteIndex = sublistOppositeStart

    while (index < list.size) {
        val base = list[index]
        dprintln("check: [$index] $base")
        ++index

        if (base.visited) {
            dprintln("skip(0)")
            continue;
        }
        base.visited = true

        var numSameGroup = 1
        var numOpposite = 0

        while (index < list.size) {
            val rhs = list[index]
            dprintln("sg: [$index] $rhs")

            if (rhs.visited) {
                dprintln("skip(1-0)")
                break
            }

            val s = base.sameGroup(rhs)
            dprintln("-> $s")
            if (s > BigInteger.ZERO) {
                break
            }
            if (s == BigInteger.ZERO) {
                dprintln("sameG")
                rhs.visited = true
                ++numSameGroup
            }
            ++index
        }
        while (listOppsiteIndex < list.size) {
            val rhs = list[listOppsiteIndex]
            dprintln("op: [$listOppsiteIndex] $rhs")

            if (rhs.visited) {
                dprintln("skip(1)")
                ++listOppsiteIndex
                continue
            }

            val o = base.opposite(rhs)
            dprintln("-> $o")

            if (o < BigInteger.ZERO) {
                break;
            }
            if (o == BigInteger.ZERO) {
                dprintln("opposite")
                rhs.visited = true
                ++numOpposite
            }
            ++listOppsiteIndex
        }

        while (subListIndex < subList.size) {
            val rhs = subList[subListIndex]
            dprintln("sg2: [$subListIndex] $rhs")

            if (rhs.visited) {
                dprintln("skip(2)")
                ++subListIndex
                continue
            }

            val s = base.sameGroup(rhs)
            dprintln("-> $s")
            if (s < BigInteger.ZERO) {
                break
            }
            if (s == BigInteger.ZERO) {
                dprintln("sameG")
                rhs.visited = true
                ++numSameGroup
            }
            ++subListIndex
        }

        while (subListOppsiteIndex < subList.size) {
            val rhs = subList[subListOppsiteIndex]
            dprintln("op2: [$subListOppsiteIndex] $rhs")

            if (rhs.visited) {
                dprintln("skip(3)")
                ++subListOppsiteIndex
                continue
            }

            val o = base.opposite(rhs)
            dprintln("-> $o")

            if (o > BigInteger.ZERO) {
                break;
            }
            if (o == BigInteger.ZERO) {
                dprintln("opposite")
                rhs.visited = true
                ++numOpposite
            }
            ++subListOppsiteIndex
        }

        dprintln("(2^${numOpposite} - 1) + (2^${numSameGroup} - 1) + 1 = ${(TWO.pow(numOpposite) - ModInt.ONE) + (TWO.pow(numSameGroup) - ModInt.ONE) + ModInt.ONE}")
        dprintln()
        result *= (TWO.pow(numOpposite) - ModInt.ONE) +
            (TWO.pow(numSameGroup) - ModInt.ONE) + ModInt.ONE
    }

    return result
}

fun solve() {

    val N = nextInt()
    var upper = mutableListOf<Fish>()
    val lower = mutableListOf<Fish>()

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

        if ((b > 0L) || ((b == 0L) && (a >= 0L))) {
            upper.add(Fish(a, b))
        } else {
            lower.add(Fish(a, b))
        }
    }

    upper.sortBy { -it.cos }
    lower.sortBy { it.cos }

    val upperOppositeIndexStart = bsearch_upper(upper)
    val lowerOppositeIndexStart = bsearch_lower(lower)

    dprintln(upper)
    dprintln(upperOppositeIndexStart)
    dprintln(lower)
    dprintln(lowerOppositeIndexStart)
    dprintln()

    var result = ModInt.ONE

    result *= calculate(upper, lower, upperOppositeIndexStart, lowerOppositeIndexStart)
    result *= calculate(lower, upper, lowerOppositeIndexStart, upperOppositeIndexStart)

    put(result - ModInt.ONE)
}
