#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <sstream>
#include <cmath>
#include <set>
#include <iomanip>
#include <deque>
#include <stdio.h>
using namespace std;

#define REP(i,n) for(int (i)=0;(i)<(int)(n);(i)++)

typedef long long ll;

struct ConvexHull {
    
    struct Point {
        double x,y;
        Point () {}
        Point (double _x, double _y) : x(_x), y(_y) {}
        bool operator < (const Point &a) const {
            return (x == a.x) ? (y < a.y) : (x < a.x);
        }
    };
    
    double dot(Point a, Point b) { return a.x * b.x + a.y * b.y; }
    double cross(Point a, Point b) { return a.x * b.y - a.y * b.x; }
    double norm(Point a) { return sqrt(dot(a, a) * dot(a, a)); }
    Point sub(Point a, Point b) { return Point(a.x - b.x, a.y - b.y); }
    
    vector< Point > Pos;
    vector< Point > CHPos;
    
    int counter_clockwise(Point p0, Point p1, Point p2) {
        Point a = sub(p1, p0);
        Point b = sub(p2, p0);
        if (cross(a,b) > 1.0e-8) return 1;
        if (cross(a,b) < -1.0e-8) return -1;
        if (dot(a,b) < -1.0e-8) return 2;
        if (norm(a) < norm(b)) return 2;
        return 0;
    }
    
    void add_point(double x, double y) {
        Pos.push_back(Point(x, y));
    }
    
    void build() {
        int n = (int) Pos.size(), k = 0;
        sort(Pos.begin(),Pos.end());
        vector< Point > ch(2 * n);
        for (int i = 0; i < n; ch[k++] = Pos[i++]) {
            while (k >= 2 && counter_clockwise(ch[k-2], ch[k-1], Pos[i]) <= 0) --k;
        }
        for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = Pos[i--]) {
            while (k >= t && counter_clockwise(ch[k-2], ch[k-1], Pos[i]) <= 0) --k;
        }
        copy(ch.begin(), ch.begin() + k - 1, back_inserter(CHPos));
    }
    
    double diameter() {
        int n = (int) CHPos.size();
        int is = 0, js = 0;
        for (int i = 1; i < n; i++) {
            if (CHPos[i].y > CHPos[is].y) is = i;
            if (CHPos[i].y < CHPos[js].y) js = i;
        }
        double maxd = norm(sub(CHPos[is], CHPos[js]));
        int i = is, maxi = is;
        int j = js, maxj = js;
        do{
            if (cross(sub(CHPos[(i + 1) % n], CHPos[i]), sub(CHPos[(j + 1) % n], CHPos[j])) >= 0) {
                j = (j + 1) % n;
            } else {
                i = (i + 1) % n;
            }
            if(norm(sub(CHPos[i], CHPos[j])) > maxd) {
                maxd = norm(sub(CHPos[i], CHPos[j]));
                maxi = i, maxj = j;
            }
        } while (i != is || j != js);
        return sqrt(maxd);
    }
    
    int size() {
        return (int) CHPos.size();
    }
    
    Point operator [] (int n) {
        return CHPos[n];
    }
    
};

int main(){
    
    int n; cin >> n;
    
    ConvexHull inst;
    REP(i,n) {
        double x,y; cin >> x >> y;
        inst.add_point(x, y);
    }
    
    inst.build();
    
    cout << inst.size() << endl;
    
    vector< pair< pair<double,double>, int> > v;
    REP(i,inst.size()) {
        v.push_back(make_pair(make_pair(inst[i].y,inst[i].x),i));
    }
    sort(v.begin(),v.end());
    
    int idx = v[0].second;
    REP(i,inst.size()) {
        cout << inst[(i+idx)%inst.size()].x << " " << inst[(i+idx)%inst.size()].y << endl;
    }
    
    return 0;
}

Measured memory_bytes: 10352