//include
//------------------------------------------
#include <vector>
#include <list>
#include <map>
#include <climits>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <queue>
#include <random>
#include <cctype>
#include <complex>
#include <regex>

using namespace std;

#define C_MAX(a, b) ((a)>(b)?(a):(b))
#define SHOW_VECTOR(v) {std::cerr << #v << "\t:";for(const auto& xxx : v){std::cerr << xxx << " ";}std::cerr << "\n";}
#define SHOW_MAP(v){std::cerr << #v << endl; for(const auto& xxx: v){std::cerr << xxx.first << " " << xxx.second << "\n";}}

typedef complex<double> P;
typedef vector<P> Poly;

#define EPS 1e-8
#define EQ (abs((a)-(b))<EPS)
const double PI = acos(-1.0);

inline int signum(double x) { return abs(x) < EPS ? 0 : x > 0 ? 1 : -1; }

namespace std {
    bool operator<(const P &a, const P &b) {
        return a.real() == b.real() ? a.imag() < b.imag() : a.real() < b.real();
    }
}

double dot(P a, P b) {
    return a.real() * b.real() + a.imag() * b.imag();
}

double cross(P a, P b) {
    return a.real() * b.imag() - a.imag() * b.real();
}

int ccw(P a, P b, P c) {
    b -= a;
    c -= a;
    int sign = signum(cross(b, c));
    if (abs(sign) == 1) return sign;
    if (signum(dot(b, c)) < 0) return -2;
    if (abs(b) < abs(c)) return 2;
    return 0;
}

double area_poly(Poly poly) {
    double ans = 0.0;
    for (int i = 0; i < poly.size(); i++) ans += cross(poly[i], poly[(i + 1) % poly.size()]);
    return abs(ans) / 2.0;
}

bool is_convex(Poly poly) {
    if (poly.size() < 3) return false;
    int s = -3;
    int n = poly.size();
    for (int i = 0; i < poly.size(); i++) {
        int r = ccw(poly[i], poly[(i + 1) % n], poly[(i + 2) % n]);
        if (s == -3 && abs(r) == 1) s = r;
        if (s * r == -1) return false;
    }
    return true;
}

Poly convex_hull(Poly poly) {
    Poly g;
    int n = poly.size();
    int m;

    if (n < 3) return poly;

    sort(poly.begin(), poly.end());
    for (int i = 0; i < poly.size(); i++) {
        while ((m = g.size()) >= 2 && ccw(g[m - 2], g[m - 1], poly[i]) <= 0) g.pop_back();
        g.push_back(poly[i]);
    }
    int t = g.size();
    for (int i = n - 2; i >= 0; i--) {
        while ((m = g.size()) > t && ccw(g[m - 2], g[m - 1], poly[i]) <= 0) g.pop_back();
        g.push_back(poly[i]);
    }
    g.pop_back();
    return g;
}

int main() {

    int N;
    cin >> N;

    Poly poly(N);
    for (int i = 0; i < N; i++) {
        double x, y;
        cin >> x >> y;
        poly[i] = P(x, y);
    }

    auto res = convex_hull(poly);
    int n = res.size();

    cout << n << endl;

    int s = 0;
    for (int i = 1; i < n; i++)
        if (res[i].imag() < res[s].imag() ||
            (res[i].imag() == res[s].imag() && res[i].real() < res[s].real()))
            s = i;

    for (int i = 0; i < n; i++) {
        cout << res[(i + s) % n].real() << " " << res[(i + s) % n].imag() << endl;
    }

}














































Measured memory_bytes: 7536