Monocarp is the coach of the Berland State University programming teams. He decided to compose a problemset for a training session for his teams.

Monocarp has n problems that none of his students have seen yet. The i-th problem has a topic a_i (an integer from 1 to n) and a difficulty b_i (an integer from 1 to n). All problems are different, that is, there are no two tasks that have the same topic and difficulty at the same time.

Monocarp decided to select exactly 3 problems from n problems for the problemset. The problems should satisfy at least one of two conditions (possibly, both):

  * the topics of all three selected problems are different; 
  * the difficulties of all three selected problems are different. 



Your task is to determine the number of ways to select three problems for the problemset.

Input

The first line contains a single integer t (1 ≤ t ≤ 50000) — the number of testcases.

The first line of each testcase contains an integer n (3 ≤ n ≤ 2 ⋅ 10^5) — the number of problems that Monocarp have.

In the i-th of the following n lines, there are two integers a_i and b_i (1 ≤ a_i, b_i ≤ n) — the topic and the difficulty of the i-th problem.

It is guaranteed that there are no two problems that have the same topic and difficulty at the same time.

The sum of n over all testcases doesn't exceed 2 ⋅ 10^5.

Output

Print the number of ways to select three training problems that meet either of the requirements described in the statement.

Example

Input


2
4
2 4
3 4
2 1
1 3
5
1 5
2 4
3 3
4 2
5 1


Output


3
10

Note

In the first example, you can take the following sets of three problems:

  * problems 1, 2, 4; 
  * problems 1, 3, 4; 
  * problems 2, 3, 4. 



Thus, the number of ways is equal to three.
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter; // System.out is a PrintStream
import java.util.HashMap;
import java.util.InputMismatchException;


public class D {
    private static int MOD = (int)1e9 + 7, mod = 99_82_44_353;
    private static double PI = 3.14159265358979323846;

    public static void main(String[] args) throws IOException {
        FasterScanner scn = new FasterScanner();
        PrintWriter out = new PrintWriter(System.out);
        for (int tc = scn.nextInt(); tc > 0; tc--) {
            int N = scn.nextInt();
            int[][] arr = new int[N][2];
            HashMap<Integer, Integer> x = new HashMap<>(), y = new HashMap<>();
            for (int i = 0; i < N; i++) {
                arr[i][0] = scn.nextInt();
                arr[i][1] = scn.nextInt();
                x.put(arr[i][0], x.getOrDefault(arr[i][0], 0) + 1);
                y.put(arr[i][1], y.getOrDefault(arr[i][1], 0) + 1);
            }
            long ans = 1L * N * (N - 1) * (N - 2) / 6L;
            for (int i = 0; i < N; i++) {
                ans -= 1L * (x.get(arr[i][0]) - 1) * (y.get(arr[i][1]) - 1);
            }
            out.println(ans);
        }
        out.close();
    }

    /* ------------------- Sorting ------------------- */
    private static void ruffleSort(int[] arr) {
        // int N = arr.length;
        // Random rand = new Random();
        // for (int i = 0; i < N; i++) {
        //     int oi = rand.nextInt(N), temp = arr[i];
        //     arr[i] = arr[oi];
        //     arr[oi] = temp;
        // }
        // Arrays.sort(arr);
    }
        
    /* ------------------- Sorting ------------------- */
    
    private static boolean isPalindrome(String str) {
        for (int i = 0, j = str.length() - 1; i < j; i++, j--) {
            if (str.charAt(i) != str.charAt(j)) {
                return false;
            }
        }
        return true;
    }
    
    private static boolean isPalindrome(char[] str) {
        for (int i = 0, j = str.length - 1; i < j; i++, j--) {
            if (str[i] != str[j]) {
                return false;
            }
        }
        return true;
    }
    
    /* ------------------- Pair class ------------------- */
    private static class Pair implements Comparable<Pair> {
		int x, y;
		Pair(int x, int y) {
			this.x = x;
			this.y = y;
		}
		public int compareTo(Pair o) {
			return this.x == o.x ? this.y - o.y : this.x - o.x;
		}
	}

    /* ------------------- HCF and LCM ------------------- */
    private static int gcd(int num1, int num2) {
        int temp = 0;
        while (num2 != 0) {
            temp = num1;
            num1 = num2;
            num2 = temp % num2;
        }
        return num1;
    }
    
    private static int lcm(int num1, int num2) {
        return (int)((1L * num1 * num2) / gcd(num1, num2));
    }
    
    /* ------------------- primes and prime factorization ------------------- */
    private static boolean[] seive(int N) {
        // true means not prime, false means is a prime number :)
        boolean[] notPrimes = new boolean[N + 1];
        notPrimes[0] = notPrimes[1] = true;
        for (int i = 2; i * i <= N; i++) {
            if (notPrimes[i]) continue;
            for (int j = i * i; j <= N; j += i) {
                notPrimes[j] = true;
            }
        }
        return notPrimes;
    }

	/*
    private static TreeMap<Integer, Integer> primeFactors(long N) {
		TreeMap<Integer, Integer> primeFact = new TreeMap<>();
		for (int i = 2; i <= Math.sqrt(N); i++) {
            int count = 0;
            while (N % i == 0) {
                N /= i;
                count++;
            }
            if (count != 0) {
                primeFact.put(i, count);
            }
		}
		if (N != 1) {
            primeFact.put((int)N, 1);
        }
		return primeFact;
	}
    */

    /* ------------------- Binary Search ------------------- */
    private static long factorial(int N) {
        long ans = 1L;
        for (int i = 2; i <= N; i++) {
            ans *= i;
        }
        return ans;
    }

    private static long[] factorialDP(int N) {
        long[] factDP = new long[N + 1];
        factDP[0] = factDP[1] = 1;
        for (int i = 2; i <= N; i++) {
            factDP[i] = factDP[i - 1] * i;
        }
        return factDP;
    }

    private static long factorialMod(int N, int mod) {
        long ans = 1L;
        for (int i = 2; i <= N; i++) {
            ans = ((ans % mod) * (i % mod)) % mod;
        }
        return ans;
    }

    /* ------------------- Binary Search ------------------- */
    private static int floorSearch(int[] arr, int st, int ed, int tar) {
        int ans = -1;
        while (st <= ed) {
            int mid = ((ed - st) >> 1) + st;
            if (arr[mid] <= tar) {
                ans = mid;
                st = mid + 1;
            } else {
                ed = mid - 1;
            }
        }
        return ans;
    }
    
    private static int ceilingSearch(int[] arr, int st, int ed, int tar) {
        int ans = -1;
        while (st <= ed) {
            int mid = ((ed - st) >> 1) + st;
            if (arr[mid] < tar) {
                st = mid + 1;
            } else {
                ans = mid;
                ed = mid - 1;
            }
        }
        return ans;
    }
    
    /* ------------------- Power Function ------------------- */
    public static long pow(long x, long y) {
        long res = 1;
		while (y > 0) {
            if ((y & 1) != 0) {
                res = (res * x);
				y--;
			}
			x = (x * x);
			y >>= 1;
		}
		return res;
	}
    
	public static long powMod(long x, long y, int mod) {
        long res = 1;
		while (y > 0) {
            if ((y & 1) != 0) {
                res = (res * x) % mod;
				y--;
			}
			x = (x * x) % mod;
			y >>= 1;
		}
		return res % mod;
	}

    /* ------------------- Disjoint Set(Union and Find) ------------------- */
    private static class DSU {
		public int[] parent, rank;
		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 find(int a) {
			if (parent[a] == a) {
				return a;
            }
            return parent[a] = find(parent[a]);
		}
		public boolean union(int a, int b) {
			int parA = find(a), parB = find(b);
			if (parA == parB) return false;
			if (rank[parA] > rank[parB]) {
                parent[parB] = parA;
            } else if (rank[parA] < rank[parB]) {
                parent[parA] = parB;
            } else {
                parent[parA] = parB;
                rank[parB]++;
            }
            return true;
		}
	}
    
    /* ------------------- Scanner class for input ------------------- */
    
    private static class FasterScanner {
		private InputStream stream;
		private byte[] buffer = new byte[1024];
		private int curChar, numChars;
		private SpaceCharFilter filter;

		public FasterScanner() {
            // default
			this.stream = System.in;
		}

		public FasterScanner(InputStream stream) {
			this.stream = stream;
		}

		private int readChar() {
			if (numChars == -1) {
				throw new InputMismatchException();
            }
			if (curChar >= numChars) {
				curChar = 0;
				try {
					numChars = stream.read(buffer);
				} catch (IOException e) {
					throw new InputMismatchException(e.getMessage());
				}
				if (numChars <= 0) {
					return -1;
                }
			}
			return buffer[curChar++];
		}

		private boolean isWhiteSpace(int c) {
			if (filter != null) {
				return filter.isWhiteSpace(c);
            }
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		private boolean isNewLine(int ch) {
			if (filter != null) {
				return filter.isNewLine(ch);
            }
			return ch == '\r' || ch == '\n' || ch == -1;
		}

        public char nextChar() {
            int ch = readChar();
            char res = '\0';
            while (isWhiteSpace(ch)) {
                ch = readChar();
            }
            do {
                res = (char)ch;
                ch = readChar();
            } while (!isWhiteSpace(ch));
            return res;
        }

		public String next() {
			int ch = readChar();
            StringBuilder res = new StringBuilder();
			while (isWhiteSpace(ch)) {
				ch = readChar();
            }
			do {
				res.appendCodePoint(ch);
				ch = readChar();
			} while (!isWhiteSpace(ch));
			return res.toString();
		}

		public String nextLine() {
			int ch = readChar();
            StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(ch);
				ch = readChar();
			} while (!isNewLine(ch));
			return res.toString();
		}

		public int nextInt() {
			int ch = -1, sgn = 1, res = 0;
            do {
                ch = readChar();
            } while (isWhiteSpace(ch));
			if (ch == '-') {
				sgn = -1;
				ch = readChar();
			}
			do {
				if (ch < '0' || ch > '9') {
					throw new InputMismatchException("not a number");
                }
				res = (res * 10) + (ch - '0');
				ch = readChar();
			} while (!isWhiteSpace(ch));
            
			return res * sgn;
		}

		public long nextLong() {
			int ch = -1, sgn = 1;
            long res = 0L;
            do {
                ch = readChar();
            } while (isWhiteSpace(ch));
			if (ch == '-') {
				sgn = -1;
				ch = readChar();
			}
			do {
				if (ch < '0' || ch > '9') {
					throw new InputMismatchException("not a number");
                }
				res = (10L * res) + (ch - '0');
				ch = readChar();
			} while (!isWhiteSpace(ch));

			return 1L * res * sgn;
		}

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

        /* for custom delimiters */
		public interface SpaceCharFilter {
			public boolean isWhiteSpace(int ch);
			public boolean isNewLine(int ch);
		}
	}
}
