#include <bits/stdc++.h>

using namespace std;
using uint = unsigned int;
using ll = long long;
using ull = unsigned long long;
constexpr ll TEN(int n) { return (n==0) ? 1 : 10*TEN(n-1); }
template<class T> using V = vector<T>;
template<class T> using VV = V<V<T>>;

template<class T> ostream& operator<<(ostream& os, const V<T> &v) {
    os << "["; for (auto p: v) os << p << ", "; os << "]";
    return os;
}

using D = double;
const D PI = acos(D(-1)), EPS = 1e-10;

int sgn(D a) { return (abs(a) <= EPS) ? 0 : (a < 0 ? -1 : 1); }
int sgn(D a, D b) { return sgn(a-b); }
//relative sign
// int rsgn(D a, D f) {
//     if (abs(a) <= f*EPS) return 0;
//     return (a < 0) ? -1 : 1;
// }
struct Pt2 {
    D x, y;
    Pt2() {}
    Pt2(D _x, D _y) : x(_x), y(_y) {}
    Pt2 operator+(const Pt2 &r) const { return Pt2(x+r.x, y+r.y); }
    Pt2 operator-(const Pt2 &r) const { return Pt2(x-r.x, y-r.y); }
    Pt2 operator*(const Pt2 &r) const { return Pt2(x*r.x-y*r.y, x*r.y+y*r.x); }

    Pt2 operator*(const D &r) const { return Pt2(x*r, y*r); }
    Pt2 operator/(const D &r) const { return Pt2(x/r, y/r); }

    Pt2& operator+=(const Pt2 &r) { return *this=*this+r; }
    Pt2& operator-=(const Pt2 &r) { return *this=*this-r; }
    Pt2& operator*=(const Pt2 &r) { return *this=*this*r; }
    Pt2& operator*=(const D &r) { return *this=*this*r; }
    Pt2& operator/=(const D &r) { return *this=*this/r; }
    
    Pt2 operator-() const { return Pt2(-x, -y); }

    bool operator<(const Pt2 &r) const { return 2*sgn(x, r.x)+sgn(y, r.y)<0; }
    bool operator==(const Pt2 &r) const { return sgn((*this-r).rabs()) == 0; }

    D norm() const { return x*x + y*y; }
    D abs() const { return sqrt(norm()); }
    D rabs() const { return max(std::abs(x), std::abs(y)); } // robust abs
    D arg() const { return atan2(y, x); }

    pair<D, D> to_pair() const { return make_pair(x, y); }
    static Pt2 polar(D le, D th) { return Pt2(le*cos(th), le*sin(th)); }
};
ostream& operator<<(ostream& os, const Pt2 &p) {
    return os << "P(" << p.x << ", " << p.y << ")";
}
using P = Pt2;

struct L {
    P s, t;
    L() {}
    L(P _s, P _t) : s(_s), t(_t) {}
    P vec() const { return t-s; }
    D abs() const { return vec().abs(); }
    D arg() const { return vec().arg(); }
};
ostream& operator<<(ostream& os, const L &l) {
    return os << "L(" << l.s << ", " << l.t << ")";
}

D cross(P a, P b) { return a.x*b.y - a.y*b.x; }
D dot(P a, P b) { return a.x*b.x + a.y*b.y; }
// cross(a, b) is too small?
int sgncrs(P a, P b) {
    D cr = cross(a, b);
    if (abs(cr) <= (a.rabs() + b.rabs()) * EPS) return 0;
    return (cr < 0) ? -1 : 1;
}

// -2, -1, 0, 1, 2 : front, clock, on, cclock, back
int ccw(P b, P c) {
    int s = sgncrs(b, c);
    if (s) return s;
    if (!sgn(c.rabs()) || !sgn((c-b).rabs())) return 0;
    if (dot(b, c) < 0) return 2;
    if (dot(-b, c-b) < 0) return -2;
    return 0;
}
int ccw(P a, P b, P c) { return ccw(b-a, c-a); }
int ccw(L l, P p) { return ccw(l.s, l.t, p); }

using Pol = V<P>;

D area2(const Pol &pol) {
    D u = 0;
    P a = pol.back();
    for (auto b: pol) u += cross(a, b), a = b;
    return u;
}

// 0: outside, 1: on line, 2: inside
int contains(const Pol &pol, P p) {
    int in = -1;
    P _a, _b = pol.back();
    for (int i = 0; i < int(pol.size()); i++) {
        _a = _b; _b = pol[i];
        P a = _a, b = _b;
        if (ccw(a, b, p) == 0) return 1;
        if (a.y > b.y) swap(a, b);
        if (!(a.y <= p.y && p.y < b.y)) continue;
        if (sgn(a.y, p.y) ? (cross(a-p, b-p) > 0) : (a.x > p.x)) in *= -1;
    }
    return in + 1;
}

// p must be sorted and uniqued!
Pol convex_down(const Pol &ps) {
    assert(ps.size() >= 2);
    Pol dw;
    for (P d: ps) {
        size_t n;
        while ((n = dw.size()) > 1) {
            if (ccw(dw[n-2], dw[n-1], d) != -1) break; // line上も取る
//            if (ccw(dw[n-2], dw[n-1], d) == 1) break;
            dw.pop_back();
        }
        dw.push_back(d);
    }
    return dw;
}

Pol convex(Pol ps) {
    sort(begin(ps), end(ps));
    ps.erase(unique(begin(ps), end(ps)), end(ps));
    if (ps.size() <= 1) return ps;
    Pol dw = convex_down(ps);
    reverse(begin(ps), end(ps));
    Pol up = convex_down(ps);
    dw.insert(begin(dw), begin(up) + 1, end(up) - 1);
    return dw;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cout << setprecision(20) << fixed;
 
    int n;
    cin >> n;
    V<P> p(n);
    for (int i = 0; i < n; i++) {
        D x, y;
        cin >> x >> y;
        p[i] = P(x, y);
    }
    p = convex(p);
    n = int(p.size());
    int s = 0;
    for (int i = 0; i < n; i++) {
        if (p[i].y < p[s].y || (p[i].y == p[s].y && p[i].x < p[s].x)) s = i;
    }
    cout << n << endl;
    for (int i = 0; i < n; i++) {
        P q = p[(s+i)%n];
        cout << int(q.x) << " " << int(q.y) << endl;
    }
 
    return 0;
}



Measured memory_bytes: 8220