#include <bits/stdc++.h>
#define ll long long
#define MAXN 200010
#define INF 1000000010
#define MOD 1000000007

using namespace std;

struct par
{
    ll X, Y;
};

struct linija
{
    par A, B;
};

par pocetak;

ll pomnozi(par A, par B)
{
    return A.X * B.Y - B.X * A.Y;
}

par Drugi(stack <par> &stek)
{
    par tren_tacka = stek.top();
    stek.pop();
    par treba = stek.top();
    stek.push(tren_tacka);
    return treba;
}

ll Udaljenost(par A, par B)
{
    ll Udalj1 = (A.X - B.X)*(A.X - B.X);
    ll Udalj2 = (A.Y - B.Y)*(A.Y - B.Y);
    return Udalj1 + Udalj2;
}
ll Pravac(par A, par B, par C)
{
    ll rez = (B.Y - A.Y)*(C.X - B.X) - (B.X - A.X)*(C.Y - B.Y);
    if(rez == 0) return 0;
    if(rez < 0) return 2;
    return 1;
}

int cmp(const void *A, const void *B)
{
    par *prva = (par*)A;
    par *druga = (par*)B;
    ll pravac = Pravac(pocetak, *prva, *druga);
    if(pravac == 0)
    {
        if(Udaljenost(pocetak, *druga) >= Udaljenost(pocetak, *prva)) return -1;
        return 1;
    }
    if(pravac == 2) return -1;
    return 1;
}

vector <par> Omotac (par tacke[], ll ima)
{
    vector <par> rez;
    ll min_Y = tacke[0].Y, mini = 0;
    for(int i = 1; i < ima; i++)
    {
        ll sad_Y = tacke[i].Y;
        if((sad_Y < min_Y) || (min_Y == sad_Y && tacke[i].X < tacke[mini].X))
        {
            min_Y = tacke[i].Y;
            mini = i;
        }
    }
    swap(tacke[0], tacke[mini]);
    pocetak = tacke[0];
    qsort(&tacke[1], ima - 1, sizeof(par), cmp);
    ll idx = 1;
    for(int i = 1; i < ima; i++)
    {
        while(i < ima-1 && Pravac(pocetak, tacke[i], tacke[i + 1]) == 0) i++;
        tacke[idx] = tacke[i];
        idx++;
    }
    if(idx < 3) return rez;
    stack <par> stek;
    for(int i = 0; i < 3; i++) stek.push(tacke[i]);
    for(int i = 3; i < idx; i++)
    {
        while(stek.size() > 1 && Pravac(Drugi(stek), stek.top(), tacke[i]) != 2) stek.pop();
        stek.push(tacke[i]);
    }
    while(!stek.empty())
    {
        rez.push_back(stek.top());
        stek.pop();
    }
}

bool Na_liniji(linija L, par tacka)
{
    if(tacka.X <= max(L.A.X, L.B.X) && tacka.X <= min(L.A.X, L.B.X)
       && (tacka.Y <= max(L.A.Y, L.B.Y) && tacka.Y <= min(L.A.Y, L.B.Y))) return true;
    return false;
}

bool Sece(linija L1, linija L2)
{
    ll P1 = Pravac(L1.A, L1.B, L2.A);
    ll P2 = Pravac(L1.A, L1.B, L2.B);
    ll P3 = Pravac(L2.A, L2.B, L1.A);
    ll P4 = Pravac(L2.A, L2.B, L1.B);
    if(P1 != P2 && P3 != P4) return true;
    if(P1 == 0 && Na_liniji(L1, L2.A)) return true;
    if(P2 == 0 && Na_liniji(L1, L2.B)) return true;
    if(P3 == 0 && Na_liniji(L2, L1.A)) return true;
    if(P4 == 0 && Na_liniji(L2, L1.B)) return true;
    return false;
}

bool Unutra(vector <par> tacke, par nula, ll ima)
{
    linija van = {nula, {INF, nula.Y}};
    ll br = 0, i = 0;
    do
    {
        linija stranica = {tacke[i], tacke[(i+1)%ima]};
        if(Sece(stranica, van))
        {
            if(Pravac(stranica.A, nula, stranica.B) == 0)
                return Na_liniji(stranica, nula);
            br++;
        }
        i = (i+1)%ima;
    } while(i != 0);
    return br%2;
}

bool Na_pravoj(vector <par> tacke, ll N)
{
    ll A, B, C, D;
    A = tacke[0].X - tacke[1].X;
    B = tacke[0].Y - tacke[1].Y;
    for(int i = 2; i < N; i++)
    {
        C = tacke[0].X - tacke[i].X;
        D = tacke[0].Y - tacke[i].Y;
        if(B*C != A*D) return false;
    }
    return true;
}

int main()
{
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    ll T, N, X, Y, ima = 0;
    vector <par> rez;
    vector <ll> A;
    vector <ll> B;
    cin >> N;
    par tacke[N];
    for(int i = 0; i < N; i++) {cin >> X >> Y; tacke[i] = {X, Y};}
    /**rez = Omotac(tacke, N);
    for(auto it = rez.begin(); it != rez.end(); it++) {cout << it->X << " " << it->Y << endl;}
    return 0;**/
    for(int i = 0; i < N; i++)
    {
        if(tacke[i].Y == 1) A.push_back(tacke[i].X);
        if(tacke[i].Y == -1) B.push_back(tacke[i].X);
    }
    if(A.size() + B.size() == N && A.size() == 1)
    {
        ll ima = 1LL;
        sort(B.begin(), B.end());
        ll levo = 0, desno = 0, jednako = 0, treba_X = -A[0];
        for(int i = 0; i < B.size(); i++)
        {
            if(B[i] < treba_X) levo++;
            else if(B[i] > treba_X) desno++;
            else jednako++;
        }
        ima *= 1LL*(1<<levo - 1)*(1<<desno - 1);
        if(ima >= MOD) ima %= MOD;
        if(jednako) ima += (1<<(levo + desno) - 1);
        if(ima >= MOD) ima %= MOD;
        cout << ima << endl;
        return 0;
    }
    for(int bit = 0; bit < (1<<N); bit++)
    {
        vector <par> tren;
        vector <par> rez;
        for(int mask = 0; mask < N; mask++) {if(bit&(1 << mask)) {tren.push_back(tacke[mask]);}}
        ll vel = (ll) tren.size();
        par sad[vel];
        for(int i = 0; i < vel; i++) sad[i] = {tren[i].X, tren[i].Y};
        if(vel == 0) continue;
        if(vel == 1)
        {
            if(sad[0].X == 0 && sad[0].Y == 0) ima++;
            if(ima >= MOD) ima %= MOD;
            continue;
        }
        if(vel == 2)
        {
            tren.push_back({0, 0});
            if(Na_pravoj(tren, tren.size())) ima++;
            if(ima >= MOD) ima %= MOD;
            continue;
        }
        else
        {
            if(Na_pravoj(tren, tren.size()))
            {
                tren.push_back({0, 0});
                if(Na_pravoj(tren, tren.size())) ima++;
            }
            else
            {
                rez = Omotac(sad, vel);
                if(Unutra(rez, {0, 0}, (ll) rez.size())) ima++;
            }
            if(ima >= MOD) ima %= MOD;
            continue;
        }
    }
    cout << ima << endl;
}
/**
17
25 32
36 40
-13 7
-26 -49
3 27
-33 -39
-19 -9
36 6
-16 -31
-17 -48
-29 34
-49 36
-28 -25
7 37
2 45
-18 15
-23 -26
41 42

11
6 -1
-4 -1
5 -1
-3 -1
-2 -1
-1 -1
0 -1
1 -1
2 -1
3 -1
-4 1

**/