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.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Solution {


    static MyScanner sc;
    private static PrintWriter out;
    static long M = 1000000007;


    public static void main(String[] s) throws Exception {
        StringBuilder stringBuilder = new StringBuilder();
//        stringBuilder.append("5\n" +
//                "1 10\n" +
//                "2 10\n" +
//                "3 10\n" +
//                "4 10\n" +
////                "5 5");
//        stringBuilder.append("100000 ");
//        for (int i = 0; i < 100000 ; i++) {
//            stringBuilder.append(i * 2 + 1);
//            stringBuilder.append(' ');
//            stringBuilder.append(i * 2 + 2);
//            stringBuilder.append(' ');
//        }
//            stringBuilder.append(i * 2 + 2);
//            stringBuilder.append(' ');
//            stringBuilder.append(i * 2 + 1);
//            stringBuilder.append(' ');
//        }

        if (stringBuilder.length() == 0) {
            sc = new MyScanner(System.in);
        } else {
            sc = new MyScanner(new BufferedReader(new StringReader(stringBuilder.toString())));
        }

        out = new PrintWriter(new OutputStreamWriter(System.out));

        initData();
        solve();
        out.flush();
    }

    private static void initData() {

    }

    private static void solve() {
        int n = sc.nextInt();
        int[] dest = new int[n * 2 + 1];
        int[] rev = new int[n * 2 + 1];
        int[] visited = new int[n * 2 + 1];
        Arrays.fill(visited, 2_000_000);
        List<Integer>[] from = new ArrayList[n * 2 + 1];
        for (int i = 0; i < n; i++) {
            int r = sc.nextInt();
            int t = sc.nextInt();
            if (from[t] == null) {
                from[t] = new ArrayList<>();
            }
            from[t].add(r);
            rev[t]++;
            dest[r] = t;
        }
        long res = 1;
        for (int l = 1; l < dest.length; l++) {
            if (visited[l] != 2_000_000 || dest[l] == 0) continue;
            int t = l;
            int h = dest[l];
            visited[t] = Math.min(l, visited[t]);
            visited[h] = Math.min(l, visited[h]);
            while (h != 0 && t != h && visited[h] >= l) {
                t = dest[t];
                h = dest[h];
                visited[h] = Math.min(l, visited[h]);
                h = dest[h];
                visited[h] = Math.min(l, visited[h]);
            }
            if (h != 0 && dest[h] != h && visited[h] == l) {
                res *= 2;
                res %= M;
            }
        }

        for (int l = 1; l < dest.length; l++) {
            if (from[l] != null && dest[l] == 0) {
                int read = 0;
                ArrayList<Integer> bfs = new ArrayList<>();
                bfs.addAll(from[l]);
                while (read < bfs.size()) {
                    int m = bfs.get(read++);
                    if (from[m] != null) bfs.addAll(from[m]);
                }
                res *= bfs.size() + 1;
                res %= M;
            }
        }

        out.println(res);
    }

    private static long calc(int root, List<Integer>[] from) {
        if (from[root] == null) return 1;
        long rt = 1;
        for (int i : from[root]) {
            rt += calc(i, from);
        }
        return rt % M;
    }


    private static void printa(int[] res) {
        for (int i : res) {
            out.print(i);
            out.print(' ');
        }
    }

    private static void solveT() {
        int t = sc.nextInt();
        while (t-- > 0) {
            solve();
        }
    }


    private static int gcd(int l, int l1) {
        if (l > l1) return gcd(l1, l);
        if (l == 0) return l1;
        return gcd(l1 % l, l);
    }

    private static long pow(long a, long b, long m) {
        if (b == 0) return 1;
        if (b == 1) return a;
        long pp = pow(a, b / 2, m);
        pp *= pp;
        pp %= m;
        return (pp * (b % 2 == 0 ? 1 : a)) % m;
    }

    private static void sort(int[] t, IntUnaryOperator op1, IntUnaryOperator op2) {
        sort(t, (k1, k2) -> {
            int p1 = op1.applyAsInt(k1);
            int p2 = op1.applyAsInt(k2);
            if (p1 != p2) {
                return p1 - p2;
            } else {
                return op2.applyAsInt(k1) - op2.applyAsInt(k2);
            }
        });
    }

    private static void sort(int[] t, IntBinaryOperator op) {
        List<Integer> k = Arrays.stream(t).boxed().collect(Collectors.toList());
        k.sort(op::applyAsInt);
        for (int i = 0; i < t.length; i++) {
            t[i] = k.get(i);
        }
    }

    static class MyScanner {
        BufferedReader br;
        StringTokenizer st;

        MyScanner(BufferedReader br) {
            this.br = br;
        }

        public MyScanner(InputStream in) {
            this(new BufferedReader(new InputStreamReader(in)));
        }

        void findToken() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }

        String next() {
            findToken();
            return st.nextToken();
        }

        int[] na(int n) {
            int[] k = new int[n];
            for (int i = 0; i < n; i++) {
                k[i] = sc.nextInt();
            }
            return k;
        }

        long[] nl(int n) {
            long[] k = new long[n];
            for (int i = 0; i < n; i++) {
                k[i] = sc.nextLong();
            }
            return k;
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }
    }


}