#include <iostream>
#include <algorithm>
#include <cassert>
#include <climits>
#include <cmath>
#include <complex>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <map>
#include <queue>
#include <set>
#include <tuple>
using namespace std;
typedef long long ll;
#define _ << " " <<
#define all(X) (X).begin(), (X).end()
#define len(X) (X).size()
#define Pii pair<int, int>
#define Pll pair<ll, ll>
#define Tiii tuple<int, int, int>
#define Tlll tuple<ll, ll, ll>
#define PI 3.1415926535898

double eps = 1e-8;

int sgn(double x){
    if(x < -eps) return -1;
    if(x > eps) return 1;
    return 0;
}
bool EQ(double x, double y) {
    return sgn(x - y) == 0;
}
bool LE(double x, double y) {
    return sgn(x - y) == -1;
}
bool LEQ(double x, double y) {
    return sgn(x - y) <= 0;
}
 

struct point /* vec */ {
    double x, y;
    point operator+(const point &p) {
        return {x + p.x, y + p.y};
    }
    point operator-(const point &p) {
        return {x - p.x, y - p.y};
    }
    bool operator<(const point &p) const{
        if(EQ(x, p.x)) return LE(y, p.y);
        return LE(x, p.x);
    }
};

struct line {
    // ax + by + c = 0
    double a, b, c;
};

struct circle {
    point p;
    double r;
};

double dot(point P, point Q) {
    return P.x*Q.x + P.y*Q.y;
}

double cross_2d(point P, point Q) {
    return P.x*Q.y - P.y*Q.x;
}

double points_distance(point A, point B, int deg) {
    point C = B - A;
    return pow(C.x*C.x + C.y*C.y, 0.5 * deg);
}

double abs(point P) {
    return points_distance(P, {0, 0}, 1);
}

line line_2points(point P, point Q) {
    return {P.y - Q.y, Q.x - P.x, P.x*Q.y - P.y*Q.x};
}

point lines_intersection(line l, line m) {
    if (abs(l.a*m.b - l.b*m.a) < eps) {
        assert(-1);
    }
    return {- (l.b*m.c - l.c*m.b) / (l.b*m.a - l.a*m.b),
            - (l.a*m.c - l.c*m.a) / (l.a*m.b - l.b*m.a)};
}

bool line_same(line l, line m) {
    if (l.c * m.c == 0) {
        if (l.c == m.c) {
            if (l.b * m.b == 0) {
                if (l.b == m.b) return 1;
                else return 0;
            }
            else return l.a / l.b == m.a / m.b; 
        }
        else return 0;
    }
    else return l.a / l.c == m.a / m.c && l.b / l.c == m.b / m.c;
}

bool on_line(point P, point Q, point R) {
    if (P.x > Q.x) swap(P, Q);
    if (P.y > Q.y) swap(P.y, Q.y);
    return (P.x <= R.x && R.x <= Q.x && P.y <= R.y && R.y <= Q.y);
}

double point_line_distance(point P, line l) {
    return abs(l.a * P.x + l.b * P.y + l.c) / sqrt(l.a*l.a + l.b*l.b);
}

double point_segment_distance(point p1, point p2, point q) {
    if (dot(q - p1, p2 - p1) <= 0) return points_distance(p1, q, 1);
    else if (dot(q - p2, p1 - p2) <= 0) return points_distance(p2, q, 1);
    else return point_line_distance(q, line_2points(p1, p2));
}

double is_segments_intersect(point p1, point p2, point q1, point q2) {
    line s0 = line_2points(p1, p2);
    line s1 = line_2points(q1, q2);
    if (abs(s0.a*s1.b - s0.b*s1.a) < eps) {
        if (p1.x > p2.x) swap(p1, p2);
        if (p1.y > p2.y) swap(p1.y, p2.y);
        if (q1.x > q2.x) swap(q1, q2);
        if (q1.y > q2.y) swap(q1.y, q2.y);
        if (line_same(s0, s1)) {
            return (q1.x <= p2.x && p1.x <= q2.x && q1.y <= p2.y && p1.y <= q2.y);
        }
        else return 0;
    }
    return cross_2d(p2 - p1, q1 - p1) * cross_2d(p2 - p1, q2 - p1) < eps
        && cross_2d(q2 - q1, p1 - q1) * cross_2d(q2 - q1, p2 - q1) < eps;
}

vector<point> convex_hull(vector<point> P) {
    int n = P.size(), k = 0;
    sort(all(P));
    vector<point> ch(2 * n);
    for (int i = 0; i < n; i++) {
        while (k >= 2 && LE(cross_2d(ch[k - 1] - ch[k - 2], P[i] - ch[k - 1]), 0)) k--;
        ch[k] = P[i];
        k++;
    }
    for (int i = n - 2, t = k; i >= 0; i--) {
        while (k > t && LE(cross_2d(ch[k - 1] - ch[k - 2], P[i] - ch[k - 1]), 0)) k--;
        ch[k] = P[i];
        k++;
    }
    ch.resize(k - 1);
    return ch;
}


vector<point> circles_intersection(circle A, circle B) {
    vector<point> ret;
    point X = A.p;
    B.p = B.p - A.p;
    A.p = {0, 0};

    if (points_distance(A.p, B.p, 2) - pow(A.r + B.r, 2) > eps) return ret;

    double K = (B.p.x*B.p.x + B.p.y*B.p.y + A.r*A.r - B.r*B.r) / 2;
    double SQ = (B.p.x*B.p.x + B.p.y*B.p.y)*A.r*A.r - K * K;
    double DS = points_distance(A.p, B.p, 2);
    //cerr << K _ SQ _ DS << endl;
    if (SQ < 0) return ret;
    if (abs(SQ) < eps) {
        ret.push_back({K*B.p.x / DS + X.x, K*B.p.y / DS + X.y});
        return ret;
    }
    ret.push_back({(K*B.p.x + B.p.y*sqrt(SQ)) / DS + X.x,
                   (K*B.p.y - B.p.x*sqrt(SQ)) / DS + X.y});
    ret.push_back({(K*B.p.x - B.p.y*sqrt(SQ)) / DS + X.x,
                   (K*B.p.y + B.p.x*sqrt(SQ)) / DS + X.y});
    return ret;
}
 
int main() {
    int n;
    cin >> n;
    vector<point> p(n);
    for (int i = 0; i < n; i++) {
        cin >> p[i].x >> p[i].y;
    }
    vector<point> ans = convex_hull(p);
    cout << ans.size() << endl;
    double mn = 1e100;
    int mn_idx = -1;
    for (int i = 0; i < n; i++) {
        if (mn > ans[i].y) mn_idx = i;
        else if (mn == ans[i].y) {
            if (ans[i].x < ans[mn_idx].x) mn_idx = i;
        }
        mn = min(mn, ans[i].y);
    }
    for (int i = 0; i < ans.size(); i++) {
        cout << ans[(i + mn_idx) % ans.size()].x _ ans[(i + mn_idx) % ans.size()].y << endl;
    }
}


Measured memory_bytes: 9100