description: Vlad has n friends, for each of whom he wants to buy one gift for the New Year.
  
  There are m shops in the city, in each of which he can buy a gift for any of his friends. If the j-th friend (1 ≤ j ≤ n) receives a gift bought in the shop with the number i (1 ≤ i ≤ m), then the friend receives p_{ij} units of joy. The rectangular table p_{ij} is given in the input.
  
  Vlad has time to visit at most n-1 shops (where n is the number of friends). He chooses which shops he will visit and for which friends he will buy gifts in each of them.
  
  Let the j-th friend receive a_j units of joy from Vlad's gift. Let's find the value α=min\\{a_1, a_2, ..., a_n\}. Vlad's goal is to buy gifts so that the value of α is as large as possible. In other words, Vlad wants to maximize the minimum of the joys of his friends.
  
  For example, let m = 2, n = 2. Let the joy from the gifts that we can buy in the first shop: p_{11} = 1, p_{12}=2, in the second shop: p_{21} = 3, p_{22}=4.
  
  Then it is enough for Vlad to go only to the second shop and buy a gift for the first friend, bringing joy 3, and for the second — bringing joy 4. In this case, the value α will be equal to min\{3, 4\} = 3
  
  Help Vlad choose gifts for his friends so that the value of α is as high as possible. Please note that each friend must receive one gift. Vlad can visit at most n-1 shops (where n is the number of friends). In the shop, he can buy any number of gifts.
  
  Input
  
  The first line of the input contains an integer t (1 ≤ t ≤ 10^4) — the number of test cases in the input.
  
  An empty line is written before each test case. Then there is a line containing integers m and n (2 ≤ n, 2 ≤ n ⋅ m ≤ 10^5) separated by a space — the number of shops and the number of friends, where n ⋅ m is the product of n and m.
  
  Then m lines follow, each containing n numbers. The number in the i-th row of the j-th column p_{ij} (1 ≤ p_{ij} ≤ 10^9) is the joy of the product intended for friend number j in shop number i.
  
  It is guaranteed that the sum of the values n ⋅ m over all test cases in the test does not exceed 10^5.
  
  Output
  
  Print t lines, each line must contain the answer to the corresponding test case — the maximum possible value of α, where α is the minimum of the joys from a gift for all of Vlad's friends.
  
  Example
  
  Input
  
  
  5
  
  2 2
  1 2
  3 4
  
  4 3
  1 3 1
  3 1 1
  1 2 2
  1 1 3
  
  2 3
  5 3 4
  2 5 1
  
  4 2
  7 9
  8 1
  9 6
  10 8
  
  2 4
  6 5 2 1
  7 9 7 2
  
  
  Output
  
  
  3
  2
  4
  8
  2
solution: import java.io.OutputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.PrintWriter;
  import java.io.PrintStream;
  import java.util.Arrays;
  import java.util.Random;
  import java.util.ArrayList;
  import java.util.AbstractCollection;
  import java.io.InputStream;
  
  /**
   * Built using CHelper plug-in
   * Actual solution is at the top
   *
   * @author sarthakmanna
   */
  public class Main {
      public static void main(String[] args) {
          InputStream inputStream = System.in;
          OutputStream outputStream = System.out;
          FastReader in = new FastReader(inputStream);
          PrintWriter out = new PrintWriter(outputStream);
          DNewYearsProblem solver = new DNewYearsProblem();
          int testCount = Integer.parseInt(in.next());
          for (int i = 1; i <= testCount; i++)
              solver.solve(i, in, out);
          out.close();
      }
  
      static class DNewYearsProblem {
          final static Helper hp = new Helper();
          int N;
          int M;
          int[][] P;
          static int donno;
  
          public void fillInputParams(FastReader in) {
              N = in.nextInt();
              M = in.nextInt();
              P = new int[N][];
              for (int i = 0; i < N; ++i) P[i] = in.getIntArray(M);
          }
  
          Object solveOptimised(FastReader in) {
              long[] maxHappiness = new long[M];
              for (int j = 0; j < M; ++j) {
                  int max = 0;
                  for (int i = 0; i < N; ++i) max = Math.max(max, P[i][j]);
                  maxHappiness[j] = max;
              }
              if (N < M) return hp.min(maxHappiness);
  
              SegmentTree segT = new SegmentTree(maxHappiness, Integer.MAX_VALUE, 0) {
  
                  public long nodeToNode(long a, long b) {
                      return Math.min(a, b);
                  }
              };
  
              long ans = 0;
              for (int i = 0; i < N; ++i) {
                  donno = i;
                  Integer[] indexes = hp.getIndexArrayInteger(M);
                  Arrays.sort(indexes, (a, b) -> Integer.compare(P[donno][a], P[donno][b]));
  
                  long temp = P[i][indexes[M - 2]];
                  int a = indexes[M - 1], b = indexes[M - 2];
                  if (a > b) {
                      a ^= b;
                      b ^= a;
                      a ^= b;
                  }
                  temp = hp.min(temp, segT.rangeQuery(0, a - 1), segT.rangeQuery(a + 1, b - 1), segT.rangeQuery(b + 1, N));
  
                  ans = Math.max(ans, temp);
              }
              return ans;
          }
  
          Object solveBrute(FastReader in) {
              return null;
          }
  
          public void solve(int testNumber, FastReader in, PrintWriter out) {
              // out.print("Case #" + testNumber + ": ");
  
              fillInputParams(in);
              Object outOptimised = solveOptimised(in);
              Object outBrute = solveBrute(in);
              if (outBrute == null) {
                  out.println(outOptimised);
              } else if (outBrute.toString().equals(outOptimised.toString())) {
                  System.out.println(testNumber + ". OK Checked");
              } else {
                  // print input params
                  System.err.println("Actual = " + outOptimised);
                  System.err.println("Expected = " + outBrute);
                  System.out.println();
                  throw new ArithmeticException();
              }
          }
  
      }
  
      static class Helper {
          public final long MOD;
          public final int MAXN;
          final Random rnd;
  
          public Helper() {
              MOD = 1000_000_007;
              MAXN = 1000_006;
              rnd = new Random();
          }
  
          public Helper(long mod, int maxn) {
              MOD = mod;
              MAXN = maxn;
              rnd = new Random();
          }
  
          public long min(long... ar) {
              long ret = ar[0];
              for (long itr : ar) ret = Math.min(ret, itr);
              return ret;
          }
  
          public Integer[] getIndexArrayInteger(int size) {
              Integer[] ret = new Integer[size];
              for (int i = 0; i < size; ++i) ret[i] = i;
              return ret;
          }
  
      }
  
      static class SegmentTree {
          private int N;
          private long[] tree;
          private long[] lazy;
          public final long DEFAULT_NODE;
          public final long DEFAULT_LAZY;
  
          public SegmentTree(long[] ar, long def_node, long def_lazy) {
              DEFAULT_NODE = def_node;
              DEFAULT_LAZY = def_lazy;
              N = 1;
              while (N < ar.length) N <<= 1;
              tree = new long[N << 1];
              Arrays.fill(tree, DEFAULT_NODE);
              lazy = new long[N << 1];
              Arrays.fill(lazy, DEFAULT_LAZY);
  
              for (int i = 0; i < ar.length; ++i) tree[i + N] = ar[i];
              for (int i = N - 1; i > 0; --i) {
                  tree[i] = nodeToNode(tree[i << 1], tree[i << 1 | 1]);
              }
          }
  
          public long nodeToNode(long a, long b) {
              return a + b;
          }
  
          public long lazyToLazy(long a, long b) {
              return a + b;
          }
  
          public long lazyToNode(long nv, long lv, int l, int r) {
              return nv + lv * (r - l + 1);
          }
  
          public void pushDown(int i, int l, int r) {
              tree[i] = lazyToNode(tree[i], lazy[i], l, r);
              if (i << 1 < tree.length) {
                  lazy[i << 1] = lazyToLazy(lazy[i << 1], lazy[i]);
                  lazy[i << 1 | 1] = lazyToLazy(lazy[i << 1 | 1], lazy[i]);
              }
              lazy[i] = DEFAULT_LAZY;
          }
  
          public long rangeQuery(int l, int r) {
              return query(1, 0, N - 1, l, r);
          }
  
          private long query(int i, int l, int r, int ql, int qr) {
              pushDown(i, l, r);
              int mid = l + r >> 1, i2 = i << 1;
              if (l > qr || r < ql) return DEFAULT_NODE;
              else if (l >= ql && r <= qr) return tree[i];
              else {
                  return nodeToNode(query(i2, l, mid, ql, qr),
                          query(i2 | 1, mid + 1, r, ql, qr));
              }
          }
  
          public String toString() {
              ArrayList<Long> toStr = new ArrayList<>();
              for (int i = 0; i < N; ++i) toStr.add(rangeQuery(i, i));
              return toStr.toString();
          }
  
      }
  
      static class FastReader {
          static final int BUFSIZE = 1 << 20;
          static byte[] buf;
          static int index;
          static int total;
          static InputStream in;
  
          public FastReader(InputStream is) {
              try {
                  in = is;
                  buf = new byte[BUFSIZE];
              } catch (Exception e) {
              }
          }
  
          private int scan() {
              try {
                  if (index >= total) {
                      index = 0;
                      total = in.read(buf);
                      if (total <= 0)
                          return -1;
                  }
                  return buf[index++];
              } catch (Exception | Error e) {
                  System.err.println(e.getMessage());
                  return 13 / 0;
              }
          }
  
          public String next() {
              int c;
              for (c = scan(); c <= 32; c = scan()) ;
              StringBuilder sb = new StringBuilder();
              for (; c > 32; c = scan())
                  sb.append((char) c);
              return sb.toString();
          }
  
          public int nextInt() {
              int c, val = 0;
              for (c = scan(); c <= 32; c = scan()) ;
              boolean neg = c == '-';
              if (c == '-' || c == '+')
                  c = scan();
              for (; c >= '0' && c <= '9'; c = scan())
                  val = (val << 3) + (val << 1) + (c & 15);
              return neg ? -val : val;
          }
  
          public int[] getIntArray(int size) {
              int[] ar = new int[size];
              for (int i = 0; i < size; ++i) ar[i] = nextInt();
              return ar;
          }
  
      }
  }
  
  