#include<bits/stdc++.h>
using namespace std;
#define E 1e-18
#define ll long long
#define int long long
#define db double
#define For(i,j,k) for(int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for(int i=(int)(j);i>=(int)(k);i--)
inline ll read(){
	ll x=0;char ch=getchar();bool f=0;
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=1;
	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
	return f?-x:x;
}
void write(ll x){
	if(x<0) putchar('-'),x=-x;
	if(x>=10) write(x/10);putchar(x%10+'0');
}
void writeln(ll x){write(x);puts("");}
void writep(ll x){write(x);putchar(' ');}

int const N=1e5+3;
int n,m,top,vis[N],sta[N];
struct point{
	db x,y;
    point operator - (point A) const{return (point){x-A.x,y-A.y};}
    point operator + (point A) const{return (point){x+A.x,y+A.y};}
    bool operator == (point A) const{return x==A.x && y==A.y;}
	void print(){printf("%.10lf %.10lf\n",x,y);}
}base,A[N],B[N];

point operator *(db x,point A){return (point){x*A.x,x*A.y};}
db CJ(point A,point B){return A.x*B.y-B.x*A.y;}//叉积 
db DJ(point A,point B){return A.x*B.x+A.y*B.y;}//点积 
db dis(point A){return sqrt(A.x*A.x+A.y*A.y);}//向量长度 

bool cmpp(point A,point B){return CJ(A,B)>0;}
bool cmp(point A,point B){return (CJ(A,B)>0 || CJ(A,B)==0 && dis(A)<dis(B));}//按极角排序，极角相同按距离排序 
bool cmp_(point A,point B){return dis(A)>dis(B);}
point CGL_1_A(point A,point B,point C){//点在直线上的投影点
	db d=dis(B-A);
	return (A+(DJ(C-A,B-A)/d/d*(B-A)));
}
point CGL_1_B(point A,point B,point C){//点关于直线的对称点
	point P=CGL_1_A(A,B,C);
	return (C+2*(P-C));
}
int CGL_1_C(point A,point B,point C){//向量的位置关系(向量AC和向量AB) 
    if (CJ(B-A,C-A)>0) return 1;//逆时针 
    if (CJ(B-A,C-A)<0) return 2;//顺时针 
    if (DJ(C-A,B-A)<0) return 3;//方向相反
	if (dis(C-A)>dis(B-A)) return 4;//方向相同 AC>AB
	if (dis(C-A)<=dis(B-A)) return 5;//方向相同 AB>AC
}
int CGL_2_A(point A,point B,point C,point D){//判断直线平行、垂直
	if (CJ(B-A,D-C)==0) return 2;//平行 
	if (DJ(B-A,D-C)==0) return 1;//垂直 
	return 0;//相交 
}
int CGL_2_B(point A,point B,point C,point D){//判断线段是否有交
	if (min(A.x,B.x)>max(C.x,D.x) || min(C.x,D.x)>max(A.x,B.x) || min(A.y,B.y)>max(C.y,D.y) || min(C.y,D.y)>max(A.y,B.y)) return 0;//快速排斥实验(两个矩形是否相交)
	return CJ(B-A,C-A)*CJ(B-A,D-A)<=0 && CJ(D-C,A-C)*CJ(D-C,B-C)<=0;//跨立实验
}
point CGL_2_C(point A,point B,point C,point D){//求直线交点
	point p1=CGL_1_A(A,B,C),p2=CGL_1_A(A,B,D);//求C、D在AB上的投影点 
	db d1=dis(C-p1),d2=dis(D-p2);//三角形的相似比 
	if (CJ(B-A,C-A)*CJ(B-A,D-A)<0) return (C+(d1/(d1+d2)*(D-C)));
	else if (d1<d2) return (D+d2/(d2-d1+E)*(C-D));
	else return (C+d1/(d1-d2+E)*(D-C));
}
db Distance(point A,point B,point C){//点到线段的距离 
	point P=CGL_1_A(A,B,C);//C在AB上的投影点 
	if (P.x>=min(A.x,B.x) && P.x<=max(A.x,B.x) && P.y>=min(A.y,B.y) && P.y<=max(A.y,B.y)) return dis(P-C);//投影点在线段上 
	return min(dis(A-C),dis(B-C));//两个端点到C的最小值 
}
db CGL_2_D(point A,point B,point C,point D){//线段到线段的距离
	point P=CGL_2_C(A,B,C,D);//求直线交点 
	if (P.x>=min(A.x,B.x) && P.x<=max(A.x,B.x) && P.y>=min(A.y,B.y) && P.y<=max(A.y,B.y) && P.x>=min(C.x,D.x) && P.x<=max(C.x,D.x) && P.y>=min(C.y,D.y) && P.y<=max(C.y,D.y)) return 0;//线段有交点 
	return min(Distance(A,B,C),min(Distance(A,B,D),min(Distance(C,D,A),Distance(C,D,B))));
}
db CGL_3_A(){//多边形的有向面积
    int n=read(),ans=0;
    for (int i=1;i<=n;i++) scanf("%lf%lf",&A[i].x,&A[i].y);
    A[n+1]=A[1];
    for (int i=1;i<=n;i++) ans+=CJ(A[i],A[i+1]);//叉积求平行四边形面积 
    return ans/2.0;//总面积要 ÷2
}
int CGL_3_B(){//判断多边形是否为凸多边形
    int n=read();
    for (int i=1;i<=n;i++) scanf("%lf%lf",&A[i].x,&A[i].y);
	A[0]=A[n];A[n+1]=A[1];
	for (int i=1;i<=n;i++) if (CJ(A[i-1]-A[i],A[i+1]-A[i])>0) return 0;//每个角要大于180° 
	return 1; 
}
int CGL_3_C(point A[],point P){//点与多边形的位置关系
    point Q,Q_;
    memset(vis,0,sizeof(vis));
    Q.x=1e9;Q.y=P.y;//向右无限延伸 
    Q_.x=-1e9;Q_.y=P.y;//向左无限延伸 
	for (int i=1;i<=n;i++)
	  if (CGL_2_B(A[i],A[i%n+1],P,Q) && CGL_2_B(A[i],A[i%n+1],P,Q_)) return 1;//在简单多边形的边上 
	for (int i=1;i<=n;i++)
	  if (A[i].y==P.y && A[i].x>P.x) A[i].y--,vis[i]=1;//强制使在射线上的点往下移 
	int sum=0;
	for (int i=1;i<=n;i++)
	  if ((vis[i] || vis[i%n+1]) && CJ(Q-P,A[i]-P)*CJ(Q-P,A[i%n+1]-P)<=0) sum++;//修改过的点只需判断所在的边是否在射线两侧 
	  else if (CGL_2_B(A[i],A[i%n+1],P,Q)) sum++;//其余的边经过射线的个数
	for (int i=1;i<=n;i++)
	  if (vis[i]) A[i].y++;//移回来 
	return (sum&1)?2:0;//2-在多边形内 0-在多边形外 
}
void CGL_4_A(point *A,int &n){//Convex求凸包
	base=A[1];top=0;//base为起点 
	for (int i=1;i<=n;i++) A[i]=A[i]-base;//从起点开始的向量 
	sort(A+2,A+n+1,cmp);//按极角排序 
	sta[++top]=1;//单调栈维护凸包 
	for (int i=2;i<=n;sta[++top]=i,i++){
	  while (top>1 && CJ((A[i]-A[sta[top-1]]),(A[sta[top]]-A[sta[top-1]]))>0) top--;//简单单调栈操作(用叉积来判断) 
}
	for (int i=1;i<=top;i++) A[i]=A[sta[i]]+base;//回到之前的向量 
	n=top;A[n+1]=A[1];//形成环 
}

signed main(){
// 	freopen("jicao.txt","r",stdin);
// 	freopen("fuck.txt","w",stdout);
	m=n=read();
	for (int i=1;i<=n;i++){
		scanf("%lf%lf",&A[i].x,&A[i].y);
		if (A[i].y<A[1].y || A[i].y==A[1].y && A[i].x<A[1].x) swap(A[i],A[1]);
	}
	for (int i=1;i<=n;i++) B[i]=A[i];
	CGL_4_A(A,n);
	int k=n;
	for (int i=1;i<=m;i++){
		if (B[i]==A[k] || B[i]==A[n+1]) continue;
		point Q,Q_;
	    Q.x=1e9;Q.y=B[i].y;
	    Q_.x=-1e9;Q_.y=B[i].y;
		if (CGL_2_B(A[k],A[n+1],B[i],Q) && CGL_2_B(A[k],A[n+1],B[i],Q_)) n++,A[n+1]=A[n],A[n]=B[i];
	}
	base=A[1];
	for (int i=k+1;i<=n;i++) A[i]=A[i]-base;
	sort(A+k+1,A+n+1,cmp_);
	for (int i=k+1;i<=n;i++) A[i]=A[i]+base;
//	stable_sort(A+1,A+1+n,cmpp);
	writeln(n);
	for (int i=1;i<=n;i++) writep(A[i].x),writeln(A[i].y);
	return 0;
}



Measured memory_bytes: 6404