#include<bits/stdc++.h>
using namespace std;

typedef pair<int, int> pii;

const int mod = 1e9 + 7;
const int MN = 200010;

int exp(int x, int n) {
    int ret = 1;
    while(n) {
        if(n & 1) ret = 1LL * ret * x % mod;
        x = 1LL * x * x % mod;
        n >>= 1;
    }
    return ret;
}
int inv(int x) {
    return exp(x, mod - 2);
}
int fact[MN], invf[MN];

int N;
pii P[MN];
vector<pii> Vx[MN], Vy[MN];
vector<int> adj[MN];
int par[MN], tin[MN], timer;
vector<int> V, cycle;
int ans;

bool dfs0(int u, int p) {
    tin[u] = timer++;
    V.push_back(u);

    for(int i = 0; i < adj[u].size(); i++) {
        int v = adj[u][i];
        if(v == p) continue;
        if(tin[v] != -1) {
            if(tin[v] < tin[u]) {
                if(cycle.size()) return false;
                int t = u;
                while(1) {
                    cycle.push_back(t);
                    if(t == v) break;
                    t = par[t];
                }
            }
            continue;
        }
        par[v] = u;
        if(!dfs0(v, u)) return false;
    }
    return true;
}

int X[MN], Y[MN];
int dir[MN];

void dfs1(int u, int p) {
    tin[u] = timer++;

    for(int i = 0; i < adj[u].size(); i++) {
        int v = adj[u][i];
        if(tin[v] != -1) continue;
        if(p == -1 && P[u].first == P[v].first && P[u].second > P[v].second) continue;
        dir[v] = P[u].second == P[v].second;
        dfs1(v, u);
    }
}

vector<int> tree[MN];
int root[MN], sz[MN];

int dfs2(int u) {
    int ret = 1;

    sz[u] = 0;
    for(int i = 0; i < tree[u].size(); i++) {
        int v = tree[u][i];
        int t = dfs2(v);
        sz[u] += sz[v];
        ret = 1LL * ret * t % mod;
        ret = 1LL * ret * invf[ sz[v] ] % mod;
    }
    ret = 1LL * ret * fact[ sz[u] ] % mod;
    sz[u]++;
    return ret;
}

int solve(int u) {
    for(int i = 0; i < V.size(); i++) {
        tin[V[i]] = -1;
        X[ P[V[i]].first ] = 0;
        Y[ P[V[i]].second ] = 0;
    }
    dir[u] = 0;
    Y[ P[u].second ] = 1;
    dfs1(u, -1);

    for(int i = 0; i < V.size(); i++) {
        tree[V[i]].clear();
        root[V[i]] = 1;
    }
    for(int i = 0; i < V.size(); i++) {
        int u = V[i];
        if(dir[u]) {
            int x = P[u].first;
            for(int j = 0; j < Vx[x].size(); j++) {
                if(Vx[x][j].second == u) break;
                tree[u].push_back(Vx[x][j].second);
                root[Vx[x][j].second] = 0;
            }
        }
        else {
            int y = P[u].second;
            for(int j = 0; j < Vy[y].size(); j++) {
                if(Vy[y][j].second == u) break;
                tree[u].push_back(Vy[y][j].second);
                root[Vy[y][j].second] = 0;
            }
        }
    }

    int ret = 1;
    for(int i = 0; i < V.size(); i++) if(root[V[i]]) {
        int t = dfs2(V[i]);
        ret = 1LL * ret * t % mod;
        ret = 1LL * ret * invf[ sz[V[i]] ] % mod;
    }
    ret = 1LL * ret * fact[ V.size() ] % mod;
    return ret;
}

int main() {
    fact[0] = 1;
    for(int i = 1; i < MN; i++) {
        fact[i] = 1LL * fact[i - 1] * i % mod;
    }
    for(int i = 0; i < MN; i++) {
        invf[i] = inv(fact[i]);
    }

    scanf("%d", &N);

    for(int i = 0; i < 2 * N; i++) {
        scanf("%d %d", &P[i].first, &P[i].second);
        P[i].first--;
        P[i].second--;

        Vx[ P[i].first ].push_back(pii(P[i].second, i));
        Vy[ P[i].second ].push_back(pii(P[i].first, i));
    }
    for(int i = 0; i < N; i++) {
        sort(Vx[i].begin(), Vx[i].end());
        sort(Vy[i].begin(), Vy[i].end());

        for(int j = 0; j < (int)Vx[i].size() - 1; j++) {
            int u = Vx[i][j].second;
            int v = Vx[i][j + 1].second;
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
        for(int j = 0; j < (int)Vy[i].size() - 1; j++) {
            int u = Vy[i][j].second;
            int v = Vy[i][j + 1].second;
            adj[u].push_back(v);
            adj[v].push_back(u);
        }
    }

    memset(tin, -1, sizeof(tin));
    ans = 1;
    for(int i = 0; i < 2 * N; i++) if(tin[i] == -1) {
        cycle.clear();
        V.clear();
        if(!dfs0(i, -1)) {
            printf("0");
            return 0;
        }

        int mxy = -1, mnx = 1e9, mxx = -1, p1 = -1, p2 = -1;
        for(int j = 0; j < cycle.size(); j++) {
            int u = cycle[j];
            if(mxy < P[u].second) {
                mxy = P[u].second;
                mnx = P[u].first;
                mxx = P[u].first;
                p1 = u;
                p2 = u;
            }
            else if(mxy == P[u].second) {
                if(mnx > P[u].first) mnx = P[u].first, p1 = u;
                if(mxx < P[u].first) mxx = P[u].first, p2 = u;
            }
        }

        int tmp = solve(p1) + solve(p2);
        tmp %= mod;
        ans = 1LL * ans * tmp % mod;
        ans = 1LL * ans * invf[ V.size() ] % mod;
    }
    ans = 1LL * ans * fact[2 * N] % mod;

    printf("%d", ans);
}


Measured memory_bytes: 48760