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 java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;


public class Solution {
    // VM options: -Xmx1024m -Xss1024m

    private static String inputFilename = "input.txt";
    private static String outputFilename = "output.txt";
    private BufferedReader in;
    private StringTokenizer line;
    private PrintWriter out;
    private boolean isDebug;

    public Solution(boolean isDebug) {
        this.isDebug = isDebug;
    }

    private ArrayList<Integer>[] g;
    private ArrayList<Integer>[] rg;

    public void solve() throws IOException {
        int n = nextInt();
        n = 2 * n;
        g = new ArrayList[n];
        rg = new ArrayList[n];
        for (int i = 0; i < n; i++) {
            g[i] = new ArrayList<>();
            rg[i] = new ArrayList<>();
        }
        ArrayList<Integer> toClear = new ArrayList<>();
        for (int i = 0; i < n; i += 2) {
            int t1 = nextInt() - 1;
            int t2 = nextInt() - 1;
            g[t1].add(t2);
            rg[t2].add(t1);
            if (t1 == t2) {
                toClear.add(t1);
            }
        }
        for (int v : toClear) {
            clear(v);
        }
        long mm = 1000000007;
        long res = 1;
        for (int i = 0; i < n; i++) {
            if (g[i].isEmpty()) {
                res = res * clear(i) % mm;
            }
        }
        Dsu dsu = new Dsu(n);
        for (int i = 0; i < n; i++) {
            for (int j : rg[i]) {
                if (dsu.unionSets(i, j)) {
                    res = res * 2 % mm;
                }
            }
        }


        out.println(res);
    }

    private static class Dsu {
        private int[] parent;
        private int[] rank;

        public Dsu(int n) {
            parent = new int[n];
            rank = new int[n];
            for (int i = 0; i < n; i++) {
                parent[i] = i;
                rank[i] = 1;
            }
        }

        public int findSet(int v) {
            if (v == parent[v]) {
                return v;
            }
            return parent[v] = findSet(parent[v]);
        }

        public boolean unionSets(int a, int b) {
            a = findSet(a);
            b = findSet(b);
            if (a != b) {
                if (rank[a] < rank[b]) {
                    int t = a;
                    a = b;
                    b = t;
                }
                parent[b] = a;
                rank[a] += rank[b];
                return false;
            }
            return true;
        }
    }


    private int clear(int v) {
        ArrayList<Integer> tmp = rg[v];
        rg[v] = new ArrayList<>();
        int res = 1;
        for (int nv : tmp) {
            res += clear(nv);
        }
        return res;
    }


    public static void main(String[] args) throws IOException {
        new Solution(Arrays.asList(args).contains("DEBUG_MODE")).run(args);
    }

    public void run(String[] args) throws IOException {
        if (isDebug) {
            in = new BufferedReader(new InputStreamReader(new FileInputStream(inputFilename)));
//            in = new BufferedReader(new InputStreamReader(System.in));
        } else {
            in = new BufferedReader(new InputStreamReader(System.in));
        }
        out = new PrintWriter(System.out);
//        out = new PrintWriter(outputFilename);

//        int t = nextInt();
        int t = 1;
        for (int i = 0; i < t; i++) {
//            out.print("Case #" + (i + 1) + ": ");
            solve();
        }

        in.close();
        out.flush();
        out.close();
    }

    private int[] nextIntArray(int n) throws IOException {
        int[] res = new int[n];
        for (int i = 0; i < n; i++) {
            res[i] = nextInt();
        }
        return res;
    }

    private long[] nextLongArray(int n) throws IOException {
        long[] res = new long[n];
        for (int i = 0; i < n; i++) {
            res[i] = nextLong();
        }
        return res;
    }

    private int nextInt() throws IOException {
        return Integer.parseInt(nextToken());
    }

    private long nextLong() throws IOException {
        return Long.parseLong(nextToken());
    }

    private double nextDouble() throws IOException {
        return Double.parseDouble(nextToken());
    }

    private String nextToken() throws IOException {
        while (line == null || !line.hasMoreTokens()) {
            line = new StringTokenizer(in.readLine());
        }
        return line.nextToken();
    }
}
