description: Lord Omkar would like to have a tree with n nodes (3 ≤ n ≤ 10^5) and has asked his disciples to construct the tree. However, Lord Omkar has created m (1 ≤ m < n) restrictions to ensure that the tree will be as heavenly as possible. 
  
  A tree with n nodes is an connected undirected graph with n nodes and n-1 edges. Note that for any two nodes, there is exactly one simple path between them, where a simple path is a path between two nodes that does not contain any node more than once.
  
  Here is an example of a tree: 
  
  <image>
  
  A restriction consists of 3 pairwise distinct integers, a, b, and c (1 ≤ a,b,c ≤ n). It signifies that node b cannot lie on the simple path between node a and node c. 
  
  Can you help Lord Omkar and become his most trusted disciple? You will need to find heavenly trees for multiple sets of restrictions. It can be shown that a heavenly tree will always exist for any set of restrictions under the given constraints.
  
  Input
  
  Each test contains multiple test cases. The first line contains the number of test cases t (1 ≤ t ≤ 10^4). Description of the test cases follows.
  
  The first line of each test case contains two integers, n and m (3 ≤ n ≤ 10^5, 1 ≤ m < n), representing the size of the tree and the number of restrictions.
  
  The i-th of the next m lines contains three integers a_i, b_i, c_i (1 ≤ a_i, b_i, c_i ≤ n, a, b, c are distinct), signifying that node b_i cannot lie on the simple path between nodes a_i and c_i. 
  
  It is guaranteed that the sum of n across all test cases will not exceed 10^5.
  
  Output
  
  For each test case, output n-1 lines representing the n-1 edges in the tree. On each line, output two integers u and v (1 ≤ u, v ≤ n, u ≠ v) signifying that there is an edge between nodes u and v. Given edges have to form a tree that satisfies Omkar's restrictions.
  
  Example
  
  Input
  
  
  2
  7 4
  1 2 3
  3 4 5
  5 6 7
  6 5 4
  5 3
  1 2 3
  2 3 4
  3 4 5
  
  
  Output
  
  
  1 2
  1 3
  3 5
  3 4
  2 7
  7 6
  5 1
  1 3
  3 2
  2 4
  
  Note
  
  The output of the first sample case corresponds to the following tree: 
  
  <image> For the first restriction, the simple path between 1 and 3 is 1, 3, which doesn't contain 2. The simple path between 3 and 5 is 3, 5, which doesn't contain 4. The simple path between 5 and 7 is 5, 3, 1, 2, 7, which doesn't contain 6. The simple path between 6 and 4 is 6, 7, 2, 1, 3, 4, which doesn't contain 5. Thus, this tree meets all of the restrictions.
  
  The output of the second sample case corresponds to the following tree: 
  
  <image>
solution: //Utilities
  import java.io.*;
  import java.util.*;
  
  public class B {
  	static int t;
  	static int n, m;
  	static int[] a, b, c;
  	static boolean[] vis;
  	static HashSet<Integer> set;
  	static DSU dsu;
  	
  	public static void main(String[] args) throws IOException {
  		t = in.iscan();
  		while (t-- > 0) {
  			run();
  		}
  		out.close();
  	} 
  	
  	static void run() throws IOException {
  		n = in.iscan(); m = in.iscan();
  		dsu = new DSU(n);
  		a = new int[m]; b = new int[m]; c = new int[m];
  		vis = new boolean[n+1];
  		for (int i = 0; i < m; i++) {
  			a[i] = in.iscan(); b[i] = in.iscan(); c[i] = in.iscan();
  			vis[b[i]] = true;
  		}
  		int con = -1;
  		for (int i = 1; i <= n; i++) {
  			if (!vis[i]) {
  				con = i;
  				break;
  			}
  		}
  		for (int i = 1; i <= n; i++) {
  			if (i == con) {
  				continue;
  			}
  			out.println(i + " " + con);
  		}
  	}
  	
  	static class DSU
  	{
  	    // I modified this dsu to include rank
  	    public int[] dsu;
  	    public int[] size;
  	    public int[] rank;
  
  	    public DSU(int N)
  	    {
  	        dsu = new int[N+1];
  	        size = new int[N+1];
  	        rank = new int[N+1];
  	        for(int i=0; i <= N; i++)
  	        {
  	            dsu[i] = i;
  	            size[i] = 1;
  	        }
  	    }
  	    //with path compression, no find by rank
  	    public int find(int x)
  	    {
  	        return dsu[x] == x ? x : (dsu[x] = find(dsu[x]));
  	    }
  	    
  	    public void merge(int x, int y, boolean sized)
  	    {
  	        int fx = find(x);
  	        int fy = find(y);
  	        if (sized){
  	            if (rank[fx] < rank[fy]){
  	                dsu[fx] = fy;   
  	                size[fy] += size[fx];
  	            }
  	            else if (rank[fx] == rank[fy]){
  	                dsu[fx] = fy;
  	                size[fy] += size[fx];
  	                rank[fy]++;
  	            }
  	            else {
  	                dsu[fy] = fx;
  	                size[fx] += size[fy];
  	            }
  	        }
  	        else {
  	            if (rank[fx] < rank[fy]){
  	                dsu[fx] = fy;   
  	            }
  	            else if (rank[fx] == rank[fy]){
  	                dsu[fx] = fy;
  	                rank[fy]++;
  	            }
  	            else {
  	                dsu[fy] = fx;
  	            }
  	        }
  	    }
  	}
  	
  	static INPUT in = new INPUT(System.in);
  	static PrintWriter out = new PrintWriter(System.out);
  	private static class INPUT {
  
  		private InputStream stream;
  		private byte[] buf = new byte[1024];
  		private int curChar, numChars;
  
  		public INPUT (InputStream stream) {
  			this.stream = stream;
  		}
  
  		public INPUT (String file) throws IOException {
  			this.stream = new FileInputStream (file);
  		}
  
  		public int cscan () throws IOException {
  			if (curChar >= numChars) {
  				curChar = 0;
  				numChars = stream.read (buf);
  			}
  			
  			if (numChars == -1)
  				return numChars;
  
  			return buf[curChar++];
  		}
  
  		public int iscan () throws IOException {
  			int c = cscan (), sgn = 1;
  			
  			while (space (c))
  				c = cscan ();
  
  			if (c == '-') {
  				sgn = -1;
  				c = cscan ();
  			}
  
  			int res = 0;
  
  			do {
  				res = (res << 1) + (res << 3);
  				res += c - '0';
  				c = cscan ();
  			}
  			while (!space (c));
  
  			return res * sgn;
  		}
  
  		public String sscan () throws IOException {
  			int c = cscan ();
  			
  			while (space (c))
  				c = cscan ();
  
  			StringBuilder res = new StringBuilder ();
  
  			do {
  				res.appendCodePoint (c);
  				c = cscan ();
  			}
  			while (!space (c));
  
  			return res.toString ();
  		}
  
  		public double dscan () throws IOException {
  			int c = cscan (), sgn = 1;
  			
  			while (space (c))
  				c = cscan ();
  
  			if (c == '-') {
  				sgn = -1;
  				c = cscan ();
  			}
  
  			double res = 0;
  
  			while (!space (c) && c != '.') {
  				if (c == 'e' || c == 'E')
  					return res * UTILITIES.fast_pow (10, iscan ());
  				
  				res *= 10;
  				res += c - '0';
  				c = cscan ();
  			}
  
  			if (c == '.') {
  				c = cscan ();
  				double m = 1;
  
  				while (!space (c)) {
  					if (c == 'e' || c == 'E')
  						return res * UTILITIES.fast_pow (10, iscan ());
  
  					m /= 10;
  					res += (c - '0') * m;
  					c = cscan ();
  				}
  			}
  
  			return res * sgn;
  		}
  
  		public long lscan () throws IOException {
  			int c = cscan (), sgn = 1;
  			
  			while (space (c))
  				c = cscan ();
  
  			if (c == '-') {
  				sgn = -1;
  				c = cscan ();
  			}
  
  			long res = 0;
  
  			do {
  				res = (res << 1) + (res << 3);
  				res += c - '0';
  				c = cscan ();
  			}
  			while (!space (c));
  
  			return res * sgn;
  		}
  
  		public boolean space (int c) {
  			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
  		}
  	}
  
  	public static class UTILITIES {
  
  		static final double EPS = 10e-6;
  		
  		public static void sort(int[] a, boolean increasing) {
  			ArrayList<Integer> arr = new ArrayList<Integer>();
  			int n = a.length;
  			for (int i = 0; i < n; i++) {
  				arr.add(a[i]);
  			}
  			Collections.sort(arr);
  			for (int i = 0; i < n; i++) {
  				if (increasing) {
  					a[i] = arr.get(i);
  				}
  				else {
  					a[i] = arr.get(n-1-i);
  				}
  			}
  		}
  		
  		public static void sort(long[] a, boolean increasing) {
  			ArrayList<Long> arr = new ArrayList<Long>();
  			int n = a.length;
  			for (int i = 0; i < n; i++) {
  				arr.add(a[i]);
  			}
  			Collections.sort(arr);
  			for (int i = 0; i < n; i++) {
  				if (increasing) {
  					a[i] = arr.get(i);
  				}
  				else {
  					a[i] = arr.get(n-1-i);
  				}
  			}
  		}
  		
  		public static void sort(double[] a, boolean increasing) {
  			ArrayList<Double> arr = new ArrayList<Double>();
  			int n = a.length;
  			for (int i = 0; i < n; i++) {
  				arr.add(a[i]);
  			}
  			Collections.sort(arr);
  			for (int i = 0; i < n; i++) {
  				if (increasing) {
  					a[i] = arr.get(i);
  				}
  				else {
  					a[i] = arr.get(n-1-i);
  				}
  			}
  		}
  
  		public static int lower_bound (int[] arr, int x) {
  			int low = 0, high = arr.length, mid = -1;
  
  			while (low < high) {
  				mid = (low + high) / 2;
  
  				if (arr[mid] >= x)
  					high = mid;
  				else
  					low = mid + 1;
  			}
  
  			return low;
  		}
  
  		public static int upper_bound (int[] arr, int x) {
  			int low = 0, high = arr.length, mid = -1;
  
  			while (low < high) {
  				mid = (low + high) / 2;
  
  				if (arr[mid] > x)
  					high = mid;
  				else
  					low = mid + 1;
  			}
  
  			return low;
  		}
  		
  		public static void updateMap(HashMap<Integer, Integer> map, int key, int v) {
  			if (!map.containsKey(key)) {
  				map.put(key, v);
  			}
  			else {
  				map.put(key, map.get(key) + v);
  			}
  			if (map.get(key) == 0) {
  				map.remove(key);
  			}
  		}
  
  		public static long gcd (long a, long b) {
  			return b == 0 ? a : gcd (b, a % b);
  		}
  
  		public static long lcm (long a, long b) {
  			return a * b / gcd (a, b);
  		}
  
  		public static long fast_pow_mod (long b, long x, int mod) {
  			if (x == 0) return 1;
  			if (x == 1) return b;
  			if (x % 2 == 0) return fast_pow_mod (b * b % mod, x / 2, mod) % mod;
  
  			return b * fast_pow_mod (b * b % mod, x / 2, mod) % mod;
  		}
  
  		public static int fast_pow (int b, int x) {
  			if (x == 0) return 1;
  			if (x == 1) return b;
  			if (x % 2 == 0) return fast_pow (b * b, x / 2);
  
  			return b * fast_pow (b * b, x / 2);
  		}
  
  		public static long choose (long n, long k) {
  			k = Math.min (k, n - k);
  			long val = 1;
  
  			for (int i = 0; i < k; ++i)
  				val = val * (n - i) / (i + 1);
  
  			return val;
  		}
  
  		public static long permute (int n, int k) {
  			if (n < k) return 0;
  			long val = 1;
  
  			for (int i = 0; i < k; ++i)
  				val = (val * (n - i));
  
  			return val;
  		}
  		
  		// start of permutation and lower/upper bound template
  		public static void nextPermutation(int[] nums) {
  		    //find first decreasing digit
  		    int mark = -1;
  		    for (int i = nums.length - 1; i > 0; i--) {
  		        if (nums[i] > nums[i - 1]) {
  		            mark = i - 1;
  		            break;
  		        }
  		    }
  		 
  		    if (mark == -1) {
  		        reverse(nums, 0, nums.length - 1);
  		        return;
  		    }
  		 
  		    int idx = nums.length-1;
  		    for (int i = nums.length-1; i >= mark+1; i--) {
  		        if (nums[i] > nums[mark]) {
  		            idx = i;
  		            break;
  		        }
  		    }
  		 
  		    swap(nums, mark, idx);
  		 
  		    reverse(nums, mark + 1, nums.length - 1);
  		}
  		 
  		public static void swap(int[] nums, int i, int j) {
  		    int t = nums[i];
  		    nums[i] = nums[j];
  		    nums[j] = t;
  		}
  		 
  		public static void reverse(int[] nums, int i, int j) {
  		    while (i < j) {
  		        swap(nums, i, j);
  		        i++;
  		        j--;
  		    }
  		}
  		
  		static int lower_bound (int[] arr, int hi, int cmp) {
  			int low = 0, high = hi, mid = -1;
  			while (low < high) {
  				mid = (low + high) / 2;
  				if (arr[mid] >= cmp) high = mid;
  				else low = mid + 1;
  			}
  			return low;
  		}
  	 
  		static int upper_bound (int[] arr, int hi, int cmp) {
  			int low = 0, high = hi, mid = -1;
  			while (low < high) {
  				mid = (low + high) / 2;
  				if (arr[mid] > cmp) high = mid;
  				else low = mid + 1;
  			}
  			return low;
  		}
  		// end of permutation and lower/upper bound template
  	}
  }