#include "bits/stdc++.h"

/*#define _USE_MATH_DEFINES
#include <cmath>
#include <cstdlib>
#include <deque>
#include <algorithm>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <iterator>
#include<complex>*/

using namespace std;

#define rep(i,a,b) for(int i=(a), i##_len=(b);i<i##_len;i++)
#define rrep(i,a,b) for(int i=(b)-1;i>=(a);i--)
#define all(c) begin(c),end(c)

//#define int long long
#define SZ(x) ((int)(x).size())
#define pb push_back
#define mp make_pair

typedef long long ll;
//typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<double, double> pdd;
typedef pair<double, int> pdi;

template<class T> bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; }
template<class T> bool chmin(T &a, const T &b) { if (b < a) { a = b; return true; } return false; }

const int INF = sizeof(int) == sizeof(long long) ? 0x3f3f3f3f3f3f3f3fLL : 0x3f3f3f3f;
const int MOD = (int)1e9 + 7;
const double EPS = 1e-9;

typedef complex<double> P;
typedef vector<P> G;

namespace std
{
	bool operator < (const P& a, const P& b) {
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}

double cross(const P& a, const P& b) {
	return imag(conj(a)*b);
}
double dot(const P& a, const P& b) {
	return real(conj(a)*b);
}

double length2(const P& a, const P& b)
{
	return dot(a - b, a - b);
}

double length(const P& a, const P& b)
{
	return sqrt(length2(a, b));
}

struct L : public vector<P> {
	L(const P &a, const P &b) {
		push_back(a); push_back(b);
	}
};

struct C {
	P p; double r;
	int di;
	C(const P &p, double r,int di) : p(p), r(r),di(di) { }
	C():p(P(-1,-1)),r(-1),di(-1){}
	bool operator<(const C& c)const
	{
		return r < c.r;
	}
};

int ccw(P a, P b, P c) {
	b -= a; c -= a;
	if (cross(b, c) > 0)   return +1;       // counter clockwise
	if (cross(b, c) < 0)   return -1;       // clockwise
	if (dot(b, c) < 0)     return +2;       // c--a--b on line
	if (norm(b) < norm(c)) return -2;       // a--b--c on line
	return 0;
}

bool intersectLL(const L &l, const L &m) {
	return abs(cross(l[1] - l[0], m[1] - m[0])) > EPS || // non-parallel
		abs(cross(l[1] - l[0], m[0] - l[0])) < EPS;   // same line
}
bool intersectLS(const L &l, const L &s) {
	return cross(l[1] - l[0], s[0] - l[0])*       // s[0] is left of l
		cross(l[1] - l[0], s[1] - l[0]) < EPS; // s[1] is right of l
}
bool intersectLP(const L &l, const P &p) {
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
bool intersectSS(const L &s, const L &t) {
	return ccw(s[0], s[1], t[0])*ccw(s[0], s[1], t[1]) <= 0 &&
		ccw(t[0], t[1], s[0])*ccw(t[0], t[1], s[1]) <= 0;
}
bool intersectSP(const L &s, const P &p) {
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; // triangle inequality
}

P projection(const L &l, const P &p) {
	double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
	return l[0] + t*(l[0] - l[1]);
}
P reflection(const L &l, const P &p) {
	return p + 2.0*(projection(l, p) - p);
}
double distanceLP(const L &l, const P &p) {
	return abs(p - projection(l, p));
}
double distanceLL(const L &l, const L &m) {
	return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}
double distanceLS(const L &l, const L &s) {
	if (intersectLS(l, s)) return 0;
	return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
double distanceSP(const L &s, const P &p) {
	const P r = projection(s, p);
	if (intersectSP(s, r)) return abs(r - p);
	return min(abs(s[0] - p), abs(s[1] - p));
}
double distanceSS(const L &s, const L &t) {
	if (intersectSS(s, t)) return 0;
	return min(min(distanceSP(s, t[0]), distanceSP(s, t[1])),
		min(distanceSP(t, s[0]), distanceSP(t, s[1])));
}
P crosspoint(const L &l, const L &m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS && abs(B) < EPS) return m[0]; // same line
	//if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
	return m[0] + B / A * (m[1] - m[0]);
}

vector<P> convex_hull(vector<P>& points)
{
	int n = points.size(), k = 0;
	sort(points.begin(), points.end(), [](const P &x, const P &y) {
		return imag(x) != imag(y) ? imag(x)<imag(y) : real(x)<real(y);
	});
	vector<P> ch(2 * n);
	for (int i = 0; i < n; ch[k++] = points[i++]) // lower-hull
	{
		while (k >= 2)
		{
			int state = ccw(ch[k - 2], ch[k - 1], points[i]);
			if (state > 0 || state < -1)
			{
				break;
			}
			--k;
		}
	}
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = points[i--]) // upper-hull
	{
		while (k >= t)
		{
			int state = ccw(ch[k - 2], ch[k - 1], points[i]);
			if (state > 0 || state < -1)
			{
				break;
			}
			--k;
		}
	}
	ch.resize(k - 1);
	return ch;
}

vector<P> points;

int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);

	int N,x,y;
	cin >> N;
	rep(i, 0, N)
	{
		cin >> x >> y;
		points.push_back(P(x, y));
	}

	vector<P> output = convex_hull(points);

	printf("%d\n", output.size());
	rep(i,0,SZ(output))
	{
		printf("%d %d\n", (int)real(output[i]), (int)imag(output[i]));
	}

	return 0;
}


Measured memory_bytes: 7540