jiahuimbzuai/CoQuIR huggingface dataset:
//  [javascript]
"use strict";
var input=require("fs").readFileSync("/dev/stdin","utf8");
var cin=input.split(/ |\n/),cid=0;
function next(){return +cin[cid++];}
function nextstr(){return cin[cid++];}
function nextbig(){return BigInt(cin[cid++]);}
function nexts(n,a){return a?cin.slice(cid,cid+=n):cin.slice(cid,cid+=n).map(a=>+a);}
function nextm(h,w,a){var r=[],i=0;if(a)for(;i<h;i++)r.push(cin.slice(cid,cid+=w));else for(;i<h;i++)r.push(cin.slice(cid,cid+=w).map(a=>+a));return r;}
function xArray(v){var a=arguments,l=a.length,r="Array(a["+--l+"]).fill().map(x=>{return "+v+";})";while(--l)r="Array(a["+l+"]).fill().map(x=>"+r+")";return eval(r);}

function gcd(a,b){return b?gcd(b,a%b):a;}

var mod = 1e9+7;
function mul(a,b){return ((a>>16)*b%mod*65536+(a&65535)*b)%mod;}
function pow(a,n){for(var r=1;n;a=mul(a,a),n>>=1)if(n&1)r=mul(a,r);return r;}
function mput(n){return (n%mod+mod)%mod;}

var myOut = main();
if(myOut !== undefined)console.log(myOut);

function main(){
  var n = next();
  var az = 0, bz = 0, z = 0;
  var map = new Map();
  for(var i = 0; i < n; i++){
    var a = nextbig(), b = nextbig();
    if(a === 0n && b === 0n){z++; continue;}
    if(a === 0n){az++; continue;}
    if(b === 0n){bz++; continue;}
    var c = gcd(a,b);
    a /= c, b /= c;
    if(a < 0)a = -a, b = -b;
    if(map.has(a)){
      if(map.get(a).has(b))map.get(a).set(b,map.get(a).get(b)+1);
      else map.get(a).set(b,1);
    }else{
      map.set(a,new Map());
      map.get(a).set(b,1);
    }
  }
  var ans = pow(2,az) + pow(2,bz) - 1;
  for(var i of map){
    for(var j of i[1]){
      var t = 0;
      if(j[0] < 0){
        if(map.has(-j[0]) && map.get(-j[0]).has(i[0]))continue;
      }else{
        if(map.has(j[0]) && map.get(j[0]).has(-i[0]))t = pow(2,map.get(j[0]).get(-i[0]))-1;
      }
      t += pow(2,map.get(i[0]).get(j[0]));
      ans = mul(ans,t);
    }
  }
  return mput(ans-1+z);
}
//  [javascript]
"use strict";
var input=require("fs").readFileSync("/dev/stdin","utf8");
var cin=input.split(/ |\n/),cid=0;
function next(){return +cin[cid++];}
function nextstr(){return cin[cid++];}
function nextbig(){return BigInt(cin[cid++]);}
function nexts(n,a){return a?cin.slice(cid,cid+=n):cin.slice(cid,cid+=n).map(a=>+a);}
function nextm(h,w,a){var r=[],i=0;if(a)for(;i<h;i++)r.push(cin.slice(cid,cid+=w));else for(;i<h;i++)r.push(cin.slice(cid,cid+=w).map(a=>+a));return r;}
function xArray(v){var a=arguments,l=a.length,r="Array(a["+--l+"]).fill().map(x=>{return "+v+";})";while(--l)r="Array(a["+l+"]).fill().map(x=>"+r+")";return eval(r);}

function gcd(a,b){return b?gcd(b,a%b):a;}

var mod = 1e9+7;
function mul(a,b){return ((a>>16)*b%mod*65536+(a&65535)*b)%mod;}
function pow(a,n){for(var r=1;n;a=mul(a,a),n>>=1)if(n&1)r=mul(a,r);return r;}
function mput(n){return (n%mod+mod)%mod;}

var myOut = main();
if(myOut !== undefined)console.log(myOut);

function main(){
  var n = next();
  var az = 0, bz = 0, z = 0;
  var map = {};
  for(var i = 0; i < n; i++){
    var a = nextbig(), b = nextbig();
    if(a === 0n && b === 0n){z++; continue;}
    if(a === 0n){az++; continue;}
    if(b === 0n){bz++; continue;}
    var c = gcd(a,b);
    a /= c, b /= c;
    if(a < 0)a = -a, b = -b;
    if(map[a]){
      if(map[a][b])map[a][b]++;
      else map[a][b] = 1;
    }else{
      map[a] = {};
      map[a][b] = 1;
    }
  }
  var ans = pow(2,az) + pow(2,bz) - 1;
  for(var i in map){
    for(var j in map[i]){
      var t = 0;
      if(j < 0){
        if(map[j.slice(1)] && map[j.slice(1)][i])continue;
      }else{
        if(map[j] && map[j]["-"+i])t = pow(2,map[j]["-"+i])-1;
      }
      t += pow(2,map[i][j]);
      ans = mul(ans,t);
    }
  }
  return mput(ans-1+z);
}
//  [javascript]
"use strict";
var input=require("fs").readFileSync("/dev/stdin","utf8");
var cin=input.split(/ |\n/),cid=0;
function next(){return +cin[cid++];}
function nextstr(){return cin[cid++];}
function nextbig(){return BigInt(cin[cid++]);}
function nexts(n,a){return a?cin.slice(cid,cid+=n):cin.slice(cid,cid+=n).map(a=>+a);}
function nextm(h,w,a){var r=[],i=0;if(a)for(;i<h;i++)r.push(cin.slice(cid,cid+=w));else for(;i<h;i++)r.push(cin.slice(cid,cid+=w).map(a=>+a));return r;}
function xArray(v){var a=arguments,l=a.length,r="Array(a["+--l+"]).fill().map(x=>{return "+v+";})";while(--l)r="Array(a["+l+"]).fill().map(x=>"+r+")";return eval(r);}

function gcd(a,b){return b?gcd(b,a%b):a;}

var mod = 1e9+7;
function mul(a,b){return ((a>>16)*b%mod*65536+(a&65535)*b)%mod;}
function pow(a,n){for(var r=1;n;a=mul(a,a),n>>=1)if(n&1)r=mul(a,r);return r;}
function mput(n){return (n%mod+mod)%mod;}

var myOut = main();
if(myOut !== undefined)console.log(myOut);

function main(){
  const n = next();
  let az = 0, bz = 0, z = 0;
  const map = {};
  for(let i = 0; i < n; i++){
    let a = nextbig(), b = nextbig();
    if(a === 0n && b === 0n){z++; continue;}
    if(a === 0n){az++; continue;}
    if(b === 0n){bz++; continue;}
    const c = gcd(a,b);
    a /= c, b /= c;
    if(a < 0)a = -a, b = -b;
    if(map[a]){
      if(map[a][b])map[a][b]++;
      else map[a][b] = 1;
    }else{
      map[a] = {};
      map[a][b] = 1;
    }
  }
  let ans = pow(2,az) + pow(2,bz) - 1;
  for(let i in map){
    for(let j in map[i]){
      let t = 0;
      if(j < 0){
        if(map[j.slice(1)] && map[j.slice(1)][i])continue;
      }else{
        if(map[j] && map[j]["-"+i])t = pow(2,map[j]["-"+i])-1;
      }
      t += pow(2,map[i][j]);
      ans = mul(ans,t);
    }
  }
  return mput(ans-1+z);
}
//  [javascript]
"use strict";
var input=require("fs").readFileSync("/dev/stdin","utf8");
var cin=input.split(/ |\n/),cid=0;
function next(){return +cin[cid++];}
function nextstr(){return cin[cid++];}
function nextbig(){return BigInt(cin[cid++]);}
function nexts(n,a){return a?cin.slice(cid,cid+=n):cin.slice(cid,cid+=n).map(a=>+a);}
function nextm(h,w,a){var r=[],i=0;if(a)for(;i<h;i++)r.push(cin.slice(cid,cid+=w));else for(;i<h;i++)r.push(cin.slice(cid,cid+=w).map(a=>+a));return r;}
function xArray(v){var a=arguments,l=a.length,r="Array(a["+--l+"]).fill().map(x=>{return "+v+";})";while(--l)r="Array(a["+l+"]).fill().map(x=>"+r+")";return eval(r);}

function gcd(a,b){return b?gcd(b,a%b):a;}

var mod = 1e9+7;
function mul(a,b){return ((a>>16)*b%mod*65536+(a&65535)*b)%mod;}
function pow(a,n){for(var r=1;n;a=mul(a,a),n>>=1)if(n&1)r=mul(a,r);return r;}
function mput(n){return (n%mod+mod)%mod;}

var myOut = main();
if(myOut !== undefined)console.log(myOut);

function main(){
  var n = next();
  var az = 0, bz = 0, z = 0;
  var map = {};
  for(var i = 0; i < n; i++){
    var a = nextbig(), b = nextbig();
    if(a === 0n && b === 0n){z++; continue;}
    if(a === 0n){az++; continue;}
    if(b === 0n){bz++; continue;}
    var c = gcd(a,b);
    a /= c, b /= c;
    if(a < 0)a = -a, b = -b;
    if(map[a]){
      if(map[a][b]){
        map[a][b] *= 2;
        if(map[a][b] >= mod)map[a][b] -= mod;
      }
      else map[a][b] = 2;
    }else{
      map[a] = {};
      map[a][b] = 2;
    }
  }
  var ans = pow(2,az) + pow(2,bz) - 1;
  for(var i in map){
    for(var j in map[i]){
      var t = 0;
      if(j < 0){
        if(map[j.slice(1)] && map[j.slice(1)][i])continue;
      }else{
        if(map[j] && map[j]["-"+i])t = map[j]["-"+i]-1;
      }
      t += map[i][j];
      ans = mul(ans,t);
    }
  }
  return mput(ans-1+z);
}
//  [javascript]
"use strict";
var input=require("fs").readFileSync("/dev/stdin","utf8");
var cin=input.split(/ |\n/),cid=0;
function next(){return +cin[cid++];}
function nextstr(){return cin[cid++];}
function nextbig(){return BigInt(cin[cid++]);}
function nexts(n,a){return a?cin.slice(cid,cid+=n):cin.slice(cid,cid+=n).map(a=>+a);}
function nextm(h,w,a){var r=[],i=0;if(a)for(;i<h;i++)r.push(cin.slice(cid,cid+=w));else for(;i<h;i++)r.push(cin.slice(cid,cid+=w).map(a=>+a));return r;}
function xArray(v){var a=arguments,l=a.length,r="Array(a["+--l+"]).fill().map(x=>{return "+v+";})";while(--l)r="Array(a["+l+"]).fill().map(x=>"+r+")";return eval(r);}

function gcd(a,b){return b?gcd(b,a%b):a;}

var mod = 1e9+7;
function mul(){for(var a=arguments,r=a[0],i=a.length;--i;)r=((r>>16)*a[i]%mod*65536+(r&65535)*a[i])%mod;return r;}
function pow(a,n){for(var r=1;n;a=mul(a,a),n>>=1)if(n&1)r=mul(a,r);return r;}
function mput(n){return (n%mod+mod)%mod;}

var myOut = main();
if(myOut !== undefined)console.log(myOut);

function main(){
  var n = next();
  var az = 0, bz = 0, z = 0;
  var map = {};
  for(var i = 0; i < n; i++){
    var a = nextbig(), b = nextbig();
    if(a === 0n && b === 0n){z++; continue;}
    if(a === 0n){az++; continue;}
    if(b === 0n){bz++; continue;}
    var c = gcd(a,b);
    a /= c, b /= c;
    if(a < 0)a = -a, b = -b;
    if(b < 0){
      var t = -b;
      b = -a, a = t;
    }
    if(map[a]){
      if(map[a][b])map[a][b]++;
      else map[a][b] = 1;
    }else{
      map[a] = {};
      map[a][b] = 1;
    }
  }
  var ans = pow(2,az) + pow(2,bz) - 1;
  for(var i in map){
    for(var j in map[i]){
      var t = 0;
      if(j < 0){
        if(map[i][j.slice(1)])continue;
      }else{
        if(map[i]["-"+j])t = pow(2,map[i]["-"+j])-1;
      }
      t += pow(2,map[i][j]);
      ans = mul(ans,t);
    }
  }
  ans += z-1;
  return ans >= mod ? ans-mod : ans;
}
//  [go]
package main

import (
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func run(_r io.Reader, _w io.Writer) {
	buf := make([]byte, 4096)
	_i := len(buf)
	rc := func() byte {
		if _i == len(buf) {
			_r.Read(buf)
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		neg := false
		for ; '0' > b || b > '9'; b = rc() {
			if b == '-' {
				neg = true
			}
		}
		for ; '0' <= b && b <= '9'; b = rc() {
			x = x*10 + int(b&15)
		}
		if neg {
			return -x
		}
		return
	}
	abs := func(x int) int {
		if x < 0 {
			return -x
		}
		return x
	}
	gcd := func(a, b int) int {
		for a != 0 {
			a, b = b%a, a
		}
		return b
	}
	const mod int = 1e9 + 7
	pow := func(n int) int {
		res, x := 1, 2
		for ; n > 0; n >>= 1 {
			if n&1 == 1 {
				res = res * x % mod
			}
			x = x * x % mod
		}
		return res
	}

	type pair struct{ x, y int }
	cntO := 0
	cnt := map[pair]int{}
	cnt2 := map[pair]int{}
	n := r()
	for i := 0; i < n; i++ {
		x, y := r(), r()
		if x == 0 && y == 0 {
			cntO++
			continue
		}
		if y < 0 {
			x = -x
			y = -y
		} else if y == 0 {
			x = abs(x)
		}
		g := gcd(abs(x), y)
		x /= g
		y /= g
		if x > 0 {
			cnt[pair{x, y}]++
		} else {
			cnt2[pair{y, -x}]++
		}
	}

	ans := 1
	for p, c := range cnt {
		ans = ans * (pow(c) + pow(cnt2[p]) - 1) % mod
		delete(cnt2, p)
	}
	for _, c := range cnt2 {
		ans = ans * (pow(c)) % mod
	}
	Fprint(_w, (ans+cntO-1+mod)%mod)
}

func main() { run(os.Stdin, os.Stdout) }
//  [go]
package main

import (
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func run(_r io.Reader, _w io.Writer) {
	buf := make([]byte, 4096)
	_i := len(buf)
	rc := func() byte {
		if _i == len(buf) {
			_r.Read(buf)
			_i = 0
		}
		b := buf[_i]
		_i++
		return b
	}
	r := func() (x int) {
		b := rc()
		neg := false
		for ; '0' > b; b = rc() {
			if b == '-' {
				neg = true
			}
		}
		for ; '0' <= b; b = rc() {
			x = x*10 + int(b&15)
		}
		if neg {
			return -x
		}
		return
	}
	abs := func(x int) int {
		if x < 0 {
			return -x
		}
		return x
	}
	gcd := func(a, b int) int {
		for a != 0 {
			a, b = b%a, a
		}
		return b
	}
	const mod int = 1e9 + 7
	pow := func(n int) int {
		res, x := 1, 2
		for ; n > 0; n >>= 1 {
			if n&1 == 1 {
				res = res * x % mod
			}
			x = x * x % mod
		}
		return res
	}

	type pair struct{ x, y int }
	cntO := 0
	cnt := map[pair]int{}
	cnt2 := map[pair]int{}
	n := r()
	for i := 0; i < n; i++ {
		x, y := r(), r()
		if x == 0 && y == 0 {
			cntO++
			continue
		}
		if y < 0 {
			x = -x
			y = -y
		} else if y == 0 {
			x = abs(x)
		}
		g := gcd(abs(x), y)
		x /= g
		y /= g
		if x > 0 {
			cnt[pair{x, y}]++
		} else {
			cnt2[pair{y, -x}]++
		}
	}

	ans := 1
	for p, c := range cnt {
		ans = ans * (pow(c) + pow(cnt2[p]) - 1) % mod
		delete(cnt2, p)
	}
	for _, c := range cnt2 {
		ans = ans * (pow(c)) % mod
	}
	Fprint(_w, (ans+cntO-1+mod)%mod)
}

func main() { run(os.Stdin, os.Stdout) }
//  [go]
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
)

func out(x ...interface{}) {
	fmt.Println(x...)
}

var sc = bufio.NewScanner(os.Stdin)

func getInt() int {
	sc.Scan()
	i, e := strconv.Atoi(sc.Text())
	if e != nil {
		panic(e)
	}
	return i
}

func getString() string {
	sc.Scan()
	return sc.Text()
}

// min, max, asub, absなど基本関数
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func asub(a, b int) int {
	if a > b {
		return a - b
	}
	return b - a
}

func abs(a int) int {
	if a >= 0 {
		return a
	}
	return -a
}

func lowerBound(a []int, x int) int {
	idx := sort.Search(len(a), func(i int) bool {
		return a[i] >= x
	})
	return idx
}

func upperBound(a []int, x int) int {
	idx := sort.Search(len(a), func(i int) bool {
		return a[i] > x
	})
	return idx
}

const mod = 1000000007

func mpow(a, b int) int {
	if b == 0 {
		return 1
	} else if b%2 == 0 {
		tmp := mpow(a, b/2)
		return tmp * tmp % mod
	}
	return mpow(a, b-1) * a % mod
}

var fracMemo = []int{1, 1}

func mfrac(n int) int {
	if len(fracMemo) > n {
		return fracMemo[n]
	}
	if len(fracMemo) == 0 {
		fracMemo = append(fracMemo, 1)
	}
	for len(fracMemo) <= n {
		size := len(fracMemo)
		fracMemo = append(fracMemo, fracMemo[size-1]*size%mod)
	}
	return fracMemo[n]
}

var ifracMemo = []int{1, 1}

func mifrac(n int) int {
	if len(ifracMemo) > n {
		return ifracMemo[n]
	}
	if len(ifracMemo) == 0 {
		fracMemo = append(ifracMemo, 1)
	}
	for len(ifracMemo) <= n {
		size := len(ifracMemo)
		ifracMemo = append(ifracMemo, ifracMemo[size-1]*mpow(size, mod-2)%mod)
	}
	return ifracMemo[n]
}

func nCr(n, r int) int {
	if n == r {
		return 1
	}
	if n < r || r < 0 {
		return 0
	}
	ret := 1
	ret *= mfrac(n)
	ret %= mod
	ret *= mifrac(r)
	ret %= mod
	ret *= mifrac(n - r)
	ret %= mod
	return (ret)
}

func gcd(a, b int) int {
	for b != 0 {
		a, b = b, a%b
	}
	return a
}

type pair struct {
	f, s int
}

func main() {
	sc.Split(bufio.ScanWords)
	N := getInt()
	a := make([]int, N)
	b := make([]int, N)
	for i := 0; i < N; i++ {
		a[i], b[i] = getInt(), getInt()
	}

	zero := 0
	m := make(map[pair]pair)
	for i := 0; i < N; i++ {
		if a[i] == 0 && b[i] == 0 {
			zero++
			continue
		}
		g := gcd(abs(a[i]), abs(b[i]))
		a[i] /= g
		b[i] /= g
		if a[i] == 0 {
			x := m[pair{0, 1}]
			x.f++
			m[pair{0, 1}] = x
		} else if b[i] == 0 {
			x := m[pair{0, 1}]
			x.s++
			m[pair{0, 1}] = x
		} else if a[i] > 0 && b[i] > 0 {
			x := m[pair{a[i], b[i]}]
			x.f++
			m[pair{a[i], b[i]}] = x
		} else if a[i] < 0 && b[i] < 0 {
			a[i] = -a[i]
			b[i] = -b[i]
			x := m[pair{a[i], b[i]}]
			x.f++
			m[pair{a[i], b[i]}] = x
		} else if a[i] < 0 {
			a[i] = -a[i]
			b[i] = -b[i]
			x := m[pair{-b[i], a[i]}]
			x.s++
			m[pair{-b[i], a[i]}] = x
		} else {
			x := m[pair{-b[i], a[i]}]
			x.s++
			m[pair{-b[i], a[i]}] = x
		}
	}

	// out(zero)
	// out(m)
	// for i, v := range m {
	// 	out(i, v)
	// }
	ans := 1
	for _, v := range m {
		x := mpow(2, v.f)
		x += mpow(2, v.s)
		x %= mod
		x--
		if x < 0 {
			x += mod
		}
		x %= mod
		// out(x)
		ans *= x
		ans %= mod
	}
	ans += zero - 1
	if ans < 0 {
		ans += mod
	}
	ans %= mod
	out(ans)
}
//  [go]
package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func main() {
	sc := NewScanner(os.Stdin)
	n, _ := sc.NextInt()
	a, b := make([]int, n), make([]int, n)
	for i := 0; i < n; i++ {
		a[i], _ = sc.NextInt()
		b[i], _ = sc.NextInt()
	}
	ans := solve(n, a, b)
	fmt.Println(ans)
}

const mod = 1000000007

type pair struct {
	x, y int
}

func solve(n int, a, b []int) (ans uint) {
	zero := uint(0)
	count := map[pair]*pair{}
	for i := 0; i < n; i++ {
		x, y := a[i], b[i]
		if x == 0 && y == 0 {
			zero++
			continue
		}
		if y < 0 || y == 0 && x < 0 {
			x, y = rotate180(x, y)
		}
		rot90 := x <= 0
		if rot90 {
			x, y = rotate90(x, y)
		}
		g := gcd(x, y)
		x, y = x/g, y/g
		key := pair{x, y}
		if count[key] == nil {
			count[key] = &pair{}
		}
		if rot90 {
			count[key].y++
		} else {
			count[key].x++
		}
	}

	ans = 1
	for _, v := range count {
		c1, c2 := v.x, v.y
		now := uint(1)
		now = (now + ModPow(2, uint(c1), mod) - 1) % mod
		now = (now + ModPow(2, uint(c2), mod) - 1) % mod
		ans = ModMul(ans, now, mod)
	}
	if ans == 0 {
		panic("")
	}
	ans = (ans + zero - 1 + mod) % mod
	return ans
}

func rotate180(x1, y1 int) (x2, y2 int) {
	return -x1, -y1
}

func rotate90(x1, y1 int) (x2, y2 int) {
	return y1, -x1
}

func gcd(x, y int) int {
	if x < y {
		x, y = y, x
	}
	if y == 0 {
		return x
	}
	return gcd(y, x%y)
}

// Scanner is a wrapper of bufio.Scanner which is customized for competitive programing.
type Scanner struct {
	bufio.Scanner
}

// NewScanner is a constructor for Scanner.
func NewScanner(r io.Reader) *Scanner {
	sc := Scanner{*bufio.NewScanner(r)}
	sc.Buffer([]byte{}, math.MaxInt64)
	sc.Split(bufio.ScanWords)
	return &sc
}

// NextInt reads a integer from io stream.
func (sc *Scanner) NextInt() (int, error) {
	if !sc.Scan() {
		return -1, errors.New("failed to scan")
	}
	return strconv.Atoi(sc.Text())
}

// ModMul returns a*b with mod
func ModMul(a, b, mod uint) uint {
	if b == 0 {
		return 0
	}
	if a*b/b == a {
		return a * b % mod
	}
	panic("overflow")
}

// ModPow returns base^n with mod
func ModPow(base, n, mod uint) uint {
	ans := uint(1)
	for ; n > 0; n >>= 1 {
		if n&1 == 1 {
			ans = ModMul(ans, base, mod)
		}
		base = ModMul(base, base, mod)
	}
	return ans
}
//  [go]
package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func main() {
	sc := NewScanner(os.Stdin)
	n, _ := sc.NextInt()
	a, b := make([]int, n), make([]int, n)
	for i := 0; i < n; i++ {
		a[i], _ = sc.NextInt()
		b[i], _ = sc.NextInt()
	}
	ans := solve(n, a, b)
	fmt.Println(ans)
}

const mod = 1000000007

type pair struct {
	x, y int
}

func solve(n int, a, b []int) (ans uint) {
	zero := uint(0)
	count := map[pair]*pair{}
	for i := 0; i < n; i++ {
		x, y := a[i], b[i]
		if x == 0 && y == 0 {
			zero++
			continue
		}
		if y < 0 || y == 0 && x < 0 {
			x, y = rotate180(x, y)
		}
		rot90 := x <= 0
		if rot90 {
			x, y = rotate90(x, y)
		}
		g := gcd(x, y)
		x, y = x/g, y/g
		key := pair{x, y}
		if count[key] == nil {
			count[key] = &pair{}
		}
		if rot90 {
			count[key].y++
		} else {
			count[key].x++
		}
	}

	ans = 1
	for _, v := range count {
		c1, c2 := v.x, v.y
		now := uint(1)
		now = (now + ModPow(2, uint(c1), mod) - 1) % mod
		now = (now + ModPow(2, uint(c2), mod) - 1) % mod
		ans = ModMul(ans, now, mod)
	}
	ans = (ans + zero - 1) % mod
	return ans
}

func rotate180(x1, y1 int) (x2, y2 int) {
	return -x1, -y1
}

func rotate90(x1, y1 int) (x2, y2 int) {
	return y1, -x1
}

func gcd(x, y int) int {
	if x < y {
		x, y = y, x
	}
	if y == 0 {
		return x
	}
	return gcd(y, x%y)
}

// ModMul returns a*b with mod
func ModMul(a, b, mod uint) uint {
	if b == 0 {
		return 0
	}
	if a*b/b == a {
		return a * b % mod
	}
	panic("overflow")
}

// ModPow returns base^n with mod
func ModPow(base, n, mod uint) uint {
	ans := uint(1)
	for ; n > 0; n >>= 1 {
		if n&1 == 1 {
			ans = ModMul(ans, base, mod)
		}
		base = ModMul(base, base, mod)
	}
	return ans
}

// Scanner is a wrapper of bufio.Scanner which is customized for competitive programing.
type Scanner struct {
	bufio.Scanner
}

// NewScanner is a constructor for Scanner.
func NewScanner(r io.Reader) *Scanner {
	sc := Scanner{*bufio.NewScanner(r)}
	sc.Buffer([]byte{}, math.MaxInt64)
	sc.Split(bufio.ScanWords)
	return &sc
}

// NextInt reads a integer from io stream.
func (sc *Scanner) NextInt() (int, error) {
	if !sc.Scan() {
		return -1, errors.New("failed to scan")
	}
	return strconv.Atoi(sc.Text())
}
//  [go]
package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func main() {
	sc := NewScanner(os.Stdin)
	n, _ := sc.NextInt()
	a, b := make([]int, n), make([]int, n)
	for i := 0; i < n; i++ {
		a[i], _ = sc.NextInt()
		b[i], _ = sc.NextInt()
	}
	ans := solve(n, a, b)
	fmt.Println(ans)
}

const mod = 1000000007

type pair struct {
	x, y int
}

func solve(n int, a, b []int) (ans int) {
	zero := 0
	count := map[pair]*pair{}
	for i := 0; i < n; i++ {
		x, y := a[i], b[i]
		if x == 0 && y == 0 {
			zero++
			continue
		}
		if y < 0 || y == 0 && x < 0 {
			x, y = rotate180(x, y)
		}
		rot90 := x <= 0
		if rot90 {
			x, y = rotate90(x, y)
		}
		g := gcd(x, y)
		x, y = x/g, y/g
		key := pair{x, y}
		if count[key] == nil {
			count[key] = &pair{}
		}
		if rot90 {
			count[key].y++
		} else {
			count[key].x++
		}
	}

	ans = 1
	for _, v := range count {
		c1, c2 := v.x, v.y
		now := 1
		now = (now + ModPow(2, c1, mod) - 1) % mod
		now = (now + ModPow(2, c2, mod) - 1) % mod
		ans = ModMul(ans, now, mod)
	}
	ans = (ans + zero - 1) % mod
	return ans
}

func rotate180(x1, y1 int) (x2, y2 int) {
	return -x1, -y1
}

func rotate90(x1, y1 int) (x2, y2 int) {
	return y1, -x1
}

func gcd(x, y int) int {
	if x < y {
		x, y = y, x
	}
	if y == 0 {
		return x
	}
	return gcd(y, x%y)
}

// ModMul returns a*b with mod
func ModMul(a, b, mod int) int {
	ua, ub, umod := uint(a), uint(b), uint(mod)
	if ub == 0 {
		return 0
	}
	if ua*ub/ub == ua {
		return int(ua * ub % umod)
	}
	panic("overflow")
}

// ModPow returns base^n with mod
func ModPow(base, n, mod int) int {
	ans := 1
	for ; n > 0; n >>= 1 {
		if n&1 == 1 {
			ans = ModMul(ans, base, mod)
		}
		base = ModMul(base, base, mod)
	}
	return ans
}

// Scanner is a wrapper of bufio.Scanner which is customized for competitive programing.
type Scanner struct {
	bufio.Scanner
}

// NewScanner is a constructor for Scanner.
func NewScanner(r io.Reader) *Scanner {
	sc := Scanner{*bufio.NewScanner(r)}
	sc.Buffer([]byte{}, math.MaxInt64)
	sc.Split(bufio.ScanWords)
	return &sc
}

// NextInt reads a integer from io stream.
func (sc *Scanner) NextInt() (int, error) {
	if !sc.Scan() {
		return -1, errors.New("failed to scan")
	}
	return strconv.Atoi(sc.Text())
}
//  [ruby]
mod = 1_000_000_007

gets

h = Hash.new{|h, k| h[k] = [0, 0] }
genten_iwashi = 0

$<.read.split.map(&:to_i).each_slice(2) do |(a,b)|

  if 0 == a | b
    genten_iwashi += 1
  else
    f = a.zero? || (a > 0 && b > 0) || (a < 0 && b < 0)
    r = ( f ? Rational(a,b) : -Rational(b,a) )
    h[r][ f ? 0 : 1 ] += 1
  end
end

ans = 1
heiwa_iwashi = 0
h.values.each do |(s, t)|
  if s == 0 || t == 0
    heiwa_iwashi += (s + t)
  else
    ans *= ( 2.pow(s,mod) + 2.pow(t, mod) - 1)
    ans %= mod
  end
end
ans = ( ans * 2.pow(heiwa_iwashi, mod) ) % mod
ans = ( ans - 1 + genten_iwashi ) % mod

puts ans
//  [ruby]
class ExponentiationTable
  
  def initialize(x, mod = nil )
    @x = x
    @mod = mod
    @table = [x]
  end
  
  def pow(n)
    res = 1
    i = 0
    while n > 0
      if (n & 1) != 0
        res *= @table[i]
        res %= @mod if @mod
      end
      i += 1
      @table[i] ||= ( @mod ? @table[i-1] ** 2 % @mod : @table[i-1] ** 2 ) 
      n >>= 1
    end
    # p @table
    res
  end
end

mod = 1_000_000_007

gets

h = Hash.new{|h, k| h[k] = [0, 0] }
genten_iwashi = 0

$<.read.split.map(&:to_i).each_slice(2) do |(a,b)|

  if 0 == a | b
    genten_iwashi += 1
  else
    f = a.zero? || (a > 0 && b > 0) || (a < 0 && b < 0)
    r = ( f ? Rational(a,b) : -Rational(b,a) )
    h[r][ f ? 0 : 1 ] += 1
  end
end

ans = 1
heiwa_iwashi = 0
two = ExponentiationTable.new(2, mod)

h.values.each do |(s, t)|
  if s == 0 || t == 0
    heiwa_iwashi += (s + t)
  else
    ans *= ( two.pow(s) + two.pow(t) - 1)
    ans %= mod
  end
end
ans = ( ans * two.pow(heiwa_iwashi) ) % mod
ans = ( ans - 1 + genten_iwashi ) % mod

puts ans
//  [ruby]
class ExponentiationTable
  
  def initialize(x, mod = nil )
    @x = x
    @mod = mod
    @table = [x]
  end
  
  def pow(n)
    res = 1
    i = 0
    while n > 0
      if (n & 1) != 0
        res *= @table[i]
        res %= @mod if @mod
      end
      i += 1
      @table[i] ||= ( @table[i-1] ** 2) 
      @table[i] %= @mod if @mod
      n >>= 1
    end
    # p @table
    res
  end
end

mod = 1_000_000_007

gets

h = Hash.new{|h, k| h[k] = [0, 0] }
genten_iwashi = 0

$<.read.split.map(&:to_i).each_slice(2) do |(a,b)|

  if 0 == a | b
    genten_iwashi += 1
  else
    f = a.zero? || (a > 0 && b > 0) || (a < 0 && b < 0)
    r = ( f ? Rational(a,b) : -Rational(b,a) )
    h[r][ f ? 0 : 1 ] += 1
  end
end

ans = 1
heiwa_iwashi = 0
two = ExponentiationTable.new(2, mod)

h.values.each do |(s, t)|
  if s == 0 || t == 0
    heiwa_iwashi += (s + t)
  else
    ans *= ( two.pow(s) + two.pow(t) - 1)
    ans %= mod
  end
end
ans = ( ans * two.pow(heiwa_iwashi) ) % mod
ans = ( ans - 1 + genten_iwashi ) % mod

puts ans
//  [ruby]
MOD = 10 ** 9 + 7
N = gets.to_i
A = []
B = []
R = Hash.new { |h, k| h[k] = [] }

N.times do |i|
  a, b = gets.split.map(&:to_i)

  A << a
  B << b

  if b == 0
    R[Float::INFINITY] << i
  else
    R[Rational(a, b)] << i
  end
end

E = Hash.new { |h, k| h[k] = [] }

N.times do |u|
  a = A[u]
  b = B[u]

  r = (b == 0) ? Float::INFINITY : -Rational(b, a)

  R[r].each do |v|
    E[u] << v
  end
end

tree_id = 0
tree_ids = Hash.new
nums = []

N.times do |i|
  next if tree_ids[i]

  queue = []
  queue << [i, 0]
  colors = Hash.new(0)

  until queue.empty?
    v, c = queue.shift

    next if tree_ids[v]
    tree_ids[v] = tree_id
    colors[c] += 1

    E[v].each do |u|
      queue << [u, (c + 1) % 2]
    end
  end

  cnt = 0

  colors.each_value do |n|
    cnt += n * (n + 1) / 2
  end

  nums << cnt + 1

  tree_id += 1
end

ans = 1

nums.each do |n|
  ans *= n
  ans %= MOD
end

puts ans - 1
//  [ruby]
MOD = 10 ** 9 + 7
N = gets.to_i
A = []
B = []
R = Hash.new { |h, k| h[k] = [] }

N.times do |i|
  a, b = gets.split.map(&:to_i)

  A << a
  B << b

  if b == 0
    R[0] << i
  else
    R[Rational(a, b)] << i
  end
end

E = Hash.new { |h, k| h[k] = [] }

N.times do |u|
  a = A[u]
  b = B[u]

  R[-Rational(b, a)].each do |v|
    E[u] << v
  end
end

tree_id = 0
tree_ids = Hash.new
nums = []

N.times do |i|
  next if tree_ids[i]

  queue = []
  queue << [i, 0]
  colors = Hash.new(0)

  until queue.empty?
    v, c = queue.shift

    next if tree_ids[v]
    tree_ids[v] = tree_id
    colors[c] += 1

    E[v].each do |u|
      queue << [u, (c + 1) % 2]
    end
  end

  cnt = 0

  colors.each_value do |n|
    cnt += n * (n + 1) / 2
  end

  nums << cnt + 1

  tree_id += 1
end

ans = 1

nums.each do |n|
  ans *= n
  ans %= MOD
end

puts ans - 1
//  [ruby]
MOD = 10 ** 9 + 7
N = gets.to_i
A = []
B = []
R = Hash.new { |h, k| h[k] = [] }

N.times do |i|
  a, b = gets.split.map(&:to_i)

  A << a
  B << b

  R[Rational(a, b)] << i
end

E = Hash.new { |h, k| h[k] = [] }

N.times do |u|
  a = A[u]
  b = B[u]

  R[-Rational(b, a)].each do |v|
    E[u] << v
  end
end

tree_id = 0
tree_ids = Hash.new
nums = []

N.times do |i|
  next if tree_ids[i]

  queue = []
  queue << [i, 0]
  colors = Hash.new(0)

  until queue.empty?
    v, c = queue.shift

    next if tree_ids[v]
    tree_ids[v] = tree_id
    colors[c] += 1

    E[v].each do |u|
      queue << [u, (c + 1) % 2]
    end
  end

  cnt = 0

  colors.each_value do |n|
    cnt += n * (n + 1) / 2
  end

  nums << cnt + 1

  tree_id += 1
end

ans = 1

nums.each do |n|
  ans *= n
  ans %= MOD
end

puts ans - 1
//  [rust]
const M:u64=1000000007;
fn pow(a:u64,b:u64)->u64{return if b!=0{if b%2==1{pow(a,b-1)*a%M}else{pow(a*a%M,b/2)}}else{1}}
fn main(){
    proconio::input!{
        n:usize,
        abs:[(i64,i64);n]
    }
    let mut o=M-1;
    let mut mp=Vec::new();
    for ab in abs{
        let (mut a,mut b)=ab;
        if a==0&&b==0{o+=1}
        else
        {
            let g=num::integer::gcd(a,b);
            a/=g;
            b/=g;
            if a<0||a==0&&b>0{a=-a;b=-b}
            let mut f=0;
            if b<0{
                let t=a;
                a=-b;
                b=t;
                f=1;
            }
            mp.push((a,b,f))
        }
    }
    mp.sort();
    let mut i=0usize;
    let mut ans=1;
    while i<mp.len(){
        let j=i;
        let mut x=0;
        let mut y=0;
        while i<mp.len()&&mp[j].0==mp[i].0&&mp[j].1==mp[i].1{
            if mp[i].2==0{x+=1}else{y+=1}
            i+=1
        }
        ans=ans*(pow(2,x)+pow(2,y)-1)%M;
    }
    println!("{}",(ans+o)%M)
}
//  [rust]
const M:u64=1000000007;
fn main(){
    proconio::input!{
        n:usize,
        abs:[(i64,i64);n]
    }
    let mut o=M-1;
    let mut mp=Vec::new();
    for ab in abs{
        let (mut a,mut b)=ab;
        if a==0&&b==0{o+=1}
        else
        {
            let g=num::integer::gcd(a,b);
            a/=g;
            b/=g;
            if a<0||a==0&&b>0{a=-a;b=-b}
            let mut f=0;
            if b<0{
                let t=a;
                a=-b;
                b=t;
                f=1;
            }
            mp.push((a,b,f))
        }
    }
    mp.sort();
    let mut i=0usize;
    let mut ans=1;
    while i<mp.len(){
        let j=i;
        let mut x=1;
        let mut y=1;
        while i<mp.len()&&mp[j].0==mp[i].0&&mp[j].1==mp[i].1{
            if mp[i].2==0{x=x*2%M}else{y=y*2%M}
            i+=1
        }
        ans=ans*(x+y-1)%M;
    }
    println!("{}",(ans+o)%M)
}
//  [rust]
use proconio::{fastout, input};

#[allow(unused_imports)]
use std::cmp::*;
#[allow(unused_imports)]
use std::collections::*;

const MOD: usize = 1e9 as usize + 7;

// mod p で x^n
fn repeated_squaring(x: usize, n: usize, p: usize) -> usize {
    if n == 0 {
        1
    } else if n % 2 == 0 {
        repeated_squaring(x * x % p, n / 2, p)
    } else {
        (x * repeated_squaring(x, n - 1, p)) % p
    }
}

#[fastout]
fn main() {
    input! {
        n: usize,
        ab: [(isize, isize); n],
    }

    let gcd = num::integer::gcd;

    let mut hash: HashMap<(isize, isize), (usize, usize)> = HashMap::new();

    let mut zero = 0;
    for (a, b) in &ab {
        if *a == 0 && *b == 0 {
            zero += 1;
        } else {
            let c = gcd(*a, *b);
            let mut aa: isize = (*a).abs() / c;
            let mut bb: isize = (*b).abs() / c;

            let mut plus = true;
            if (*a < 0 && *b > 0) || (*a > 0 && *b < 0) {
                plus = false;
                let tmp = aa;
                aa = bb;
                bb = tmp;
            }

            if !hash.contains_key(&(aa, bb)) {
                if plus {
                    hash.insert((aa, bb), (1, 0));
                } else {
                    hash.insert((aa, bb), (0, 1));
                }
            } else {
                let (pi, ni) = hash[&(aa, bb)];
                if plus {
                    hash.insert((aa, bb), (pi + 1, ni));
                } else {
                    hash.insert((aa, bb), (pi, ni + 1));
                }
            }
        }
    }

    let mut ans = 1;
    for (_, v) in &hash {
        ans *= repeated_squaring(2, (*v).0, MOD) + repeated_squaring(2, (*v).1, MOD) - 1;
        ans %= MOD;
    }

    println!("{}", ans + zero - 1);
}
//  [swift]
#if os(Linux)
import Glibc
#else
import Darwin.C
#endif

let INPUT = stdin

func scanInts(count: Int) -> [Int] {
    let format: String
    switch count {
        case 1: format = "%lld"
        case 2: format = "%lld %lld"
        case 3: format = "%lld %lld %lld"
        case 4: format = "%lld %lld %lld %lld"
        case 5: format = "%lld %lld %lld %lld %lld"
        case 6: format = "%lld %lld %lld %lld %lld %lld"
        default: format = repeatElement("%lld", count: count).joined(separator: " ")
    }
    let ptr = UnsafeMutablePointer<CLongLong>.allocate(capacity: count)
    let ptrArray = Array(ptr ..< ptr+count)
    let read = withVaList(ptrArray) {
        vfscanf(INPUT, format, $0)
    }
    assert(read == count)
    return ptrArray.map { Int($0.pointee) }
}
func scanInt() -> Int {
    scanInts(count: 1)[0]
}
func scanIntPair() -> (Int, Int) {
    let a: [Int] = scanInts(count: 2)
    return (a[0], a[1])
}

//=============================================================================

func gcd(_ a: Int, _ b: Int) -> Int {
    b == 0 ? abs(a) : gcd(b, a%b)
}

struct Fraction: Equatable, Hashable {
    let numerator, denominator: Int
    init (_ numerator: Int, _ denominator: Int) {
        switch (numerator, denominator) {
        case (0, 0):
            self.numerator = 0
            self.denominator = 0
        case (0, _):
            self.numerator = 0
            self.denominator = 1
        case (_, 0):
            self.numerator = 1
            self.denominator = 0
        default:
            let g = gcd(numerator, denominator)
            self.numerator = denominator.signum() * numerator / g
            self.denominator = abs(denominator) / g
        }
    }
    init (_ tuple : (Int, Int)) {
        self.init(tuple.0, tuple.1)
    }
    func perpendicular() -> Fraction {
        Fraction(-denominator, numerator)
    }
}

func pow(_ x: Int, _ n: Int, mod: Int) -> Int {
    precondition(n >= 0 && mod > 1)
    if n == 0 { return 1 }

    var u = pow(x, n/2, mod: mod)
    u = u*u % mod
    if n%2 == 1 { u = u*x % mod }
    return u
}

//=============================================================================

let MOD = Int(1e9+7)

let N = scanInt()
var cliques: [Fraction: Int] = [:]
var zeroes = 0
for _ in 1...N {
    let f = Fraction(scanIntPair())
    if f == Fraction(0, 0) {
        zeroes += 1
    } else {
        cliques[f, default: 0] += 1
    }
}

var ways = 1
while let (k1, v1) = cliques.first {
    cliques.removeValue(forKey: k1)
    let k2 = k1.perpendicular()
    let v2 = cliques.removeValue(forKey: k2)

    ways *= pow(2, v1, mod: MOD) + (v2 != nil ? pow(2, v2!, mod: MOD) - 1 : 0)
    ways %= MOD
}
ways += MOD - 1
ways += zeroes
ways %= MOD
print(ways)
//  [swift]
func gcd(_ a: Int, _ b: Int) -> Int {
    b == 0 ? abs(a) : gcd(b, a%b)
}

struct Fraction: Equatable, Hashable {
    let numerator, denominator: Int
    init (_ numerator: Int, _ denominator: Int) {
        switch (numerator, denominator) {
        case (0, 0):
            self.numerator = 0
            self.denominator = 0
        case (0, _):
            self.numerator = 0
            self.denominator = 1
        case (_, 0):
            self.numerator = 1
            self.denominator = 0
        default:
            let g = gcd(numerator, denominator)
            self.numerator = denominator.signum() * numerator / g
            self.denominator = abs(denominator) / g
        }
    }
    func perpendicular() -> Fraction {
        Fraction(-denominator, numerator)
    }
}

func pow(_ x: Int, _ n: Int, mod: Int) -> Int {
    precondition(n >= 0 && mod > 1)
    if n == 0 { return 1 }

    var u = pow(x, n/2, mod: mod)
    u = u*u % mod
    if n%2 == 1 { u = u*x % mod }
    return u
}
///////////////////////////////////////////////////////////////////////////////

let MOD = Int(1e9+7)

let N = Int(readLine()!)!
var cliques: [Fraction: Int] = [:]
var zeroes = 0
for _ in 1...N {
    let line = readLine()!.split(separator: " ").map { Int($0)! }
    let f = Fraction(line[0], line[1])
    if f == Fraction(0, 0) {
        zeroes += 1
    } else {
        cliques[f, default: 0] += 1
    }
}

var ways = 1
while let (k1, v1) = cliques.first {
    cliques.removeValue(forKey: k1)
    let k2 = k1.perpendicular()
    let v2 = cliques.removeValue(forKey: k2)

    ways *= pow(2, v1, mod: MOD) + (v2 != nil ? pow(2, v2!, mod: MOD) - 1 : 0)
    ways %= MOD
}
ways += MOD - 1
ways += zeroes
ways %= MOD
print(ways)
//  [swift]
func gcd(_ a: Int, _ b: Int) -> Int {
    b == 0 ? abs(a) : gcd(b, a%b)
}

struct Fraction: Equatable, Hashable {
    let numerator, denominator: Int
    init (_ numerator: Int, _ denominator: Int) {
        switch (numerator, denominator) {
        case (0, 0):
            self.numerator = 0
            self.denominator = 0
        case (0, _):
            self.numerator = 0
            self.denominator = 1
        case (_, 0):
            self.numerator = 1
            self.denominator = 0
        default:
            let g = gcd(numerator, denominator)
            self.numerator = denominator.signum() * numerator / g
            self.denominator = abs(denominator) / g
        }
    }
    func perpendicular() -> Fraction {
        Fraction(-denominator, numerator)
    }
}

func pow(_ x: Int, _ n: Int, mod: Int) -> Int {
    precondition(n >= 0 && mod > 1)
    if n == 0 { return 1 }

    var u = pow(x, n/2, mod: mod)
    u = u &* u % mod
    if n%2 == 1 { u = u &* x % mod }
    return u
}
///////////////////////////////////////////////////////////////////////////////

let MOD = Int(1e9+7)

let N = Int(readLine()!)!
var cliques: [Fraction: Int] = [:]
var zeroes = 0
for _ in 1...N {
    let line = readLine()!.split(separator: " ").map { Int($0)! }
    let f = Fraction(line[0], line[1])
    if f == Fraction(0, 0) {
        zeroes += 1
    } else {
        cliques[f, default: 0] += 1
    }
}

var ways = 1
while let (k1, v1) = cliques.first {
    cliques.removeValue(forKey: k1)
    let k2 = k1.perpendicular()
    let v2 = cliques.removeValue(forKey: k2)

    ways *= pow(2, v1, mod: MOD) + (v2 != nil ? pow(2, v2!, mod: MOD) - 1 : 0)
    ways %= MOD
}
ways += MOD - 1
ways += zeroes
ways %= MOD
print(ways)
//  [swift]
#if os(Linux)
import Glibc
#else
import Darwin.C
#endif

let INPUT_SIZE = 67_108_864
func readLines() -> [Substring] {
    let ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: INPUT_SIZE+1)
    let n = fread(ptr, 1, INPUT_SIZE, stdin)
    ptr[n] = 0
    return String(cString: ptr).split(separator: "\n")
}
var input = readLines().makeIterator()

//=============================================================================

func gcd(_ a: Int, _ b: Int) -> Int {
    b == 0 ? abs(a) : gcd(b, a%b)
}

struct Fraction: Equatable, Hashable {
    let numerator, denominator: Int
    init (_ numerator: Int, _ denominator: Int) {
        switch (numerator, denominator) {
        case (0, 0):
            self.numerator = 0
            self.denominator = 0
        case (0, _):
            self.numerator = 0
            self.denominator = 1
        case (_, 0):
            self.numerator = 1
            self.denominator = 0
        default:
            let g = gcd(numerator, denominator)
            self.numerator = denominator.signum() * numerator / g
            self.denominator = abs(denominator) / g
        }
    }
    func perpendicular() -> Fraction {
        Fraction(-denominator, numerator)
    }
}

func pow(_ x: Int, _ n: Int, mod: Int) -> Int {
    precondition(n >= 0 && mod > 1)
    if n == 0 { return 1 }

    var u = pow(x, n/2, mod: mod)
    u = u*u % mod
    if n%2 == 1 { u = u*x % mod }
    return u
}

//=============================================================================

let MOD = Int(1e9+7)

let N = Int(input.next()!)!
var cliques: [Fraction: Int] = [:]
var zeroes = 0
for _ in 1...N {
    let line = input.next()!.split(separator: " ").map { Int($0)! }
    let f = Fraction(line[0], line[1])
    if f == Fraction(0, 0) {
        zeroes += 1
    } else {
        cliques[f, default: 0] += 1
    }
}

var ways = 1
while let (k1, v1) = cliques.first {
    cliques.removeValue(forKey: k1)
    let k2 = k1.perpendicular()
    let v2 = cliques.removeValue(forKey: k2)

    ways *= pow(2, v1, mod: MOD) + (v2 != nil ? pow(2, v2!, mod: MOD) - 1 : 0)
    ways %= MOD
}
ways += MOD - 1
ways += zeroes
ways %= MOD
print(ways)
//  [swift]
func gcd(_ a: Int, _ b: Int) -> Int {
    b == 0 ? abs(a) : gcd(b, a%b)
}

struct Fraction: Equatable, Hashable {
    let numerator, denominator: Int
    init (_ numerator: Int, _ denominator: Int) {
        switch (numerator, denominator) {
        case (0, 0):
            self.numerator = 0
            self.denominator = 0
        case (0, _):
            self.numerator = 0
            self.denominator = 1
        case (_, 0):
            self.numerator = 1
            self.denominator = 0
        default:
            let g = gcd(numerator, denominator)
            self.numerator = denominator.signum() * numerator / g
            self.denominator = abs(denominator) / g
        }
    }
    func perpendicular() -> Fraction {
        Fraction(-denominator, numerator)
    }
}

func pow(_ x: Int, _ n: Int, mod: Int) -> Int {
    precondition(n >= 0 && mod > 1)
    if n == 0 { return 1 }

    var u = pow(x, n/2, mod: mod)
    u = u*u % mod
    if n%2 == 1 { u = u*x % mod }
    return u
}
///////////////////////////////////////////////////////////////////////////////

let MOD = Int(1e9+7)

let N = Int(readLine()!)!
var cliques: [Fraction: Int] = [:]
var zeroes = 0
for _ in 1...N {
    let line = readLine()!.split(separator: " ").map { Int($0)! }
    let f = Fraction(line[0], line[1])
    if f == Fraction(0, 0) {
        zeroes += 1
    } else {
        cliques[f, default: 0] += 1
    }
}

var ways = 1
while let (k1, v1) = cliques.first {
    cliques.removeValue(forKey: k1)
    let k2 = k1.perpendicular()
    let v2 = cliques.removeValue(forKey: k2)

    ways *= pow(2, v1, mod: MOD) + (v2 != nil ? pow(2, v2!, mod: MOD) - 1 : 0)
    ways %= MOD
}
ways -= 1
ways += zeroes
ways %= MOD
print(ways)
//  [typescript]
import * as fs from 'fs';

const readString = (() => {
  const input = fs.readFileSync(0).toString();
  const words = input.split(/[ \n]/);
  let i = 0;
  return () => words[i++] || '';
})();
const readInt = () => parseInt(readString(), 10);
const readBigInt = () => BigInt(readString());

const gcd = (a: bigint, b: bigint) => {
  const _gcd = (a: bigint, b: bigint): bigint => {
    const q = a % b;
    return q === 0n ? b : _gcd(b, q);
  };
  return a > b ? _gcd(a, b) : _gcd(b, a);
};

const abs = (a: bigint) => a > 0n ? a : -a;

(function main() {
  const N = readInt();

  let zero: number = 0;
  const groups: { [k: string]: [number, number] } = {};
  Array.from({ length: N }, () => {
    let A = readBigInt();
    let B = readBigInt();
    if (A === 0n && B === 0n) {
      zero++;
    } else if (A === 0n) {
      groups['0:1'] = groups['0:1'] || [0, 0];
      groups['0:1'][0]++;
    } else if (B === 0n) {
      groups['0:1'] = groups['0:1'] || [0, 0];
      groups['0:1'][1]++;
    } else {
      const n = gcd(abs(A), abs(B));
      A /= n;
      B /= n;
      if (A < 0) {
        A *= -1n;
        B *= -1n;
      }

      if (B > 0) {
        const k = `${A}:${B}`;
        groups[k] = groups[k] || [0, 0];
        groups[k][0]++;
      } else {
        const k = `${-B}:${A}`;
        groups[k] = groups[k] || [0, 0];
        groups[k][1]++;
      }
    }
  });

  const mod = 1000000007;

  let result: bigint = BigInt(1);
  for (const k of Object.keys(groups)) {
    const [xn, yn] = groups[k];

    let tmp: number = 0;
    if (xn) {
      let xx = 1;
      for (let i = 0; i < xn; i++) {
        xx *= 2;
        if (xx > mod) xx %= mod;
      }
      xx -= 1;
      tmp += xx;
      if (tmp > mod) tmp %= mod;
    }

    if (yn) {
      let yy = 1;
      for (let i = 0; i < yn; i++) {
        yy *= 2;
        if (yy > mod) yy %= mod;
      }
      yy -= 1;
      tmp += yy;
      if (tmp > mod) tmp %= mod;
    }

    tmp++;
    if (tmp > mod) tmp %= mod;

    result *= BigInt(tmp);
    if (result > mod) result %= BigInt(mod);
  }

  result += BigInt(zero) + BigInt(mod - 1);
  if (result > mod) result %= BigInt(mod);

  console.log(result.toString());
})();
//  [typescript]
import * as fs from 'fs';

const readString = (() => {
  const input = fs.readFileSync(0).toString();
  const words = input.split(/[ \n]/);
  let i = 0;
  return () => words[i++] || '';
})();
const readInt = () => parseInt(readString(), 10);
const readBigInt = () => BigInt(readString());

const gcd = (a: bigint, b: bigint) => {
  const _gcd = (a: bigint, b: bigint): bigint => {
    const q = a % b;
    return q === 0n ? b : _gcd(b, q);
  };
  return a > b ? _gcd(a, b) : _gcd(b, a);
};

const MOD = 1000000007;
const MOD_BIGINT = BigInt(MOD);
class ModBigInt {
  constructor(public v: bigint) { }

  static of(n: number | bigint) {
    return new ModBigInt(ModBigInt.toBigInt(n));
  }

  static toBigInt(other: number | bigint | ModBigInt) {
    if (typeof other === 'bigint') return other;
    if (typeof other === 'number') return BigInt(other);
    return other.v;
  }

  clone = () => new ModBigInt(this.v);
  plus = (other: number | bigint | ModBigInt) => {
    this.v = (this.v + ModBigInt.toBigInt(other)) % MOD_BIGINT;
    return this;
  }
  minus = (other: number | bigint | ModBigInt) => {
    this.v = (this.v + MOD_BIGINT - ModBigInt.toBigInt(other)) % MOD_BIGINT;
    return this;
  }
  multiply = (other: number | bigint | ModBigInt) => {
    this.v = (this.v * ModBigInt.toBigInt(other)) % MOD_BIGINT;
    return this;
  }
  pow = (other: number) => {
    let v = mod(1);
    for (let i = 0; i < other; i++) v.multiply(this.v);
    return v;
  }
}

const mod = ModBigInt.of;

const abs = (a: bigint) => a > 0n ? a : -a;

(function main() {
  const N = readInt();

  let zero: number = 0;
  const groups: { [k: string]: [number, number] } = {};
  Array.from({ length: N }, () => {
    let A = readBigInt();
    let B = readBigInt();
    if (A === 0n && B === 0n) {
      zero++;
    } else if (A === 0n) {
      groups['0:1'] = groups['0:1'] || [0, 0];
      groups['0:1'][0]++;
    } else if (B === 0n) {
      groups['0:1'] = groups['0:1'] || [0, 0];
      groups['0:1'][1]++;
    } else {
      const n = gcd(abs(A), abs(B));
      A /= n;
      B /= n;
      if (A < 0) {
        A *= -1n;
        B *= -1n;
      }

      if (B > 0) {
        const k = `${A}:${B}`;
        groups[k] = groups[k] || [0, 0];
        groups[k][0]++;
      } else {
        const k = `${-B}:${A}`;
        groups[k] = groups[k] || [0, 0];
        groups[k][1]++;
      }
    }
  });

  let result = mod(1);
  for (const k of Object.keys(groups)) {
    const [xn, yn] = groups[k];

    let tmp = mod(0);
    if (xn) {
      tmp.plus(mod(2).pow(xn).minus(1));
    }

    if (yn) {
      tmp.plus(mod(2).pow(yn).minus(1));
    }

    tmp.plus(1);

    result.multiply(tmp);
  }

  result.plus(zero).minus(1);

  console.log(result.v.toString());
})();
//  [typescript]
import * as fs from 'fs';

const readString = (() => {
  const input = fs.readFileSync(0).toString();
  const words = input.split(/[ \n]/);
  let i = 0;
  return () => words[i++] || '';
})();
const readInt = () => parseInt(readString(), 10);
const readBigInt = () => BigInt(readString());

const gcd = (a: bigint, b: bigint) => {
  const _gcd = (a: bigint, b: bigint): bigint => {
    const q = a % b;
    return q === 0n ? b : _gcd(b, q);
  };
  return a > b ? _gcd(a, b) : _gcd(b, a);
};

const abs = (a: bigint) => a > 0n ? a : -a;

(function main() {
  const N = readInt();

  let zero: number = 0;
  const groups: { [k: string]: [number, number] } = {};
  Array.from({ length: N }, () => {
    let A = readBigInt();
    let B = readBigInt();
    if (A === 0n && B === 0n) {
      zero++;
    } else if (A === 0n) {
      groups['0:1'] = groups['0:1'] || [0, 0];
      groups['0:1'][0]++;
    } else if (B === 0n) {
      groups['0:1'] = groups['0:1'] || [0, 0];
      groups['0:1'][1]++;
    } else {
      const n = gcd(abs(A), abs(B));
      A /= n;
      B /= n;
      if (A < 0) {
        A *= -1n;
        B *= -1n;
      }

      if (B > 0) {
        const k = `${A}:${B}`;
        groups[k] = groups[k] || [0, 0];
        groups[k][0]++;
      } else {
        const k = `${-B}:${A}`;
        groups[k] = groups[k] || [0, 0];
        groups[k][1]++;
      }
    }
  });

  const mod = 1000000007;

  let result: bigint = BigInt(1);
  for (const k of Object.keys(groups)) {
    const [xn, yn] = groups[k];

    let tmp: number = 0;
    if (xn) {
      let xx = 1;
      for (let i = 0; i < xn; i++) {
        xx *= 2;
        if (xx > mod) xx %= mod;
      }
      xx -= 1;
      tmp += xx;
      if (tmp > mod) tmp %= mod;
    }

    if (yn) {
      let yy = 1;
      for (let i = 0; i < yn; i++) {
        yy *= 2;
        if (yy > mod) yy %= mod;
      }
      yy -= 1;
      tmp += yy;
      if (tmp > mod) tmp %= mod;
    }

    tmp++;
    if (tmp > mod) tmp %= mod;

    result *= BigInt(tmp);
    if (result > mod) result %= BigInt(mod);
  }

  result += BigInt(zero) + BigInt(mod - 1);
  if (result > mod) result %= BigInt(mod);

  console.log(result);
})();