import java.io.*;
import java.util.*;

public class gen_guard {

	static String testsPath = "../tests";
	static boolean STRESS_MODE;
	final int MAX_C = 10000;
	final int MAX_N = 100;

	public void solve() throws IOException {
		 if (STRESS_MODE) {
			 rand = new Random(System.nanoTime());
			 if (rand.nextBoolean()) {
				 writeTest(scale(getRandomTest(100, 200, UniformPointGenerator.impl())));
			 } else {
				 writeTest(getRandomTest(10, 20, UniformPointGenerator.impl()));
			 }
			 return;
		 }
		writeTest(toList(new int[][] { { 0, 0 }, { 0, 1 }, { 1, 0 } }));
		writeTest(toList(new int[][] { { 0, 1 }, { 0, 3 }, { 1, 4 }, { 4, 4 },
				{ 5, 3 }, { 4, 2 }, { 3, 3 }, { 2, 3 }, { 1, 2 }, { 2, 1 },
				{ 3, 2 }, { 4, 1 }, { 5, 2 }, { 6, 1 }, { 5, 0 }, { 1, 0 } }));
		writeTest(toList(new int[][] { { 0, 1 }, { 0, 3 }, { 1, 4 }, { 4, 4 },
				{ 5, 3 }, { 4, 2 }, { 3, 3 }, { 2, 3 }, { 2, 1 },
				{ 3, 2 }, { 4, 1 }, { 5, 2 }, { 6, 1 }, { 5, 0 }, { 1, 0 } }));
		writeTest(toList(new int[][]{{-MAX_C, -MAX_C}, {-MAX_C, MAX_C}, {MAX_C, MAX_C}, {MAX_C, -MAX_C}}));
		writeTest(toList(new int[][] { { 0, 0 }, { 0, 2 }, { 1, 2 }, { 1, 1 },
				{ 2, 1 }, { 2, 3 }, { 0, 3 }, { 0, 4 }, { 3, 4 }, { 3, 0 } }));
		writeTest(toList(new int[][] { { 0, 0 }, { 0, 4 }, { 5, 4 }, { 5, 0 },
				{ 2, 0 }, { 2, 2 }, { 3, 2 }, { 3, 1 }, { 4, 1 }, { 4, 3 },
				{ 1, 3 }, { 1, 0 } }));
		writeTest(toList(new int[][] { { 0, 0 }, { 0, 5 }, { 6, 5 }, { 6, 0 },
				{ 5, 0 }, { 5, 3 }, { 3, 3 }, { 5, 4 }, { 1, 4 }, { 2, 3 },
				{ 1, 3 }, { 1, 1 }, { 2, 1 }, { 2, 2 }, { 3, 2 }, { 4, 1 },
				{ 4, 0 } }));
		writeTest(shift(getTest1(10)));
		writeTest(shift(getTest1(24)));
		writeTest(toList(new int[][] { { 0, 0 }, { 0, 4 }, { 6, 4 }, { 6, 0 },
				{ 3, 0 }, { 5, 1 }, { 4, 1 }, { 5, 2 }, { 3, 2 }, { 5, 3 },
				{ 1, 3 }, { 2, 2 }, { 1, 2 }, { 3, 1 }, { 1, 1 }, { 2, 0 } }));
		writeTest(toList(new int[][] { { 0, 0 }, { 0, 4 }, { 6, 4 }, { 6, 2 },
				{ 5, 3 }, { 1, 3 }, { 1, 1 }, { 2, 1 }, { 2, 2 }, { 3, 2 },
				{ 3, 1 }, { 4, 1 }, { 4, 2 }, { 5, 2 }, { 6, 1 }, { 6, 0 } }));
		writeTest(scale(shift(getTest1(3))));
		writeTest(scale(shift(getTest1(24))));
		writeTest(shift(toList(new int[][] { { -MAX_C, 0 }, { -MAX_C, 3 },
				{ MAX_C - 1, 2 }, { -MAX_C + 1, 2 }, { -MAX_C + 1, 1 },
				{ MAX_C, 2 } })));
		writeTest(shift(toList(new int[][] { { -MAX_C, 0 }, { -MAX_C, 4 },
				{-1, 4}, { -1, 2 }, {-2, 3}, { -MAX_C + 1, 3 }, { -MAX_C + 1, 1 },
				{ MAX_C - 2, 3 } })));
		writeTest(shift(toList(new int[][] { { -MAX_C, -1 }, { -MAX_C, 4 },
				{-1, 4}, { -1, 2 }, {-2, 3}, { -MAX_C + 1, 3 }, { -MAX_C + 1, 0 }, { -MAX_C + 2, 1 },
				{ MAX_C - 3, 3 } })));
		writeTest(shift(toList(new int[][] { { -MAX_C, -1 }, { -MAX_C, 4 },
				{-1, 4}, { -1, 2 }, {-2, 3}, { -MAX_C + 1, 3 }, { -MAX_C + 1, 0 }, { -MAX_C + 2, 1 }, { 0, 1 },
				{ MAX_C - 3, 3 }, { MAX_C - 3, -1 } })));
		writeTest(getRandomTest(10, 20, UniformPointGenerator.impl()));
		writeTest(getRandomTest(10, 10, UniformPointGenerator.impl()));
		writeTest(getRandomTest(20, 30, UniformPointGenerator.impl()));
		writeTest(getRandomTest(20, 30, UniformPointGenerator.impl()));
		writeTest(scale(getRandomTest(20, 30, UniformPointGenerator.impl())));
		writeTest(scale(getRandomTest(20, 30, UniformPointGenerator.impl())));
		writeTest(getRandomTest(50, 50, UniformPointGenerator.impl()));
		writeTest(getRandomTest(50, 50, UniformPointGenerator.impl()));
		writeTest(scale(getRandomTest(50, 50, UniformPointGenerator.impl())));
		writeTest(scale(getRandomTest(50, 30, UniformPointGenerator.impl())));		
		writeTest(getRandomTest(100, 1000, UniformPointGenerator.impl()));
		writeTest(getRandomTest(100, 500, UniformPointGenerator.impl()));
		writeTest(getRandomTest(100, 200, UniformPointGenerator.impl()));
		writeTest(getRandomTest(100, 100, UniformPointGenerator.impl()));
		writeTest(getRandomTest(100, 100, UniformPointGenerator.impl()));
		writeTest(scale(getRandomTest(100, 100, UniformPointGenerator.impl())));
		writeTest(scale(getRandomTest(100, 100, UniformPointGenerator.impl())));
		writeTest(scale(getRandomTest(100, 100, UniformPointGenerator.impl())));
		writeTest(getRandomTest(100, 1000, CirclePointGenerator.impl()));
		writeTest(getRandomTest(100, 1000, CirclePointGenerator.impl()));
		writeTest(getRandomTest(100, 1000, CirclePointGenerator.impl()));
		writeTest(getRandomTest(100, 1000, CirclePointGenerator.impl()));
		writeTest(getRandomTest(100, 1000, CirclePointGenerator2.impl()));
		writeTest(getRandomTest(100, 1000, CirclePointGenerator2.impl()));
		writeTest(getRandomTest(100, 1000, CirclePointGenerator2.impl()));
		writeTest(getRandomTest(100, 1000, CirclePointGenerator2.impl()));
	}

	// Test of 4 * k + 4 points
	List<Point> getTest1(int k) {
		ArrayList<Point> al = new ArrayList<Point>();
		al.add(new Point(0, 0));
		al.add(new Point(0, k + 1));
		al.add(new Point(5, k + 1));
		al.add(new Point(5, 0));
		for (int i = 0; i < k; ++i) {
			al.add(new Point(3, i));
			al.add(new Point(4, i + 1));
		}
		for (int i = k; i > 0; --i) {
			al.add(new Point(1, i));
			al.add(new Point(2, i - 1));
		}
		return al;
	}

	List<Point> getRandomTest(int n, int MAX, PointGenerator pg) {
		ArrayList<Point> al = new ArrayList<Point>();
		Set<Point> ps = new TreeSet<Point>();
		for (int i = 0; i < n; ++i) {
			while (true) {
				Point p = pg.getPoint(MAX);
				if (!ps.contains(p)) {
					ps.add(p);
					al.add(p);
					break;
				}
			}
		}

		loop:
		while (true) {
//			double len = 0;
//			for (int a = 0; a < al.size(); ++a) {
//				int b = (a + 1) % al.size();
//				Point pa = al.get(a);
//				Point pb = al.get(b);
//				len += pb.sub(pa).norm();
//			}
//			System.out.println(al.size() + " " + len);
			for (int a = 0; a < al.size(); ++a) {
				int b = (a + 1) % al.size();
				Point pa = al.get(a);
				Point pb = al.get(b);
				for (int c = 0; c < al.size(); ++c) {
					int d = (c + 1) % al.size();
					if (c == b || c == a || d == a) continue;
					Point pc = al.get(c);
					Point pd = al.get(d);
					if (sign(pb.sub(pa).vmul(pd.sub(pa))) * sign(pb.sub(pa).vmul(pc.sub(pa))) <= 0 &&
						sign(pd.sub(pc).vmul(pa.sub(pc))) * sign(pd.sub(pc).vmul(pb.sub(pc))) <= 0) {
						
						ArrayList<Point> ta = new ArrayList<Point>();
						for (int t = d; t != b; t = (t + 1) % n) {
							ta.add(al.get(t));
						}
						Collections.reverse(ta);
						for (int t = b; t != d; t = (t + 1) % n) {
							ta.add(al.get(t));
						}
						al = ta;
//						System.out.print(".");
						continue loop;
					}
				}
			}
			break;
		}
		
		loop:
		while (true) {
			for (int a = 0; a < al.size(); ++a) {
				int b = (a + 1) % al.size();
				int c = (b + 1) % al.size();
				Point pa = al.get(a);
				Point pb = al.get(b);
				Point pc = al.get(c);
				if (pb.sub(pa).vmul(pc.sub(pa)) == 0) {
					al.remove(b);
					continue loop;
				}
			}
			break;
		}
		
		int area = 0;
		for (int a = 0; a < al.size(); ++a) {
			int b = (a + 1) % al.size();
			Point pa = al.get(a);
			Point pb = al.get(b);
			area += pb.vmul(pa);
		}
		
		if (area < 0) {
			Collections.reverse(al);
		}
		
		return al;
	}
	
	int sign(int i) {
		return i < 0 ? -1 : i > 0 ? 1 : 0;
	}

	static class CirclePointGenerator2 implements PointGenerator {
		
		private static final CirclePointGenerator impl = new CirclePointGenerator();
		
		private CirclePointGenerator2() {}
		
		public static PointGenerator impl() {
			return impl;
		}
		

		@Override
		public Point getPoint(int MAX) {
			double a = rand.nextDouble() * 2 * Math.PI;
			double r = Math.pow(rand.nextDouble() * 2 - 1, 3) * MAX;
			return new Point((int)Math.round(r * Math.cos(a)), (int)Math.round(r * Math.sin(a)));
		}		
	}
	
	static class CirclePointGenerator implements PointGenerator {
		
		private static final CirclePointGenerator impl = new CirclePointGenerator();
		
		private CirclePointGenerator() {}
		
		public static PointGenerator impl() {
			return impl;
		}
		

		@Override
		public Point getPoint(int MAX) {
			double a = rand.nextDouble() * 2 * Math.PI;
			double r = Math.pow(rand.nextDouble(), .2) * MAX;
			return new Point((int)Math.round(r * Math.cos(a)), (int)Math.round(r * Math.sin(a)));
		}		
	}
	
	static class UniformPointGenerator implements PointGenerator {
		
		private static final UniformPointGenerator impl = new UniformPointGenerator();
		
		private UniformPointGenerator() {}
		
		public static PointGenerator impl() {
			return impl;
		}
		
		@Override
		public Point getPoint(int MAX) {
			return new Point(rand(-MAX, MAX), rand(-MAX, MAX));
		}		
	}
	
	static interface PointGenerator {
		Point getPoint(int MAX);
	}
	
	List<Point> toList(int[][] c) {
		ArrayList<Point> ans = new ArrayList<Point>();
		for (int[] p : c) {
			ans.add(new Point(p));
		}
		return ans;
	}

	List<Point> shift(List<Point> a) {
		int sh = rand(0, a.size() - 1);
		List<Point> b = a.subList(sh, a.size());
		b.addAll(a.subList(0, sh));
		return b;
	}

	List<Point> scale(List<Point> a) {
		int minX = MAX_C;
		int maxX = -MAX_C;
		int minY = MAX_C;
		int maxY = -MAX_C;
		for (Point p : a) {
			minX = Math.min(p.x, minX);
			minY = Math.min(p.y, minY);
			maxX = Math.max(p.x, maxX);
			maxY = Math.max(p.y, maxY);
		}
		int scale = Integer.MAX_VALUE / 2;
		if (maxX - minX > 0) {
			scale = Math.min(scale, 2 * MAX_C / (maxX - minX));
		}
		if (maxY - minY > 0) {
			scale = Math.min(scale, 2 * MAX_C / (maxY - minY));
		}
		ArrayList<Point> ans = new ArrayList<Point>();
		for (Point p : a) {
			ans.add(new Point((p.x - minX) * scale - MAX_C, (p.y - minY)
					* scale - MAX_C));
		}
		return ans;
	}

	void writeTest(List<Point> b) {
		open();
		out.println(b.size());
		for (Point p : b) {
			out.println(p.x + " " + p.y);
		}
		close();
	}

	static class Point implements Comparable<Point> {
		int x, y;

		public Point(int x, int y) {
			this.x = x;
			this.y = y;
		}

		public Point(int[] p) {
			this.x = p[0];
			this.y = p[1];
		}
		
		Point sub(Point o) {
			return new Point(x - o.x, y - o.y);
		}
		
		int vmul(Point o) {
			return x * o.y - y * o.x;
		}

		int smul(Point o) {
			return x * o.x + y * o.y;
		}
		
		
		double norm() {
			return Math.sqrt(x * x + y * y);
		}
		
		@Override
		public int compareTo(Point o) {
			return x < o.x ? -1 : x > o.x ? 1 : y < o.y ? -1 : y > o.y ? 1 : 0;
		}

		@Override
		public boolean equals(Object o) {
			if (!(o instanceof Point))
				return false;
			Point p = (Point) o;
			return x == p.x && y == p.y;
		}

		@Override
		public String toString() {
			return x + " " + y;
		}
	}

	class Vector implements Comparable<Vector> {
		int x, y;

		Vector(int x, int y) {
			this.x = x;
			this.y = y;
		}

		@Override
		public int compareTo(Vector o) {
			return y * o.x - o.y * x;
		}

		@Override
		public boolean equals(Object o) {
			if (!(o instanceof Vector))
				return false;
			Vector ov = (Vector) o;
			return compareTo(ov) == 0;
		}

		@Override
		public String toString() {
			return "<" + x + ", " + y + ">";
		}
	}

	Comparator<Vector> cmpxy = new Comparator<Vector>() {
		@Override
		public int compare(Vector o1, Vector o2) {
			return o1.x + o1.y - o2.x - o2.y;
		}
	};

	ArrayList<Point> genConvexBig(int xs, int ys, int L, int dummy) {
		TreeSet<Vector> a = new TreeSet<Vector>();
		a.add(new Vector(1, 0));
		a.add(new Vector(1, 1));
		PriorityQueue<Vector> pq = new PriorityQueue<Vector>(2, cmpxy);
		pq.addAll(a);
		TreeSet<Vector> r = new TreeSet<Vector>();
		int sum = 0;
		while (true) {
			Vector v = pq.poll();
			if (sum + v.x > L)
				break;
			sum += v.x + v.y;
			r.add(v);
			if (v.x != v.y) {
				r.add(new Vector(v.y, v.x));
			}
			Vector vl = a.lower(v);
			if (vl != null) {
				Vector vll = new Vector(vl.x + v.x, vl.y + v.y);
				a.add(vll);
				pq.add(vll);
			}
			Vector vr = a.higher(v);
			if (vr != null) {
				Vector vrr = new Vector(vr.x + v.x, vr.y + v.y);
				a.add(vrr);
				pq.add(vrr);
			}
		}

		ArrayList<Vector> l = new ArrayList<Vector>(r);
		Collections.sort(l);

		int tx = 0;
		int ty = 0;
		for (Vector v : l) {
			tx += v.x;
			ty += v.y;
		}

		System.out.println(tx + " -- " + ty);

		for (int i = l.size() - 2; i >= 0; --i) {
			Vector v = l.get(i);
			l.add(new Vector(-v.x, v.y));
		}

		for (int i = l.size() - 2; i >= 1; --i) {
			Vector v = l.get(i);
			l.add(new Vector(v.x, -v.y));
		}

		int x = xs;
		int y = ys;

		int mx = xs;
		int my = ys;

		ArrayList<Point> ans = new ArrayList<Point>();
		for (Vector v : l) {
			ans.add(new Point(x, y));
			x += v.x;
			y += v.y;
			mx = Math.max(x, mx);
			my = Math.max(y, my);
		}
		assert x == xs && y == ys;
		System.out.println(ans.size());

		TreeSet<Point> ts = new TreeSet<Point>(ans);

		int lx = mx - xs, ly = my - ys;
		int cx = xs + lx / 2, cy = ys + ly / 2;

		for (int i = ans.size(); i < dummy; ++i) {
			Point p = null;
			while (p == null || ts.contains(p)) {
				p = new Point(rand(cx - lx / 20, cx + lx / 20), rand(cy - ly
						/ 20, cy + ly / 20));
			}
			ts.add(p);
			ans.add(p);
		}

		return ans;
	}

	public static void main(String[] args) {
		File f = new File("../tests");
		if (!f.exists()) {
			f.mkdir();
		}
		if (args.length > 0 && args[0].equals("stress")) {
			STRESS_MODE = true;
		}
		new gen_guard().run();
	}

	public void run() {
		try {
			solve();
		} catch (Throwable e) {
			e.printStackTrace();
			System.exit(-1);
		}
	}

	static Random rand = new Random(6439586L);
	PrintWriter out;
	int I = 0;

	String getName(int i) {
		return "../tests/" + ((i < 10) ? "0" : "") + i;
	}

	void open() {
		try {
			if (STRESS_MODE) {
				out = new PrintWriter(System.out);
			} else {
				++I;
				System.out.println("Generating test " + I);
				out = new PrintWriter(getName(I));
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			System.exit(-1);
		}
	}

	void close() {
		out.close();
	}

	static final String ALPHA = "abcdefghijklmnopqrstuvwxyz";

	static String randString(int len, String alpha) {
		StringBuilder ans = new StringBuilder();
		int k = alpha.length();
		for (int i = 0; i < len; i++) {
			ans.append(alpha.charAt(rand.nextInt(k)));
		}
		return ans.toString();
	}

	static long rand(long l, long r) {
		return l + (rand.nextLong() >>> 1) % (r - l + 1);
	}

	static int rand(int l, int r) {
		return l + rand.nextInt(r - l + 1);
	}
}