#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <utility>
#include <iomanip>
#include <algorithm>
#include <functional>
using namespace std;

#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl
#define EACH(i, s) for (__typeof__((s).begin()) i = (s).begin(); i != (s).end(); ++i)

template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, vector<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }
template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)
{ EACH(it, P) { s << "<" << it->first << "->" << it->second << "> "; } return s << endl; }


const int MOD = 1000000007;
inline long long mod(long long a, long long m) { return (a % m + m) % m; }

struct Fp {
	long long val;

	Fp() : val(0) {}
	Fp(long long val_) { this->val = mod(val_, MOD); }
	Fp operator = (long long val_) { this->val = mod(val_, MOD); return *this; }
	inline Fp operator - () { return mod(-val, MOD); }
	inline const Fp& operator += (const Fp &x);
	inline const Fp& operator -= (const Fp &x);
	inline const Fp& operator *= (const Fp &x);
	inline const Fp& operator /= (const Fp &x);
	inline const bool operator == (const Fp &x);
	inline const bool operator != (const Fp &x);
};

ostream &operator << (ostream &os, Fp x) { return os << x.val; }
istream &operator >> (istream &is, Fp &x) { is >> x; return is; }
bool operator == (Fp x, Fp y) { return mod(x.val, MOD) == mod(y.val, MOD); }

inline Fp operator + (Fp x, Fp y) { return mod(x.val + y.val, MOD); }
inline Fp operator - (Fp x, Fp y) { return mod(x.val - y.val, MOD); }
inline Fp operator * (Fp x, Fp y) { return mod(x.val * y.val, MOD); }
inline Fp operator / (Fp x, Fp y) {
	long long a = y.val, b = MOD, u = 1, v = 0;
	while (b) {
		long long t = a / b;
		a -= t*b; swap(a, b);
		u -= t*v; swap(u, v);
	}
	return x * u;
}
inline Fp power(Fp a, long long n) {
	if (n == 0) return Fp(1);
	Fp t = power(a, n / 2);
	t = t * t; if (n & 1) t = t * a;
	return t;
}
inline const Fp& Fp::operator += (const Fp &x) { *this = *this + x; return *this; }
inline const Fp& Fp::operator -= (const Fp &x) { *this = *this - x; return *this; }
inline const Fp& Fp::operator *= (const Fp &x) { *this = *this * x; return *this; }
inline const Fp& Fp::operator /= (const Fp &x) { *this = *this / x; return *this; }
inline const bool Fp::operator == (const Fp &x) { return (this->val == x.val); }
inline const bool Fp::operator != (const Fp &x) { return (this->val != x.val); }


// calc comb (small n, r ver)
const int FACT_MAX = 510000;
static Fp fp_fact_val[FACT_MAX];

void calc_fact(int MAX = FACT_MAX) {
	fp_fact_val[0] = 1;
	for (int val = 1; val < MAX; ++val) {
		fp_fact_val[val] = fp_fact_val[val - 1] * val;
	}
}

Fp fact(int n) {
	return fp_fact_val[n];
}

Fp com(int n, int r) {
	return fact(n) / fact(r) / fact(n - r);
}

Fp com(vector<int> vec) {
	int sum = 0;
	for (int i = 0; i < vec.size(); ++i) sum += vec[i];
	Fp res = fact(sum);
	for (int i = 0; i < vec.size(); ++i) {
		res /= fact(vec[i]);
	}
	return res;
}



typedef pair<int, int> pint;
const int MAX = 510000;

int N;
map<pint, int> ma;
vector<pint> points;


vector<vector<int> > xtoy, ytox;
vector<vector<int> > G;
vector<vector<int> > nG[2];


bool seen[2][MAX];
bool visited[2][MAX];
int xnum[2][MAX], ynum[2][MAX];
int dir[2][MAX];
bool xused[2][MAX], yused[2][MAX];

vector<int> comp;

bool stop = false;

void dfs(int v, int p, int xfirst = 0) {
	//COUT(v);
	if (stop) return;
	int x = points[v].first;
	int y = points[v].second;

	// dfs
	bool detected = false;
	seen[xfirst][v] = true;
	for (auto nv : G[v]) {
		if (visited[xfirst][nv]) continue;
		if (nv == p) continue;
		if (seen[xfirst][nv]) {
			detected = true;
			continue;
		}
		dfs(nv, v, xfirst);
	}

	if (dir[xfirst][v] == -1 && xused[xfirst][x] && yused[xfirst][y]) {
		stop = true;
		return;
	}

	if (!visited[xfirst][v]) {
		//cout << v << ": " << detected << "; " << pint(xnum[xfirst][x], ynum[xfirst][y]) << ", "
		//	<< make_pair(xused[xfirst][x], yused[xfirst][y]) << "; ";


		// finished condition
		if (xnum[xfirst][x] == 1 && !xused[xfirst][x]) {
			dir[xfirst][v] = 0;
			xused[xfirst][x] = true;
		}
		if (ynum[xfirst][y] == 1 && !yused[xfirst][y]) {
			dir[xfirst][v] = 1;
			yused[xfirst][y] = true;
		}

		// alternative condition
		if (dir[xfirst][v] == -1) {
			if (yused[xfirst][y]) {
				dir[xfirst][v] = 0;
				xused[xfirst][x] = true;
			}
			else if (xused[xfirst][x]) {
				dir[xfirst][v] = 1;
				yused[xfirst][y] = true;
			}
		}

		// cycle
		if (dir[xfirst][v] == -1) {
			dir[xfirst][v] = xfirst;
			if (xfirst == 0) xused[xfirst][x] = true;
			else yused[xfirst][y] = true;
		}

		//cout << dir[xfirst][v] << ";; " << endl;

		--xnum[xfirst][x];
		--ynum[xfirst][y];
		comp.push_back(v);
		visited[xfirst][v] = true;
	}
}

void makeGraph(int xfirst = 0) {
	for (auto v : comp) {
		int x = points[v].first;
		int y = points[v].second;

		if (dir[xfirst][v] == 0) {
			for (auto ny : xtoy[x]) {
				if (ny >= y) break;
				int nv = ma[pint(x, ny)];
				nG[xfirst][v].push_back(nv);
			}
		}
		else {
			for (auto nx : ytox[y]) {
				if (nx >= x) break;
				int nv = ma[pint(nx, y)];
				nG[xfirst][v].push_back(nv);
			}
		}
	}
}

bool cmp(int a, int b) {
	int na = points[a].first + points[a].second;
	int nb = points[b].first + points[b].second;
	return (na > nb);
}

Fp dp[2][MAX];
int num[2][MAX];
Fp rec(int v, int p, int xfirst = 0) {
	num[xfirst][v] = 1;
	for (auto nv : nG[xfirst][v]) {
		if (nv == p) continue;
		rec(nv, v, xfirst);
		num[xfirst][v] += num[xfirst][nv];
	}
	Fp res = 1;
	Fp div = fact(num[xfirst][v] - 1);
	for (auto nv : nG[xfirst][v]) {
		if (nv == p) continue;
		div /= fact(num[xfirst][nv]);
		res *= dp[xfirst][nv];
	}
	res *= div;
	return dp[xfirst][v] = res;
}

Fp calc(int xfirst = 0) {
	Fp res = 1;
	Fp div = fact(comp.size());
	sort(comp.begin(), comp.end(), cmp);
	for (auto v : comp) {
		if (dp[xfirst][v] != 0) continue;
		Fp tmp = rec(v, -1, xfirst);
		res *= tmp;
		div /= fact(num[xfirst][v]);

		//cout << v << ": " << tmp << endl;
	}
	res *= div;
	return res;
}

void print(vector<vector<int> > G) {
	for (int i = 0; i < G.size(); ++i) {
		cout << i << " (" << points[i] << "): ";
		for (auto v : G[i]) {
			cout << v << ", ";
		}
		cout << endl;
	}
}

Fp solve() {
	Fp div = fact(N * 2);
	xtoy.clear();
	ytox.clear();
	xtoy = ytox = vector<vector<int> >(N);
	for (int i = 0; i < N * 2; ++i) {
		xtoy[points[i].first].push_back(points[i].second);
		ytox[points[i].second].push_back(points[i].first);
	}
	for (int i = 0; i < N; ++i) {
		sort(xtoy[i].begin(), xtoy[i].end());
		sort(ytox[i].begin(), ytox[i].end());
	}

	G = nG[0] = nG[1] = vector<vector<int> >(N * 2);
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < (int)xtoy[i].size() - 1; ++j) {
			int u = ma[pint(i, xtoy[i][j])];
			int v = ma[pint(i, xtoy[i][j + 1])];
			G[u].push_back(v);
			G[v].push_back(u);
		}
		for (int j = 0; j < (int)ytox[i].size() - 1; ++j) {
			int u = ma[pint(ytox[i][j], i)];
			int v = ma[pint(ytox[i][j + 1], i)];
			G[u].push_back(v);
			G[v].push_back(u);
		}
	}

	//print(G);

	memset(seen, 0, sizeof(seen));
	memset(visited, 0, sizeof(visited));
	memset(xnum, 0, sizeof(xnum));
	memset(ynum, 0, sizeof(ynum));
	memset(dir, -1, sizeof(dir));
	memset(dp, 0, sizeof(dp));
	memset(num, 0, sizeof(num));
	memset(xused, 0, sizeof(xused));
	memset(yused, 0, sizeof(yused));
	stop = false;
	for (int i = 0; i < N; ++i) {
		xnum[0][i] = xnum[1][i] = xtoy[i].size();
		ynum[0][i] = ynum[1][i] = ytox[i].size();
	}

	//COUT(ma);

	Fp res = 1;
	for (int i = 0; i < N * 2; ++i) {
		if (visited[0][i]) continue;
		comp.clear();
		dfs(i, -1, 0);
		if (stop) break;
		makeGraph(0);

		/*
		COUT(comp);
		COUT("nG[0]");
		for (int i = 0; i < N * 2; ++i) {
			cout << i << ": dir " << dir[0][i] << endl;
		}
		print(nG[0]);
		*/

		Fp val1 = calc(0);



		comp.clear();
		dfs(i, -1, 1);
		makeGraph(1);

		/*
		COUT("nG[1]");
		for (int i = 0; i < N * 2; ++i) {
			cout << i << ": dir " << dir[1][i] << endl;
		}
		print(nG[1]);
		*/
		Fp val2 = calc(1);




		Fp val = val1 + val2;
		res *= val;
		div /= fact(comp.size());




		//COUT(val1);
		//COUT(val2);
	}

	if (stop) return 0;

	res *= div;
	return res;
}

int main() {
	calc_fact();
	while (cin >> N) {
		ma.clear(), points.clear();
		for (int i = 0; i < N * 2; ++i) {
			int x, y;
			cin >> x >> y;
			--x, --y;
			points.push_back(pint(x, y));
			ma[pint(x, y)] = i;
		}
		cout << solve() << endl;
	}
}


Measured memory_bytes: 89840