#include <bits/stdc++.h>
using namespace std;
/*******************??????********************/
const double EPS = 1e-8;
const double INF = 1e12;
typedef complex<double> P;
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);
}

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

typedef vector<P> G;
struct C {//???
	P p; double r;
	C(const P &p, double r) : p(p), r(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){
	//non-parallel || sameline
	return abs(cross(l[1]-l[0],m[1]-m[0])) > EPS || abs(cross(l[1]-l[0],m[0]-l[0])) < EPS;
}
bool intersectLS(const L& l,const L& s){
	// s[0] is left of l,s[1] is right of l
	return cross(l[1]-l[0],s[0]-l[0]) * cross(l[1]-l[0],s[1]-l[0]) < 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 intersectLP(const L& l,const P& p){
	return abs(cross(l[1]-p,l[0]-p)) < EPS;
}
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
}
// ??´???????????????
bool orthogonalLL(const L &l1, const L &l2){
	return (dot(l1[0]-l1[1], l2[0]-l2[1]) <= EPS && dot(l1[0]-l1[1], l2[0]-l2[1]) >= -EPS);
}
// ??????????????????
bool parallelLL(const L &l1, const L &l2){
	return (cross(l1[0]-l1[1], l2[0]-l2[1]) <= EPS && cross(l1[0]-l1[1], l2[0]-l2[1]) >= -EPS);
}
// p??????l?????????????????????????????????
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]);
}
// l???????§°?????¨????????????p??¨???????§°?????????????????????
P reflection(const L& l,const P& p){
	return p + 2. * (projection(l,p) - p);
}
double distancePP(const P &a, const P &b){
	return abs(a - b);
}
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 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 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 crosspointLL(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]);
}
// ????§???¢?????¢???
double area(const G &g){
	double A = 0.0;
	for(int i=0;i<g.size();i++)
		A += cross(g[i],g[(i+1)%g.size()]);
	return A / 2.0;
}
// ?????????
bool isconvex(const G &g){
	for(int i=0;i<g.size();i++){
		if(ccw(g[(i-1+g.size())%g.size()], g[i], g[(i+1)%g.size()]) == -1)return false;
	}
	return true;
}
// convex full
G convex_full(G &ps){
	int n = ps.size(), k = 0;
	sort(ps.begin(), ps.end());
	G ch(2*n);
	for (int i = 0; i < n; ch[k++] = ps[i++])//lower-hull
		while (k >= 2 && ccw(ch[k-2], ch[k-1], ps[i]) == -1) --k;
	for (int i = n-2, t = k+1; i >= 0; ch[k++] = ps[i--])//upper-hull
		while (k >= t && ccw(ch[k-2], ch[k-1], ps[i]) == -1) --k;
	ch.resize(k-1);
	return ch;
}
bool is_convex(G &g){
	G cf = convex_full(g);
	if(cf.size() == g.size())return true;
	return false;
}
// ??????????§???¢????????????
enum{ OUT, ON, IN};
int contains(const G &g, const P &p){
	bool in = false;
	for(int i=0;i<g.size();i++){
		P a = g[i] - p, b = g[(i+1)%g.size()] - p;
		if( imag(a) > imag(b) )swap(a, b);
		if( imag(a) <= 0 && 0 < imag(b) )
			if( cross(a, b) < 0) in = !in;
		if( cross(a, b) == 0 && dot(a, b) <= 0 )return ON;
	}
	return in ? IN : OUT;
}
int main(void){
	int n;
	cin >> n;
	G g(n);
	for(int i=0;i<n;i++){
		int x,y;
		cin >> x >> y;
		g[i] = P(x,y);
	}
	G cf = convex_full(g);
	G c = cf;
	for(int i=0;i<c.size();i++){
		c[i] = P(imag(c[i]),real(c[i]));
	}
	sort(c.begin(),c.end());
	for(int i=0;i<cf.size();i++){
		// cerr << c[i] << endl;
	}
	int s = 0;
	for(int i=0;i<cf.size();i++){
		if(real(c[0]) == imag(cf[i]) && imag(c[0]) == real(cf[i])){
			s = i;
			break;
		}
	}

	cout << cf.size() << endl;
	for(int i=s;i<cf.size()+s;i++){
		cout << real(cf[i%cf.size()]) << " " << imag(cf[i%cf.size()]) << endl;
	}
	return 0;
}

Measured memory_bytes: 7844