A new set of desks just arrived, and it's about time! Things were getting quite cramped in the office. You've been put in charge of creating a new seating chart for the engineers. The desks are numbered, and you sent out a survey to the engineering team asking each engineer the number of the desk they currently sit at, and the number of the desk they would like to sit at (which may be the same as their current desk). Each engineer must either remain where they sit, or move to the desired seat they indicated in the survey. No two engineers currently sit at the same desk, nor may any two engineers sit at the same desk in the new seating arrangement.

How many seating arrangements can you create that meet the specified requirements? The answer may be very large, so compute it modulo 1000000007 = 109 + 7.

Input

Input will begin with a line containing N (1 ≤ N ≤ 100000), the number of engineers. 

N lines follow, each containing exactly two integers. The i-th line contains the number of the current desk of the i-th engineer and the number of the desk the i-th engineer wants to move to. Desks are numbered from 1 to 2·N. It is guaranteed that no two engineers sit at the same desk.

Output

Print the number of possible assignments, modulo 1000000007 = 109 + 7.

Examples

Input

4
1 5
5 2
3 7
7 3


Output

6


Input

5
1 10
2 10
3 10
4 10
5 5


Output

5

Note

These are the possible assignments for the first example: 

  * 1 5 3 7 
  * 1 2 3 7 
  * 5 2 3 7 
  * 1 5 7 3 
  * 1 2 7 3 
  * 5 2 7 3 
import static java.util.Arrays.*;

import java.math.*;
import java.util.*;

public class E {

	public E () {
		int N = sc.nextInt();
		int [][] E = dec(sc.nextInts(N));

		int [][] G = dgraph(2*N, E);
		int [] C = new int [2*N]; fill(C, -1);

		next: for (int i : rep(2*N))
			if (C[i] == -1) {
				Set<Integer> S = new TreeSet<>(); int j = i;
				while (G[j].length > 0) {
					if (C[j] != -1) {
						for (int s : S)
							C[s] = C[j];
						continue next;
					}
					if (!S.add(j)) {
						for (int s : S)
							C[s] = i;
						continue next;
					}
					j = G[j][0];
				}
				for (int s : S)
					C[s] = -2;
			}

		int [][] F = inv(E);
		int [][] H = dgraph(2*N, F);

		long res = 1;
		for (int i : rep(2*N))
			if (G[i].length == 0)
				res = mod(res * dfs(i, H));

		Set<Integer> S = new TreeSet<>(); int P = 0;
		for (int i : rep(2*N))
			if (C[i] >= 0) {
				if (S.add(C[i])) ++P;
				if (G[i][0] == i) --P;
			}

		res = mod(res * modPow(2, P));

		exit(res);
	}

	int dfs(int s, int [][] H) {
		int res = 1;
		for (int j : H[s])
			res += dfs(j, H);
		return res;
	}

	int [][] inv(int [][] E) {
		int [][] res = new int [E.length][];
		for (int i = 0; i < E.length; ++i) {
			res[i] = new int [E[i].length];
			for (int j = 0; j < E[i].length; ++j)
				res[i][j] = E[i][E[i].length - 1 - j];
		}
		return res;
	}

	private static final int INF = (int) 1e9 + 10;
	private static final int MOD = (int) 1e9 + 7;
	private static int [][] dec(int [][] E) {
		return dec(E, INF);
	}
	private static int [][] dec(int [][] E, int N) {
		for (int [] e : E)
			for (int i = 0; i < e.length && i < N; ++i)
				--e[i];
		return E;
	}
	private static int [][] dgraph (int N, int [][] E) { return dwgraph(N, E)[0]; }
	private static int [][][] dwgraph(int N, int [][] E) {
		int [] D = new int [N];
		for (int [] e : E)
			++D[e[0]];
		int [][][] res = new int [2][N][];
		for (int i = 0; i < 2; ++i)
			for (int j = 0; j < N; ++j)
				res[i][j] = new int [D[j]];
		D = new int [N];
		for (int [] e : E) {
			int x = e[0], y = e[1], z = e.length > 2 ? e[2] : 1;
			res[0][x][D[x]] = y;
			res[1][x][D[x]] = z;
			++D[x];
		}
		return res;
	}
	private static long mod(long x) { return mod(x, MOD); }
	private static long mod(long x, long mod) { return ((x % mod) + mod) % mod; }
	private static long modPow(long b, long e) { return BigInteger.valueOf(b).modPow(BigInteger.valueOf(e), BigInteger.valueOf(MOD)).longValue(); }
	private static int [] rep(int N) { return rep(0, N); }
	private static int [] rep(int S, int T) { if (T <= S) return new int [0]; int [] res = new int [T-S]; for (int i = S; i < T; ++i) res[i-S] = i; return res; }
	////////////////////////////////////////////////////////////////////////////////////
	private final static IOUtils.MyScanner sc = new IOUtils.MyScanner();
	private static void exit (Object o, Object ... A) { IOUtils.print(o, A); IOUtils.exit(); }
	private static class IOUtils {
		public static class MyScanner {
			public String next() { newLine(); return line[index++]; }
			public int nextInt() { return Integer.parseInt(next()); }
			public String nextLine() { line = null; return readLine(); }
			public String [] nextStrings() { return split(nextLine()); }
			public int [] nextInts() {
				String [] L = nextStrings();
				int [] res = new int [L.length];
				for (int i = 0; i < L.length; ++i)
					res[i] = Integer.parseInt(L[i]);
				return res;
			}
			public int [][] nextInts (int N) {
				int [][] res = new int [N][];
				for (int i = 0; i < N; ++i)
					res[i] = nextInts();
				return res;
			}
			//////////////////////////////////////////////
			private boolean eol() { return index == line.length; }
			private String readLine() {
				try {
					return r.readLine();
				} catch (Exception e) {
					throw new Error (e);
				}
			}
			private final java.io.BufferedReader r;
			private MyScanner () { this(new java.io.BufferedReader(new java.io.InputStreamReader(System.in))); }
			private MyScanner (java.io.BufferedReader r) {
				try {
					this.r = r;
					while (!r.ready())
						Thread.sleep(1);
					start();
				} catch (Exception e) {
					throw new Error(e);
				}
			}
			private String [] line;
			private int index;
			private void newLine() {
				if (line == null || eol()) {
					line = split(readLine());
					index = 0;
				}
			}
			private String [] split(String s) { return s.length() > 0 ? s.split(" ") : new String [0]; }
		}
		private static String build(Object o, Object ... A) { return buildDelim(" ", o, A); }
		private static String buildDelim(String delim, Object o, Object ... A) {
			StringBuilder b = new StringBuilder();
			append(b, o, delim);
			for (Object p : A)
				append(b, p, delim);
			return b.substring(delim.length());
		}
		//////////////////////////////////////////////////////////////////////////////////
		private static void start() { if (t == 0) t = millis(); }
		private static void append(StringBuilder b, Object o, String delim) {
			if (o.getClass().isArray()) {
				int len = java.lang.reflect.Array.getLength(o);
				for (int i = 0; i < len; ++i)
					append(b, java.lang.reflect.Array.get(o, i), delim);
			} else if (o instanceof Iterable<?>)
				for (Object p : (Iterable<?>) o)
					append(b, p, delim);
			else {
				if (o instanceof Double)
					o = new java.text.DecimalFormat("#.############").format(o);
				b.append(delim).append(o);
			}
		}
		private static java.io.PrintWriter pw = new java.io.PrintWriter(System.out);
		private static void print(Object o, Object ... A) { pw.println(build(o, A)); }
		private static void err(Object o, Object ... A) { System.err.println(build(o, A)); }
		private static void exit() {
			IOUtils.pw.close();
			System.out.flush();
			err("------------------");
			err(IOUtils.time());
			System.exit(0);
		}
		private static long t;
		private static long millis() { return System.currentTimeMillis(); }
		private static String time() { return "Time: " + (millis() - t) / 1000.0; }
	}
	public static void main (String[] args) { new E(); IOUtils.exit(); }
}