#include <iostream>
#include <cmath>
#include <cassert>
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME
#define pr(...) std::cerr<< GET_MACRO(__VA_ARGS__,pr8,pr7,pr6,pr5,pr4,pr3,pr2,pr1)(__VA_ARGS__) <<std::endl
#define pr1(a) (#a)<<"="<<(a)<<" "
#define pr2(a,b) pr1(a)<<pr1(b)
#define pr3(a,b,c) pr1(a)<<pr2(b,c)
#define pr4(a,b,c,d) pr1(a)<<pr3(b,c,d)
#define pr5(a,b,c,d,e) pr1(a)<<pr4(b,c,d,e)
#define pr6(a,b,c,d,e,f) pr1(a)<<pr5(b,c,d,e,f)
#define pr7(a,b,c,d,e,f,g) pr1(a)<<pr6(b,c,d,e,f,g)
#define pr8(a,b,c,d,e,f,g,h) pr1(a)<<pr7(b,c,d,e,f,g,h)
#define prArr(a) {cerr<<(#a)<<"={";int i=0;for(auto t:(a))cerr<<(i++?", ":"")<<t;cerr<<"}"<<endl;}

template<typename T>
class Deque{
public:
  T *val;
  int sz;
  int length;
  int head, tail;
  
  Deque(){sz = 0, length = 0, val = new T[0];}
  Deque(int size, T init = T()){
    length = 1;
    while(length < size) length *= 2;
    val = new T[length];
    sz = size;
    head = 0;
    tail = 0;
    for(int i=0;i<size;i++) val[tail++] = init;
  }
  
  Deque(const Deque &t){
    sz = t.size();
    length = 1;
    while(length < sz) length *= 2;
    val = new T[length];
    head = 0;
    tail = 0;
    for(int i=0;i<sz;i++) val[tail++] = t[i];
  }
  
  T& operator [] (int i){assert(0 <= i && i < sz);return val[(head + i)%length];}
  T& operator [] (int i)const{assert(0 <= i && i < sz);return val[(head + i)%length];}
  int size()const{return sz;}
  int empty()const{return sz == 0;}

  void increaseMemory(){
    int length_ = length;
    
    length = length * 2;
    if(length == 0) length = 1;
    T *val2 = new T[length];
    for(int i=0;i<sz;i++) val2[i] = val[(head + i)%length_];
    head = 0;
    tail = sz;
    delete [] val;
    val = val2;
  };
  
  void push_back(T v){
    if(sz == length) increaseMemory();
    sz++;
    val[tail++] = v;
    if(tail == length) tail = 0;
  }
  
  void push_front(int v){
    if(sz == length) increaseMemory();
    sz++;
    head--;
    if(head == -1) head = length - 1;
    val[head] = v;
  }

  void pop_back(){
    assert(sz > 0);
    sz--;
    tail--;
    if(tail == -1) tail = length - 1;
  }
  
  void pop_front(){
    assert(sz > 0);
    sz--;
    head++;
    if(head == length) head = 0;
  }
};
template <typename T>
using vector = Deque<T>;

namespace Sort{

  template<class T, class D>
  void dfs(D &A, int l, int r){
    if(l + 1 == r) return;
    int m = (l + r) / 2;
    dfs<T>(A, l, m);
    dfs<T>(A, m, r);
    
    int idx = 0;
    int i = l;
    int j = m;
    T *tmp = new T[r - l];
   
    while(i < m || j < r){
      if(i >= m) tmp[idx] = A[j++];
      else if(j >= r) tmp[idx] = A[i++];
      else if(A[i] < A[j]) tmp[idx] = A[i++];
      else tmp[idx] = A[j++];
      idx++;
    }
    for(int i=0;i<r-l;i++) A[l + i] = tmp[i];
    delete[] tmp;
  }

  template<class T, class D>
  void sort(D &A, int n){
    dfs<T>(A, 0, n);
  };
  
}

template <typename T, typename D>
class Pair{
public:
  T first;
  D second;
  Pair(){first = second = 0;}
  Pair(const T first, const D second):first(first), second(second){}
  
  bool operator < (const Pair t)const{
    return first != t.first? (first < t.first):(second < t.second);
  }
  bool operator > (const Pair t)const{
    return first != t.first? (first > t.first):(second > t.second);
  }
};



const double EPS = 1e-12;

template<class T>
class Complex{
  T a, b;
public:
  Complex(){}
  Complex(T a,T b):a(a), b(b){}
  
  T real(){return a;}
  T imag(){return b;}
  T real(Complex t){return t.real();}
  T imag(Complex t){return t.imag();}
  
  Complex operator + (Complex t){return Complex(a + t.real(), b + t.imag());}
  Complex operator - (Complex t){return Complex(a - t.real(), b - t.imag());}
  Complex operator * (Complex t){return Complex(a * t.real() - b * t.imag(), a * t.imag() + b * t.real());}
  Complex operator * (double k){return Complex(k * a, k * b);};
  Complex& operator += (Complex t){return *this = *this + t;}
  Complex& operator -= (Complex t){return *this = *this - t;}
  Complex& operator *= (Complex t){return *this = *this * t;}
  Complex& operator *= (double k){return *this = *this * k;}
  bool operator == (T t)const{return a == t.real() && b == t.imag();}
  bool operator != (T t)const{return a != t.real() || b != t.imag();}
  bool operator < (const Complex t){
    return fabs(real()-real(t)) < EPS ? imag() < imag(t) : real() < real(t);
  }

  double norm(){return (a * a + b * b);}
  double abs(){return sqrt(norm());}
  Complex conj(){return Complex(a, -b);}
};


template <class T> T real(Complex<T> a){return a.real();}
template <class T> T imag(Complex<T> a){return a.imag();}
template <class T> T norm(Complex<T> a){return a.norm();}
template <class T> Complex<T> conj(Complex<T> a){return Complex<T>(a.real(), -a.imag());}


typedef Complex<double> P; //Point
typedef Pair<P,P> L; //Line, Segment

double dot(P a, P b){ return real(conj(a)*b); }
double cross(P a, P b){ return imag(conj(a)*b); }
int ccw(P a, P b, P c){
  b -= a;
  c -= a;
  if(cross(b,c) > EPS) return 1;   // ベクトル(b-a)の左側にベクトル(c-a)が存在する。
  if(cross(b,c) < -EPS) return -1; // ベクトル(b-a)の右側にベクトル(c-a)が存在する。
  if(dot(b,c) < -EPS) return 2;
  if(norm(b) < norm(c)) return -2;
  return 0;
}

vector<P> convex_hull(vector<P> G) {
  int n = G.size();
  Sort::sort<P>(G, n);
  vector<P> res;
  
  auto erase = [&](int i) {
    if(res.size() < 2) return 0;
    P av = res[res.size()-2];
    P bv = res[res.size()-1];
    P cv = G[i];
    if(ccw(av, bv, cv) == -1) {res.pop_back(); return 1;}
    return 0;
  };

  for(int i=0;i<n;i++){
    while(erase(i));
    res.push_back(G[i]);
  }

  for(int i=n-2;i>=0;i--){
    while(erase(i));
    res.push_back(G[i]);
  }
  res.pop_back();
  return res;
}

signed main(){

  int n;
  std::cin>>n;
  vector<P> G(n);
  for(int i=0;i<n;i++){
    int x, y;
    std::cin>>x>>y;
    G[i] = P(x, y);
  }
  
  auto ans = convex_hull(G);
  std::cout <<ans.size()<<std::endl;

  int idx = 0;
  for(int i=0;i<ans.size();i++){
    auto a = ans[idx], b = ans[i];
    if(a.imag() != b.imag() && a.imag() > b.imag()) idx = i;
    if(a.imag() == b.imag() && a.real() > b.real()) idx = i;
  }

  int m = ans.size();
  for(int i=0;i<ans.size();i++)
    std::cout<<ans[(idx + i)%m].real() <<" "<<ans[(idx + i)%m].imag()<<std::endl;
  
  
  return 0;
}



Measured memory_bytes: 9020