import java.awt.geom.*;
import java.util.*;
import java.awt.*;
import java.io.*;

public class ConvexHull {
    private class P extends Point2D.Double {
        P(double x, double y) { super(x,y); }
    }

    public static void main(String[] args) throws IOException {
        new ConvexHull().run();
    }

    public void run() throws IOException {
        ArrayList<P> hull, pts = new ArrayList<P>();
        Scanner cin = new Scanner(System.in);

        int datasets = cin.nextInt();
        for(int dataset=0; dataset < datasets; ++dataset) {
            pts.clear();
            int N = cin.nextInt();

            for(int i = 0; i < N; ++i) {
                double px = cin.nextDouble();
                double py = cin.nextDouble();
                if(i != N-1) // ignore last (dup) point
                    pts.add(new P(px,py));
            }

            hull = convexHull(pts);
            System.out.println("After sorting, convex hull is:");
            for(P pt : hull) {
                System.out.println("\t" + pt.toString());
            }

            /*
            Polygon p = new Polygon();
            for(P pt : hull) {
                p.addPoint(pt.x, pt.y);
            }
            Area a = new Area(p);
            System.out.println("Area of convex hull is: " + areaOf(a));
            // Other Area methods:
            // getBounds(), exclusiveOr, intersect, subtract, contains(P)
            */

            if(dataset != datasets -1)
                cin.nextInt(); // eat -1 delimiter
        }
    }

// Melkman's algorithm (for polylines): 38 lines
    double area( P a, P b, P c) {
        return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
    }

    public ArrayList<P> MconvexHull(ArrayList<P> v) {
        int n = v.size();
        P[] D = new P[2*n + 1];
        int bot = n-2, top = bot+3;
        D[bot] = D[top] = v.get(2);
        if(area( v.get(0), v.get(1), v.get(2) ) > 0) {
            D[bot+1] = v.get(0);
            D[bot+2] = v.get(1);
        } else {
            D[bot+1] = v.get(1);
            D[bot+2] = v.get(0);
        }

        for(int i = 3; i < n; ++i) {
            P x = v.get(i);
            if((area(D[bot], D[bot+1], x) > 0) &&
               (area(D[top-1], D[top], x) > 0) )
                    continue;

            while(area(D[bot], D[bot+1], x) <= 0)
                ++bot;
            D[--bot] = x;

            while(area(D[top-1], D[top], x) <= 0)
                --top;
            D[++top] = x;
        }

        ArrayList<P> rv = new ArrayList<P>();
        int h;
        for(h=0; h < (top-bot); ++h)
           rv.add(D[bot+h]);
        return rv;
    }

// Graham Scan, for any set of points: 53 lines
    private class PtCmp implements Comparator<P> {
        public int compare(P a, P b) {
            if(a.y < b.y) return -1;
            if(a.y > b.y) return 1;
            if(a.x < b.x) return -1;
            if(a.x > b.x) return 1;
            return 0;
        }
    }

    private class AngleCmp implements Comparator<P> {
        P p;
        AngleCmp(P pt) { p = pt; }
        public int compare(P a, P b) {
            return -DIRECTION * ccw(p, a, b); // clockwise -> right turns
        }
    }

    static final int DIRECTION = -1; // left/counterclockwise by default

    // 1 means clockwise (right turn)
    // c is on line ab, close to a: -1;  after b: 1. between = 0
    public int ccw( P a, P b, P c) {
        return Line2D.relativeCCW(a.x, a.y, b.x, b.y, c.x, c.y);
    }

    public ArrayList<P> convexHull(ArrayList<P> l) {
        P p, last, next2last;

        p = Collections.min(l, new PtCmp()); // find pivot

        l.remove(p); // remove pivot from sort
        Collections.sort(l, new AngleCmp(p));

        Stack<P> stack = new Stack<P>();
        stack.push(p); // add pivot back in the game
        stack.push(l.get(0));
        for(int i = 1; i < l.size(); ++i) {
            boolean done = false;
            while(!done && stack.size() > 1) {
                last = stack.pop();
                next2last = stack.peek();
                stack.push(last); // get top 2 elements, without disturbing stack
                // if pts are in ccw order, the "good" ones make left (-1) turns
                if(ccw(next2last, last, l.get(i)) == DIRECTION)
                      done = true;
                else  stack.pop();
            }
            stack.push(l.get(i));
        }

        return new ArrayList<P>(stack);
    }

    static double areaOf(Shape s) {
        PathIterator i = s.getPathIterator(null);
        double[] coords = new double[6];
        int r;
        double area = 0.;
        double mx, my, lx, ly, x, y;
        mx= my= lx= ly= 0.; // prevent javac complaints over un-init-ed vars
        while(!i.isDone()) {
            r = i.currentSegment(coords);
            x = coords[0]; y = coords[1];

                   if(r == PathIterator.SEG_LINETO) {
                area += (lx*y - x*ly);
            } else if(r == PathIterator.SEG_CLOSE) {
                area += (lx*my - mx*ly);
            } else if(r == PathIterator.SEG_MOVETO) {
                mx = x;
                my = y;
            }

            lx = x; ly = y;
            i.next();
        }
        return Math.abs(area/2);
    }
}
