#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;


static const int COUNTER_CLOCKWISE = 1; //??????????????¨??????
static const int CLOCKWISE = -1;
static const int ON_SEGMENT = 0;
static const int ONLINE_FRONT = 2;
static const int ONLINE_BACK = -2;

int n;

const double EPS = 1e-10;

bool equals(double a, double b) {
	return fabs(a - b) < EPS;
}

class Point {
public:
	double x, y;

	Point(double x = 0, double y = 0): x(x), y(y) {}
	Point(Point p1, Point p2): x((p2 - p1).x), y((p2 - p1).y) {}

	Point operator + (Point p) {
		return Point(x + p.x, y + p.y);
	}
	Point operator - (Point p) {
		return Point(x - p.x, y - p.y);
	}
	Point operator * (double k) {
		return Point(k * x, k * y);
	}
	Point operator / (double k) {
		return Point(x / k, y / k);
	}

	double norm() {
		return x * x + y * y;
	}
	double abs() {
		return sqrt(norm());
	}

	bool operator < (const Point &p) const {
		return x != p.x ? x < p.x : y < p.y;
	}

	bool operator == (const Point &p) const {
		return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
	}

	Point orth() {
		return Point(-y, x) / abs();
	}
};

typedef Point Vector;

double dot(Vector a, Vector b) {
	return a.x * b.x + a.y * b.y;
}

double cross(Vector a, Vector b) {
	return a.x * b.y - a.y * b.x;
}

int check(Vector v0, Vector v1) { //????????§??????
	double c = cross(v0, v1);
	if (equals(c, 0)) {
		if (dot(v0, v1) < 0) return ONLINE_BACK;
		else if (v1.norm() > v0.norm()) return ONLINE_FRONT;
		else return ON_SEGMENT;
	} else if (c > 0) {
		return COUNTER_CLOCKWISE;
	} else {
		return CLOCKWISE;
	}
}

class Polygon { //?????????????????????
public:
	vector<Point> Poly;

	void contain(Point p) {
		bool x = false; //??????????????§
		for (int i = 0; i < Poly.size(); i++) {
			Vector a = Vector((Poly[i] - p).x, (Poly[i] - p).y);
			Vector b = Vector((Poly[(i + 1) % n] - p).x, (Poly[(i + 1) % n] - p).y); //n->0?????????
			if (equals(cross(a, b), 0) && dot(a, b) <= 0) {
				cout << 1 << endl;
				return;
			}
			if (a.y > b.y) swap(a, b);
			if (a.y <= 0 && b.y > 0 && cross(a, b) > 0) x = !x; //???????????????????????????a??????,b??????
		}
		if (x) cout << 2 <<endl;
		else cout << 0 << endl;
	}
 
};

void Convex(Polygon P) {
	Polygon U;
	sort(P.Poly.begin(), P.Poly.end());

	U.Poly.push_back(P.Poly[0]);
	U.Poly.push_back(P.Poly[1]);
	int t = 0;
	for (int i = 2; i < n; i++) {
		Vector a = Vector(U.Poly[t], U.Poly[t + 1]);
		Vector b = Vector(U.Poly[t], P.Poly[i]);
		while (t >= 0 && check(a, b) == COUNTER_CLOCKWISE) {
			t--;
			a = Vector(U.Poly[t], U.Poly[t + 1]);
			b = Vector(U.Poly[t], P.Poly[i]);
			U.Poly.pop_back();
		}
		U.Poly.push_back(P.Poly[i]);
		t++;
	}

	for (int i = n - 2; i >= 0; i--) {
		Vector a = Vector(U.Poly[t], U.Poly[t + 1]);
		Vector b = Vector(U.Poly[t], P.Poly[i]);
		while (t >= 0 && check(a, b) == COUNTER_CLOCKWISE) {
			t--;
			a = Vector(U.Poly[t], U.Poly[t + 1]);
			b = Vector(U.Poly[t], P.Poly[i]);
			U.Poly.pop_back();
		}
		U.Poly.push_back(P.Poly[i]);
		t++;
	}

	reverse(U.Poly.begin(), U.Poly.end());
	Point minp = Point(10000, 10000);
	int index;
	for (int i = 0; i < U.Poly.size() - 1; i++) {
		if (U.Poly[i].y < minp.y) {
			minp = U.Poly[i];
			index = i;
		}
	}

	int m = U.Poly.size() - 1;
	cout << m << endl;
	for (int i = 0; i < m; i++) {
		cout << U.Poly[(i + index) % m].x << ' ' << U.Poly[(i + index) % m].y << endl;;
	}

}


int main() {
	cin >> n;
	int x, y;
	Polygon P;
	for (int i = 0; i < n; i++) {
		cin >> x >> y;
		P.Poly.push_back(Point(x, y));
	}
	
	Convex(P);
	
	return 0;
}

Measured memory_bytes: 6512