Zombies have found out about the Zombie Contamination level checker and managed to damage it! Now detecting the shape of their main compound will be a real challenge for Heidi. As before, a lair can be represented as a strictly convex polygon on a lattice. Each vertex of the polygon occupies a point on the lattice. However, the damaged Zombie Contamination level checker can only tell, for each cell, whether the level of Zombie Contamination for that cell is in the set {1, 2, 3}. In other words, Heidi knows all the cells of the lattice for which the Contamination level is not 0 and not 4.Given this information, Heidi still wants to know the exact shape of the lair to rain destruction on the zombies. Help her!

The input contains multiple test cases. The first line of each test case contains two space-separated integers N and M, where N is the size of the lattice grid (5 ≤ N ≤ 100000) and M is the number of lattice points for which the Zombie Contamination level is 1, 2, or 3 (8 ≤ M ≤ 200000). The second line of each test case contains M pairs of integers x1, y1, ..., xM, yM – coordinates of the cells with Zombie Contamination level not equal to 0 nor 4. It is guaranteed that 1 ≤ xi, yi ≤ N. All pairs xi, yi are different. Cells are enumerated based on the coordinates of their upper right corner. This means that the bottommost leftmost cell that touches the origin has coordinates (1, 1), and the uppermost leftmost cell is identified as (1, N). The last line of the file contains two zeroes. This line should not be treated as a test case. The sum of the M values for all tests in one file will not exceed 200000.

For each test case, the following output is expected: The first line of the output should contain one integer V, the number of vertices of the polygon that is the secret lair. The next V lines each should contain two integers, denoting the vertices of the polygon in the clockwise order, starting from the lexicographically smallest vertex.

NoteIt is guaranteed that the solution always exists and is unique. It is guaranteed that in the correct solution the coordinates of the polygon vertices are between 1 and N - 1. A vertex (x1, y1) is lexicographically smaller than vertex (x2, y2) if x1 < x2 or .

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#include <cstdio>
#include <stdlib.h>
#include <stack>
#include <numeric>
#include <bitset>
#include <cctype>
#include <list>
#include <assert.h>
#include <random>
#include <unordered_map>
#include <ctime>
typedef  long long ll;
using namespace std;
#define INF 2147483647
#define infL (1LL<<60)
#define inf (1<<30)
#define inf9 (1000000000)
#define MOD 1000000007
#define EPS 1e-18
#define Gr 9.8
#define PI acos(-1)
#define REP(i,n) for(int (i)=0;(i)<(int)(n);(i)++)
#define REQ(i,n) for(int (i)=1;(i)<=(int)(n);(i)++)
#define lch (rt<<1)
#define rch (rt<<1|1)
#define readmp(n) for(int i=0,u,v;i<n;i++) {scanf("%d%d",&u,&v); mp[u].push_back(v); mp[v].push_back(u);}
typedef pair<int, int> pii;
typedef long double ld;
typedef unsigned int uint;
#define MAX 300105
bool debug = 0;
int n,m,k;
int dx[4] = {0,1,0,-1}, dy[4] = {1,0,-1,0};
string direc="RDLU";
ll ln, lk, lm;
void etp(bool f = 0) {
    puts(f ?"Yes" : "No");
    exit(0);
}
void addmod(int &x, int y, int mod = MOD) {
    x+=y; if (x>=mod) x-=mod;
}
void et() {
    puts("-1"); exit(0);
}
 ll fastPow(ll x, ll y, int mod=MOD) {
     ll ans = 1;
     while(y>0) {
         if(y&1) ans = (x * ans)%mod;
         x = x*x%mod;
         y>>=1;
     }
     return ans;
 }

typedef ll ValType;
struct Point {
    ValType x, y;
    Point() { }
    Point(ValType x, ValType y) : x(x), y(y) { }

    Point operator+(const Point& o) const { return Point(x + o.x, y + o.y); }
    Point operator-(const Point& o) const { return Point(x - o.x, y - o.y); }
    bool operator<(const Point& o) const { return x < o.x || (x == o.x  && y < o.y); }
    friend bool operator == (const Point &r1,const Point &r2)
    {return r1.x==r2.x&&r1.y==r2.y;}
    ValType cross(Point b) const {return x*b.y- b.x*y;}
    void readin() {
        scanf("%lld%lld", &x, &y);
    }
    void pp() {
        printf("%lld %lld\n",x,y);
    }
}p[MAX];

vector<Point> convex(vector<Point> &vp) {
    sort(vp.begin(), vp.end());
    int N = unique(vp.begin(),vp.end())-vp.begin();
    vector<Point> ans1,ans2;
    REP(i,N) {
        while(ans1.size()>1) {
            Point o=ans1[ans1.size()-2], a= ans1.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans1.pop_back();
            } else break;
        }
        ans1.push_back(vp[i]);
    }
    for(int i=N-1;i>=0;i--) {
        while(ans2.size()>1) {
            Point o=ans2[ans2.size()-2], a= ans2.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans2.pop_back();
            } else break;
        }
        ans2.push_back(vp[i]);
    }
    for(int i=1;i<ans2.size()-1;i++) ans1.push_back(ans2[i]);
    return ans1;
}

ll xl[MAX],xr[MAX],yl[MAX],yr[MAX];
bool isIn(ll x, ll y) {
    for(int i=0;i<=1;i++)
        for(int j=0;j<=1;j++)
            if(xl[y+j]>x+i||xr[y+j]<x+i||yl[x+i]>y+j||yr[x+i]<y+j)
                return 0;
    return 1;
}
void fmain() {
    REP(i,MAX) {
        xl[i]=infL; yl[i]=infL;
    }
    while (~scanf("%d%d", &n,&m)) {
        if (n==0) break;
        REQ(i,m) p[i].readin();
        REQ(i,m) {
            xl[p[i].y]=min(xl[p[i].y], p[i].x);
            xr[p[i].y]=max(xr[p[i].y], p[i].x);
            yl[p[i].x] = min(yl[p[i].x], p[i].y);
            yr[p[i].x] = max(yr[p[i].x], p[i].y);
        }
        vector<Point> vp;
        REQ(i,m) {
            ll x=p[i].x,y=p[i].y;
            if (isIn(x, y)) vp.push_back(Point(x,y));
            if (isIn(x-1, y)) vp.push_back(Point(x-1,y));
            if (isIn(x, y-1)) vp.push_back(Point(x,y-1));
            if (isIn(x-1, y-1)) vp.push_back(Point(x-1,y-1));
//            int tio=0;
        }
        vector<Point> ans = convex(vp);
        printf("%d\n", ans.size());
        ans[0].pp();
        for(int i=ans.size()-1;i>=1;i--) ans[i].pp();

        REQ(i,m) {
            xl[p[i].y]=infL;
            xr[p[i].y]=0;
            yl[p[i].x] = infL;
            yr[p[i].x] = 0;
        }
    }
}
int main() {
    fmain();
    return 0;
}

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#include <cstdio>
#include <stdlib.h>
#include <stack>
#include <numeric>
#include <bitset>
#include <cctype>
#include <list>
#include <assert.h>
#include <random>
#include <unordered_map>
#include <ctime>
typedef  long long ll;
using namespace std;
#define INF 2147483647
#define infL (1LL<<60)
#define inf (1<<30)
#define inf9 (1000000000)
#define MOD 1000000007
#define EPS 1e-18
#define Gr 9.8
#define PI acos(-1)
#define REP(i,n) for(int (i)=0;(i)<(int)(n);(i)++)
#define REQ(i,n) for(int (i)=1;(i)<=(int)(n);(i)++)
#define lch (rt<<1)
#define rch (rt<<1|1)
#define readmp(n) for(int i=0,u,v;i<n;i++) {scanf("%d%d",&u,&v); mp[u].push_back(v); mp[v].push_back(u);}
typedef pair<int, int> pii;
typedef long double ld;
typedef unsigned int uint;
#define MAX 200105
bool debug = 0;
int n,m,k;
int dx[4] = {0,1,0,-1}, dy[4] = {1,0,-1,0};
string direc="RDLU";
ll ln, lk, lm;
void etp(bool f = 0) {
    puts(f ?"Yes" : "No");
    exit(0);
}
void addmod(int &x, int y, int mod = MOD) {
    x+=y; if (x>=mod) x-=mod;
}
void et() {
    puts("-1"); exit(0);
}
 ll fastPow(ll x, ll y, int mod=MOD) {
     ll ans = 1;
     while(y>0) {
         if(y&1) ans = (x * ans)%mod;
         x = x*x%mod;
         y>>=1;
     }
     return ans;
 }

typedef ll ValType;
struct Point {
    ValType x, y;
    Point() { }
    Point(ValType x, ValType y) : x(x), y(y) { }

    Point operator+(const Point& o) const { return Point(x + o.x, y + o.y); }
    Point operator-(const Point& o) const { return Point(x - o.x, y - o.y); }
    bool operator<(const Point& o) const { return x < o.x || (x == o.x  && y < o.y); }
    friend bool operator == (const Point &r1,const Point &r2)
    {return r1.x==r2.x&&r1.y==r2.y;}
    ValType cross(Point b) const {return x*b.y- b.x*y;}
    void readin() {
        scanf("%lld%lld", &x, &y);
    }
    void pp() {
        printf("%lld %lld\n",x,y);
    }
}p[MAX];

vector<Point> convex(vector<Point> &vp) {
    sort(vp.begin(), vp.end());
    int N = unique(vp.begin(),vp.end())-vp.begin();
    vector<Point> ans1,ans2;
    REP(i,N) {
        while(ans1.size()>1) {
            Point o=ans1[ans1.size()-2], a= ans1.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans1.pop_back();
            } else break;
        }
        ans1.push_back(vp[i]);
    }
    for(int i=N-1;i>=0;i--) {
        while(ans2.size()>1) {
            Point o=ans2[ans2.size()-2], a= ans2.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans2.pop_back();
            } else break;
        }
        ans2.push_back(vp[i]);
    }
    for(int i=1;i<ans2.size()-1;i++) ans1.push_back(ans2[i]);
    return ans1;
}

ll xl[MAX],xr[MAX],yl[MAX],yr[MAX];
bool isIn(ll x, ll y) {
    for(int i=0;i<=1;i++)
        for(int j=0;j<=1;j++)
            if(xl[y+j]>x+i||xr[y+j]<x+i||yl[x+i]>y+j||yr[x+i]<y+j)
                return 0;
    return 1;
}
void fmain() {
    REP(i,MAX) {
        xl[i]=infL; yl[i]=infL;
    }
    while (~scanf("%d%d", &n,&m)) {
        if (n==0) break;
        REQ(i,m) p[i].readin();
        REQ(i,m) {
            xl[p[i].y]=min(xl[p[i].y], p[i].x);
            xr[p[i].y]=max(xr[p[i].y], p[i].x);
            yl[p[i].x] = min(yl[p[i].x], p[i].y);
            yr[p[i].x] = max(yr[p[i].x], p[i].y);
        }
        vector<Point> vp;
        REQ(i,m) {
            ll x=p[i].x,y=p[i].y;
            if (isIn(x, y)) vp.push_back(Point(x,y));
            if (isIn(x-1, y)) vp.push_back(Point(x-1,y));
            if (isIn(x, y-1)) vp.push_back(Point(x,y-1));
            if (isIn(x-1, y-1)) vp.push_back(Point(x-1,y-1));
//            int tio=0;
        }
        vector<Point> ans = convex(vp);
        printf("%d\n", ans.size());
        ans[0].pp();
        for(int i=ans.size()-1;i>=1;i--) ans[i].pp();

        REQ(i,m) {
            xl[p[i].y]=infL;
            xr[p[i].y]=0;
            yl[p[i].x] = infL;
            yr[p[i].x] = 0;
        }
    }
}
int main() {
    fmain();
    return 0;
}

#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define F0R(i, a) for (int i = 0; i < (a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= (a); i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
#define trav(a, x) for (auto& a : x)

#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound

#define sz(x) (int)x.size()
#define all(x) begin(x), end(x)
#define rsz resize

const int MOD = 1000000007; // 998244353
const ll INF = 1e18;
const int MX = 200005;
const ld PI = 4*atan((ld)1);

template<class T> void ckmin(T &a, T b) { a = min(a, b); }
template<class T> void ckmax(T &a, T b) { a = max(a, b); }

namespace input {
    template<class T> void re(complex<T>& x);
    template<class T1, class T2> void re(pair<T1,T2>& p);
    template<class T> void re(vector<T>& a);
    template<class T, size_t SZ> void re(array<T,SZ>& a);

    template<class T> void re(T& x) { cin >> x; }
    void re(double& x) { string t; re(t); x = stod(t); }
    void re(ld& x) { string t; re(t); x = stold(t); }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) {
        re(first); re(rest...);
    }

    template<class T> void re(complex<T>& x) { T a,b; re(a,b); x = cd(a,b); }
    template<class T1, class T2> void re(pair<T1,T2>& p) { re(p.f,p.s); }
    template<class T> void re(vector<T>& a) { F0R(i,sz(a)) re(a[i]); }
    template<class T, size_t SZ> void re(array<T,SZ>& a) { F0R(i,SZ) re(a[i]); }
}

using namespace input;

namespace output {
    template<class T1, class T2> void pr(const pair<T1,T2>& x);
    template<class T, size_t SZ> void pr(const array<T,SZ>& x);
    template<class T> void pr(const vector<T>& x);
    template<class T> void pr(const set<T>& x);
    template<class T1, class T2> void pr(const map<T1,T2>& x);

    template<class T> void pr(const T& x) { cout << x; }
    template<class Arg, class... Args> void pr(const Arg& first, const Args&... rest) {
        pr(first); pr(rest...);
    }

    template<class T1, class T2> void pr(const pair<T1,T2>& x) {
        pr("{",x.f,", ",x.s,"}");
    }
    template<class T> void prContain(const T& x) {
        pr("{");
        bool fst = 1; for (const auto& a: x) pr(!fst?", ":"",a), fst = 0; // const needed for vector<bool>
        pr("}");
    }
    template<class T, size_t SZ> void pr(const array<T,SZ>& x) { prContain(x); }
    template<class T> void pr(const vector<T>& x) { prContain(x); }
    template<class T> void pr(const set<T>& x) { prContain(x); }
    template<class T1, class T2> void pr(const map<T1,T2>& x) { prContain(x); }

    void ps() { pr("\n"); }
    template<class Arg> void ps(const Arg& first) {
        pr(first); ps(); // no space at end of line
    }
    template<class Arg, class... Args> void ps(const Arg& first, const Args&... rest) {
        pr(first," "); ps(rest...); // print w/ spaces
    }
}

using namespace output;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0); // fast I/O
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); } // for USACO
    }
}

using namespace io;

template<class T> T invGeneral(T a, T b) {
    a %= b; if (a == 0) return b == 1 ? 0 : -1;
    T x = invGeneral(b,a);
    return x == -1 ? -1 : ((1-(ll)b*x)/a+b)%b;
}

template<class T> struct modular {
    T val;
    explicit operator T() const { return val; }
    modular() { val = 0; }
    modular(const ll& v) {
        val = (-MOD <= v && v <= MOD) ? v : v % MOD;
        if (val < 0) val += MOD;
    }

    friend ostream& operator<<(ostream& os, const modular& a) { return os << a.val; }
    friend bool operator==(const modular& a, const modular& b) { return a.val == b.val; }
    friend bool operator!=(const modular& a, const modular& b) { return !(a == b); }
    friend bool operator<(const modular& a, const modular& b) { return a.val < b.val; }

    modular operator-() const { return modular(-val); }
    modular& operator+=(const modular& m) { if ((val += m.val) >= MOD) val -= MOD; return *this; }
    modular& operator-=(const modular& m) { if ((val -= m.val) < 0) val += MOD; return *this; }
    modular& operator*=(const modular& m) { val = (ll)val*m.val%MOD; return *this; }
    friend modular pow(modular a, ll p) {
        modular ans = 1; for (; p; p /= 2, a *= a) if (p&1) ans *= a;
        return ans;
    }
    friend modular inv(const modular& a) {
        auto i = invGeneral(a.val,MOD); assert(i != -1);
        return i;
    } // equivalent to return exp(b,MOD-2) if MOD is prime
    modular& operator/=(const modular& m) { return (*this) *= inv(m); }

    friend modular operator+(modular a, const modular& b) { return a += b; }
    friend modular operator-(modular a, const modular& b) { return a -= b; }
    friend modular operator*(modular a, const modular& b) { return a *= b; }

    friend modular operator/(modular a, const modular& b) { return a /= b; }
};

typedef modular<int> mi;
typedef pair<mi,mi> pmi;
typedef vector<mi> vmi;
typedef vector<pmi> vpmi;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

typedef ll T;

namespace Point {
    typedef pair<T,T> P;
    typedef vector<P> vP;

    P dir(T ang) {
        auto c = exp(ang*complex<T>(0,1));
        return P(c.real(),c.imag());
    }

    T norm(P x) { return x.f*x.f+x.s*x.s; }
    T abs(P x) { return sqrt(norm(x)); }
    T angle(P x) { return atan2(x.s,x.f); }
    P conj(P x) { return P(x.f,-x.s); }

    P operator+(const P& l, const P& r) { return P(l.f+r.f,l.s+r.s); }
    P operator-(const P& l, const P& r) { return P(l.f-r.f,l.s-r.s); }
    P operator*(const P& l, const T& r) { return P(l.f*r,l.s*r); }
    P operator*(const T& l, const P& r) { return r*l; }
    P operator/(const P& l, const T& r) { return P(l.f/r,l.s/r); }
    P operator*(const P& l, const P& r) { return P(l.f*r.f-l.s*r.s,l.s*r.f+l.f*r.s); }
    P operator/(const P& l, const P& r) { return l*conj(r)/norm(r); }

    P& operator+=(P& l, const P& r) { return l = l+r; }
    P& operator-=(P& l, const P& r) { return l = l-r; }
    P& operator*=(P& l, const T& r) { return l = l*r; }
    P& operator/=(P& l, const T& r) { return l = l/r; }
    P& operator*=(P& l, const P& r) { return l = l*r; }
    P& operator/=(P& l, const P& r) { return l = l/r; }

    P unit(P x) { return x/abs(x); }
    T dot(P a, P b) { return (conj(a)*b).f; }
    T cross(P a, P b) { return (conj(a)*b).s; }
    T cross(P p, P a, P b) { return cross(a-p,b-p); }
    T dist(P p, P a, P b) { return std::abs(cross(p,a,b))/abs(a-b); }

    P rotate(P a, T b) { return a*P(cos(b),sin(b)); }
    P reflect(P p, P a, P b) { return a+conj((p-a)/(b-a))*(b-a); }
    P foot(P p, P a, P b) { return (p+reflect(p,a,b))/(T)2; }
    P extension(P a, P b, P c, P d) {
        T x = cross(a,b,c), y = cross(a,b,d);
        return (d*x-c*y)/(x-y);
    }
    // computes the intersection of line segments AB, CD
    // verification: https://open.kattis.com/problems/segmentintersection
    vP segIntersect(P a, P b, P c, P d) {
        if (a > b) swap(a,b);
        if (c > d) swap(c,d);

        auto a1 = cross(a,b,c), a2 = cross(a,b,d);
        if (a1 > a2) swap(a1,a2);
        if (!(a1 <= 0 && a2 >= 0)) return {};

        if (a1 == 0 && a2 == 0) {
            if (cross(a,c,d) != 0) return {};
            auto x1 = max(a,c), x2 = min(b,d);
            if (x1 > x2) return {};
            if (x1 == x2) return {x1};
            return {x1,x2};
        }

        auto z = extension(a,b,c,d);
        if (a <= z && z <= b) return {z};
        return {};
    }

    // sorts points according to atan2
    // verification: ?
    template<class T> int half(pair<T,T> x) { return mp(x.s,x.f) > mp((T)0,(T)0); }
    bool cmp(P a, P b) {
        int A = half(a), B = half(b);
        if (A != B) return A < B;
        return cross(a,b) > 0;
    }

    // computes the center of mass of a polygon with constant mass per unit area
    // verification: kattis polygonarea, VT HSPC 2018 Holiday Stars
    T area(const vP& v) {
        T area = 0;
        F0R(i,sz(v)) {
            int j = (i+1)%sz(v); T a = cross(v[i],v[j]);
            area += a;
        }
        return std::abs(area)/2;
    }
    P centroid(const vP& v) {
        P cen(0,0); T area = 0; // 2*signed area
        F0R(i,sz(v)) {
            int j = (i+1)%sz(v); T a = cross(v[i],v[j]);
            cen += a*(v[i]+v[j]); area += a;
        }
        return cen/area/(T)3;
    }

    // tests whether a point is inside, on, or outside the perimeter of any polygon
    // verification: https://open.kattis.com/problems/pointinpolygon
    string inPoly(const vP& p, P z) {
        int n = sz(p), ans = 0;
        F0R(i,n) {
            P x = p[i], y = p[(i+1)%n];
            if (cross(x,y,z) == 0 && min(x,y) <= z && z <= max(x,y)) return "on";
            if (x.s > y.s) swap(x,y);
            if (x.s <= z.s && y.s > z.s && cross(z,x,y) > 0) ans ^= 1;
        }
        return ans ? "in" : "out";
    }

    pair<P,double> ccCenter(P a, P b, P c) { // circumcenter
        b -= a; c -= a;
        P res = b*c*(conj(c)-conj(b))/(b*conj(c)-conj(b)*c);
        return {a+res,abs(res)};
    }

    pair<P, double> mec(vP ps) { // minimum enclosing circle, ex. USACO Camp 2019 Contest 2 #4
        shuffle(all(ps), mt19937(time(0)));
        P o = ps[0]; double r = 0, EPS = 1 + 1e-8;
        F0R(i,sz(ps)) if (abs(o-ps[i]) > r*EPS) {
            o = ps[i], r = 0;
            F0R(j,i) if (abs(o-ps[j]) > r*EPS) {
                o = (ps[i]+ps[j])/2, r = abs(o-ps[i]);
                F0R(k,j) if (abs(o-ps[k]) > r*EPS)
                    tie(o,r) = ccCenter(ps[i],ps[j],ps[k]);
            }
        }
        return {o,r};
    }
};

using namespace Point;

vP convex_hull(vP P) {
    sort(all(P)); P.erase(unique(all(P)),P.end());
    int n = sz(P); if (n <= 1) return P;

    vP bot = {P[0]};
    FOR(i,1,n) {
        while (sz(bot) > 1 && cross(bot[sz(bot)-2], bot.back(), P[i]) <= 0) bot.pop_back();
        bot.pb(P[i]);
    }
    bot.pop_back();

    vP up = {P[n-1]};
    F0Rd(i,n-1) {
        while (sz(up) > 1 && cross(up[sz(up)-2], up.back(), P[i]) <= 0) up.pop_back();
        up.pb(P[i]);
    }
    up.pop_back();

    bot.insert(bot.end(),all(up)); return bot;
}

int N,M;
vP bot, up;

bool above(int x, int y) {
	if (x < up[0].f || x > up.back().f) return 1;
	auto it = lb(all(up),P(x,-MOD));
	if (it->f == x) return y > it->s;
	return cross(*prev(it),*it,P(x,y)) > 0;
	// ps(bot,up); exit(0);
}

bool below(int x, int y) {
	auto it = lb(all(bot),P(x,-MOD));
	if (it->f == x) return y < it->s;
	return cross(*prev(it),*it,P(x,y)) < 0;
}

bool zero(int x, int y) {
	return above(x,y) || below(x,y);
}

bool cool(int x, int y) {
	int cnt = 0;
	F0R(i,2) F0R(j,2) cnt += zero(x+i,y+j);
	return cnt == 3;
}

void solve() {
	re(N,M); if (N == 0) exit(0);
	vP v(M), res; re(v);
	auto c = convex_hull(v);
	int ind = 0; while (ind+1 < sz(c) && c[ind+1].f > c[ind].f) ind ++;
	bot = vP(begin(c),begin(c)+ind+1);
	up.clear();
	while (ind < sz(c)) up.pb(c[ind++]);
	up.pb(c[0]);
	if (up[sz(up)-2].f == up[sz(up)-1].f) up.pop_back();
	if (up[0].f == up[1].f) up.erase(up.begin());
	reverse(all(up));
	/*FORd(i,1,N+1) {
		FORd(j,1,N+1) pr(!zero(i,j));
		ps();
	}*/
	trav(t,v) F0R(I,2) F0R(J,2) if (cool(t.f-I,t.s-J)) res.pb({t.f+I-1,t.s+J-1});
	res = convex_hull(res); reverse(begin(res)+1,end(res));
	ps(sz(res));
	trav(t,res) ps(t.f,t.s);
}

int main() {
    setIO();
    while (1) solve();
}

/* stuff you should look for
    * int overflow, array bounds
    * special cases (n=1?), set tle
    * do smth instead of nothing and stay organized
*/

#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <list>
#include <cassert>
#include <ctime>
#include <climits>
using namespace std;

#define PB push_back
#define MP make_pair
#define SZ(v) ((int)(v).size())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)
#define REPE(i,n) FORE(i,0,n)
#define FORSZ(i,a,v) FOR(i,a,SZ(v))
#define REPSZ(i,v) REP(i,SZ(v))
typedef long long ll;
typedef unsigned long long ull;
ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); }

const int MAXN=100000;
const int MAXQ=200000;
const int MAXP=MAXQ;
const int DX[]={0,+1,0,-1},DY[]={+1,0,-1,0};
typedef struct P { int x,y; P() {} P(int x,int y):x(x),y(y) {} } P;
bool operator<(const P &a,const P &b) { if(a.x!=b.x) return a.x<b.x; return a.y<b.y; }
const P operator-(const P &a,const P &b) { return P(a.x-b.x,a.y-b.y); }
const int operator^(const P &a,const P &b) { return a.x*b.y-a.y*b.x; }
bool ok(const P &a,const P &b,const P &c) { return ((b-a)^(c-a))<0; }

int n;

P q[MAXQ]; int nq;

P p[MAXP]; int np;

P h[2*MAXP]; int nh;

int mx[MAXN+1],mn[MAXN+1];

bool iszero(int x,int y) { if(y<0||y>=n||mn[y]>mx[y]) return true; return x<mn[y]||x>mx[y]; }
void solve() {
	REP(i,n) mx[i]=INT_MIN,mn[i]=INT_MAX;
	REP(i,nq) { int x=q[i].x,y=q[i].y; if(x<mn[y]) mn[y]=x; if(x>mx[y]) mx[y]=x; }
	np=0;
	REP(i,nq) {
		REP(k,4) {
			int kk=(k+1)%4;
			if(iszero(q[i].x+DX[k],q[i].y+DY[k])&&iszero(q[i].x+DX[kk],q[i].y+DY[kk])) p[np++]=P(q[i].x+k/2,q[i].y+((k==1||k==2)?1:0));
		}
	}
	//nh=np; REP(i,np) h[i]=p[i];
	sort(p,p+np);
	nh=0;
	REP(i,np) {
		while(nh>=2&&!ok(h[nh-2],h[nh-1],p[i])) --nh;
		h[nh++]=p[i];
	}
	int th=nh;
	for(int i=np-1;i>=0;--i) {
		while(nh-th>=1&&!ok(h[nh-2],h[nh-1],p[i])) --nh;
		h[nh++]=p[i];
	}
	--nh;
	printf("%d\n",nh);
	REP(i,nh) printf("%d %d\n",h[i].x,h[i].y);
}

void run() {
	while(scanf("%d%d",&n,&nq)==2) {
		if(n==0&&nq==0) break;
		REP(i,nq) scanf("%d%d",&q[i].x,&q[i].y),--q[i].x,--q[i].y;
		solve();
	}
}

int main() {
	run();
	return 0;
}

#pragma comment(linker, "/STACK:20000000")
#include <vector>
#include <list>
#include <map>
#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 <cstring>
#include <cassert>
#include <cstdlib>
#include <ctime>

using namespace std;
typedef long long int64;
#ifdef HOME
	#define E(c) cerr<<#c
	#define Eo(x) cerr<<#x<<" = "<<(x)<<endl
	#define Ef(...) fprintf(stderr, __VA_ARGS__)
#else
	#define E(c) ((void)0)
	#define Eo(x) ((void)0)
	#define Ef(...) ((void)0)
#endif

struct Point {
	int x, y;

	Point() : x(0), y(0) {}
	Point(int x, int y) : x(x), y(y) {}

	Point operator- (Point b) const {
		return Point(x - b.x, y - b.y);
	}
	Point operator+ (Point b) const {
		return Point(x + b.x, y + b.y);
	}
	bool operator< (Point b) const {
		return make_pair(x, y) < make_pair(b.x, b.y);
	}
};

int64 cross (Point a, Point b) {
	return int64(a.x) * b.y - int64(a.y) * b.x;
}
int64 dot (Point a, Point b) {
	return int64(a.x) * b.x + int64(a.y) * b.y;
}

void Process(map<int, set<int>> &cells, set<Point> &dots) {
	for (auto it = cells.begin(); it != cells.end(); it++) {
		int x = it->first;
		const auto &ySet = it->second;
		int last = *ySet.begin();
		for (auto jt = ySet.begin(); jt != ySet.end(); jt++) {
			int curr = *jt;
			if (curr - last > 1) {
				dots.insert(Point(x, last+1));
				dots.insert(Point(x, curr));
				dots.insert(Point(x+1, last+1));
				dots.insert(Point(x+1, curr));
			}
			if (curr - last == 1) {
				if (cells.find(x+1) != cells.end()) {
					const auto &nSet = cells[x+1];
					if (nSet.find(last) != nSet.end() && nSet.find(curr) != nSet.end())
						dots.insert(Point(x+1, curr));
				}
			}
			last = curr;
		}
	}
}

int n, m;

set<Point> vis;
void DFS(const set<Point> &cmap, Point p) {
	vis.insert(p);
	for (int dx = -1; dx <= 1; dx++)
		for (int dy = -1; dy <= 1; dy++)
			if (abs(dx) + abs(dy) == 1) {
				Point np(p.x + dx, p.y + dy);
				if (cmap.find(np) != cmap.end() && vis.find(np) == vis.end())
					DFS(cmap, np);
			}
}

int main() {
#ifdef HOME
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	while (1) {
		scanf("%d%d", &n, &m);
		if (n == 0) break;

		set<Point> src;
		for (int i = 0; i < m; i++) {
			int x, y;
			scanf("%d%d", &x, &y);
			x--; y--;
			src.insert(Point(x, y));
		}

		set<Point> dots;
		while (!src.empty()) {
			Point p = *src.begin();
			DFS(src, p);

			map<int, set<int>> cells;
			for (auto it = vis.begin(); it != vis.end(); it++) {
				Point p = *it;
				src.erase(p);
				cells[p.x].insert(p.y);
			}
			vis.clear();

			Process(cells, dots);
		}

		vector<Point> pts(dots.begin(), dots.end());
		Ef("%d\n", pts.size());
		for (int i = 0; i < pts.size(); i++)
			Ef("%d %d\n", pts[i].x, pts[i].y);

		Point ctr = pts[0];
		std::sort(pts.begin() + 1, pts.end(), [&](Point a, Point b) -> bool {
			int64 area = cross(a - ctr, b - ctr);
			if (area != 0)
				return area < 0;
			return dot(a - ctr, a - ctr) < dot(b - ctr, b - ctr);
		});

		vector<Point> hull;
		hull.push_back(pts[0]);
		hull.push_back(pts[1]);
        for (int i = 2; i < pts.size(); i++) {
			Point p = pts[i];
			while (hull.size() >= 2 && cross(hull.rbegin()[0] - hull.rbegin()[1], p - hull.rbegin()[0]) >= 0)
				hull.pop_back();
			hull.push_back(p);
        }

        printf("%d\n", hull.size());
        for (int i = 0; i < hull.size(); i++)
        	printf("%d %d\n", hull[i].x, hull[i].y);

	}
	return 0;
}

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

#define Pi 3.1415926535897932385
#define PRINTPOINT(_p_) cout<<"("<<_p_.x<<","<<_p_.y<<")"

struct Point{
	int x; int y;
	Point(){x=y=0;}
	Point(double _x, double _y){x=_x;y=_y;}
	friend Point operator +(const Point &a, const Point &b){return Point(b.x+a.x,b.y+a.y);}
	friend Point operator -(const Point &a, const Point &b){return Point(a.x-b.x,a.y-b.y);}
	friend Point operator *(const Point &a, double p){return Point(a.x*p, a.y*p);}
	friend Point operator /(const Point &a, double p){return Point(a.x/p, a.y/p);}
	friend double operator *(const Point &p, const Point &a){return (p.x*a.x+p.y*a.y);}
	friend double operator /(const Point &p, const Point &a){return (p.x*a.y-p.y*a.x);}
	friend bool operator <(const Point &a, const Point &b){
		if (a.x<b.x) return true;
		if (a.x>b.x) return false;
		if (a.y<b.y) return true;
		return false;
	}
	friend bool operator >(const Point &a, const Point &b){
		if (a.x>b.x) return true;
		if (a.x<b.x) return false;
		if (a.y>b.y) return true;
		return false;
	}
	friend bool operator ==(const Point &a, const Point &b){
		return (a.x==b.x && a.y==b.y);
	}
	friend bool operator !=(const Point &a, const Point &b){
		return (a.x!=b.x || a.y!=b.y);
	}
	double slope(){return y/x;}
	double measure(){return sqrt(x*x+y*y);}
	double angle(){
		double an=atan2(y,x);
		if (an<0) an+=2*Pi;
		return an;
	}
	Point shrink(){
		return Point(1,y/x);
	}
};

struct Hashdata{
	Point p;
	int t;
	Hashdata(){p=Point(); t=0;}
	Hashdata(Point _p, int _t){p=_p; t=_t;}
};

#define N 100010
#define M 200010
#define H 3000007
#define INF (double)1000000000000
#define _(_x_,_y_) Point(_x_,_y_)
#define eps ((double)1e-10)

int n,m,hc,cc;
int leftone[N], rightone[N];
Point peter[M], charles[4*M], harry[M];
int hull[M], q[M], nowtest;
Hashdata corner[H];

int point_hash(Point a){
	int x=a.x, y=a.y;
	return (x*10007+y)%H;
}

bool reader(){
	scanf("%d%d",&n,&m);
	if (n==0) return false;
	for (int i=1;i<=n;i++) leftone[i]=n,rightone[i]=0;
	for (int i=1;i<=m;i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		peter[i]=Point(x,y);
		if (x<leftone[y]) leftone[y]=x;
		if (x>rightone[y]) rightone[y]=x;
	}
	//for (int i=1;i<=m;i++) charles[i]=peter[i]-Point(0.5,0.5);
	return true;
}

void qsort(int l, int r){
	int i=l,j=r; Point mid=charles[(l+r)/2];
	do {
		while (charles[i]<mid) i++;
		while (charles[j]>mid) j--;
		if (i<=j) {
			Point t=charles[i]; charles[i]=charles[j]; charles[j]=t;
			i++; j--;
		}
	} while (i<=j);
	if (i<r) qsort(i,r);
	if (l<j) qsort(l,j);
}

void convex_hull(int vc){
	int qh=2; q[1]=vc; q[2]=vc-1;
	for (int i=vc-2;i>=1;i--) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	int qh1=qh;
	for (int i=1;i<=qh;i++) hull[i]=q[i];
	qh=2; q[1]=1; q[2]=2;
	for (int i=3;i<=vc;i++) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	for (int i=2;i<qh;i++) hull[qh1+i-1]=q[i];
	hc=qh1+qh-2;
	for (int i=0;i<hc;i++) harry[i]=charles[hull[i+1]];
}

bool in_hull(int x, int y){
	if (x<leftone[y]) return false;
	if (x>rightone[y]) return false;
	return true;
}

bool check_zeroes(int x, int y){
	if (!in_hull(x,y)) return false;
	if (!in_hull(x+1,y)) return false;
	if (!in_hull(x,y+1)) return false;
	if (!in_hull(x+1,y+1)) return false;
	return true;
}

void add_corner(Point a){
	//printf("Check: "); PRINTPOINT(a)<<endl;
	int h=point_hash(a);
	while (corner[h].t==nowtest) {
		if (corner[h].p==a) return;
		h=(h+1)%H;
	}
	//if (corner[h].p==a) return;
	corner[h]=Hashdata(a,nowtest);
	charles[++cc]=a;
}

void generate(){
	cc=0;
	for (int i=1;i<=m;i++) {
		int x=peter[i].x, y=peter[i].y;
		//printf("genloop i=%d, x=%d, y=%d\n",i,x,y);
		if (check_zeroes(x,y)) add_corner(Point(x,y));
		if (check_zeroes(x-1,y)) add_corner(Point(x-1,y));
		if (check_zeroes(x,y-1)) add_corner(Point(x,y-1));
		if (check_zeroes(x-1,y-1)) add_corner(Point(x-1,y-1));
	}
	qsort(1,cc);
	//memset(repeat,false,sizeof(repeat));
	//for (int i=2;i<=cc;i++) if (charles[i]==charles[i-1]) repeat[i]=true;
	//int nc=0;
	//for (int i=1;i<=cc;i++) if (!repeat[i]) charles[++nc]=charles[i];
	//cc=nc;
	//for (int i=1;i<=cc;i++) {
	//	PRINTPOINT(charles[i])<<endl;
	//}
}

void printer(){
	printf("%d\n",hc);
	Point starter=harry[0]; int si=0;
	for (int i=1;i<hc;i++) if (harry[i]<starter) starter=harry[i],si=i;
	for (int i=si;i<hc;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
	for (int i=0;i<si;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
}

int main(){
	nowtest=1;
	while (reader()) {
		generate();											//O(m log m)
		convex_hull(cc);									//O(m)
		printer();											//O(m)
		nowtest+=2;
	}
}

#include <cstdio>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <climits>
#include <cctype>
#include <utility>
#include <queue>
#include <cmath>
#include <complex>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
typedef pair<LL, LL> PLL;
typedef pair<int, LL> PIL;
typedef pair<LL, int> PLI;
typedef double DB;

#define pb push_back
#define mset(a, b) memset(a, b, sizeof a)
#define all(x) (x).begin(), (x).end()
#define bit(x) (1 << (x))
#define bitl(x) (1LL << (x))
#define sz(x) ((int)(x.size()))
#define cnti(x) (__builtin_popcount(x))
#define cntl(x) (__builtin_popcountll(x))
#define clzi(x) (__builtin_clz(x))
#define clzl(x) (__builtin_clzll(x))
#define ctzi(x) (__builtin_ctz(x))
#define ctzl(x) (__builtin_ctzll(x))

#define X first
#define Y second

#define Error(x) cout << #x << " = " << x << endl

template <typename T, typename U>
inline void chkmax(T& x, U y) {
	if (x < y) x = y;
}

template <typename T, typename U>
inline void chkmin(T& x, U y) {
	if (y < x) x = y;
}

typedef double DB;
const DB PI = acos(DB(-1));
const DB INF = 1e12;
const DB EPS = 1e-10;

inline DB sqr(DB x) {
	return x * x;
}

struct PT {
	DB x, y;

	PT() {}
	PT(DB x, DB y) : x(x), y(y) {}
} P[888888], Q[888888];

bool operator<(const PT& p1, const PT& p2) {
	if (fabs(p1.x - p2.x) > EPS) return p1.x < p2.x;
	return p1.y + EPS < p2.y;
}

bool operator==(const PT& p1, const PT& p2) {
	return fabs(p1.x - p2.x) < EPS && fabs(p1.y - p2.y) < EPS;
}

PT operator+(PT p1, PT p2) {
	return PT(p1.x + p2.x, p1.y + p2.y);
}

PT operator-(PT p1, PT p2) {
	return PT(p1.x - p2.x, p1.y - p2.y);
}

PT operator*(PT p, DB c) {
	return PT(p.x * c, p.y * c);
}

DB vect(PT p1, PT p2) {
	return p1.x * p2.y - p2.x * p1.y;
}

DB vect(PT p, PT p1, PT p2) {
	return vect(p1 - p, p2 - p);
}

int convex_hull(PT *p, int n, PT *q) {
	int i, k, m;

	sort(p, p + n);
	n = unique(p, p + n) - p;
	if (n == 1) {
		q[0] = p[0];
		return 1;
	}
	m = 0;
	for (i = 0; i < n; i++) {
		while (m > 1 && vect(q[m - 2], q[m - 1], p[i]) < EPS) m--;
		q[m++] = p[i];
	}
	k = m;
	for (i = n - 2; i >= 0; i--) {
		while (m > k && vect(q[m - 2], q[m - 1], p[i]) < EPS) m--;
		q[m++] = p[i];
	}
	return --m;
}

int dx[5] = {1, -1, 0, 0};
int dy[5] = {0, 0, 1, -1};

int main() {

	int n, m;
	while (scanf("%d%d", &n, &m) and n) {
		int k = 0;
		for (int i = 0; i < m; i++) {
			int x, y;
			scanf("%d%d", &x, &y);
			P[k++] = PT(x, y);
			P[k++] = PT(x - 1, y);
			P[k++] = PT(x - 1, y - 1);
			P[k++] = PT(x, y - 1);
		}
		m = convex_hull(P, k, Q);
		k = 0;
		for (int i = 0; i < m; i++) {
			int id = 0;
			double x, y;
			for(int j = 0; j < 4; j++) {
				x = Q[i].x + dx[j], y = Q[i].y + dy[j];
				PT pp = PT(x, y);
				if (vect(Q[i], Q[(i + 1) % m], pp) > -EPS and
					vect(Q[(i + m - 1) % m], Q[i], pp) > -EPS) id |= bit(j);
			}
			x = Q[i].x, y = Q[i].y;
			for (int j = 0; j < 4; j++) {
				if (id & bit(j)) {
					x += dx[j];
					y += dy[j];
				}
			}
			P[k++] = PT(x, y);
		}
		m = convex_hull(P, k, Q);
		int mx = 1111111, my = 1111111, id = -1;
		for (int i = 0; i < m; i++) {
			if (Q[i].x < mx) mx = Q[i].x, my = Q[i].y, id = i;
			else if ((int) Q[i].x == mx and Q[i].y < my) my = Q[i].y, id = i;
		}
		cout << m << endl;
		for (int i = m; i > 0; i--) {
			printf("%d %d\n", (int)(Q[(i + id) % m].x), (int)(Q[(i + id) % m].y));
		}
	}

	return 0;
}

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define M 1010
#define ep 1e-9

typedef pair <LL, LL> PII;

int n, m, id[M * M];

int dx[] = {-1, -1, 0, 0};
int dy[] = {-1, 0, -1, 0};

double ang[M * M];

vector <PII> v, in;

PII con[M * M];

PII operator - (PII a, PII b) {
  return PII(a.first - b.first, a.second - b.second);
}

LL operator ^ (PII a, PII b) {
  return a.first * b.second - a.second * b.first;
}

LL dist(PII a) {
  return a.first * a.first + a.second * a.second;
}

bool cmp(int i, int j) {
  if (fabs(ang[i] - ang[j]) > ep) {
    return ang[i] > ang[j];
  }
  return dist(v[i] - v[0]) < dist(v[j] - v[0]);
}

map <PII, bool> mp;

int main() {
  //freopen("in.txt", "r", stdin);
  int x, y;
  while (scanf("%d %d", &n, &m) && n) {
    in.clear(); v.clear(); mp.clear();
    int minx = n + 1, maxx = -1, miny, maxy;
    for (int i = 0; i < m; i++) {
      scanf("%d %d", &x, &y); in.push_back(PII(x, y));
      mp[PII(x, y)] = 1;
      if (minx > x || (minx == x && miny < y)) {
        minx = x; miny = y;
      }
      if (maxx < x || (maxx == x && maxy > y)) {
        maxx = x; maxy = y;
      }
    }

    PII lft = PII(minx, miny - 1);
    PII rgt = PII(maxx - 1, maxy);

    //printf("%d %d\n", lft.first, lft.second); printf("%d %d\n", rgt.first, rgt.second); puts("----");

    v.push_back(lft); v.push_back(rgt);

    for (int i = 0; i < m; i++) {
      for (int k = 0; k < 4; k++) {
        x = in[i].first + dx[k], y = in[i].second + dy[k];
        PII cur = PII(x, y);
        if (((cur - lft) ^ (rgt - lft)) > 0) {
          if (mp.count(cur) && mp.count(PII(cur.first + 1, cur.second))) {
            v.push_back(cur);
          }
        }
        else {
          if (mp.count(PII(cur.first, cur.second + 1)) && mp.count(PII(cur.first + 1, cur.second + 1))) {
            v.push_back(cur);
          }
        }
      }
    }

    sort(v.begin(), v.end());
    v.resize(unique(v.begin(), v.end()) - v.begin());
    int sz = v.size();
    id[0] = 0;
    for (int i = 1; i < sz; i++)
      id[i] = i, ang[i] = atan2(v[i].second - v[0].second, v[i].first - v[0].first);
    sort(id + 1, id + sz, cmp);
    int k = 0;
    for (int i = 0; i < sz; i++) {
      while (k > 1 && ((con[k - 1] - con[k - 2]) ^ (v[id[i]] - con[k - 2])) >= 0) k--;
      con[k++] = v[id[i]];
    }
    printf("%d\n", k);
    for (int i = 0; i < k; i++) {
      printf("%I64d %I64d\n", con[i].first, con[i].second);
    }
  }
}

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<cmath>
#include<algorithm>

const double eps = 1e-9;
const int N = 500005;
const int dx[] = {+0,+1,+0,-1};
const int dy[] = {+1,+0,-1,+0};

using namespace std;

struct Point {
	int x,y;
	Point (int a=0,int b=0) {x=a,y=b;}
}p[N],q[N],stack[N];

inline Point operator + (const Point& a, const Point& b) {return Point(a.x+b.x,a.y+b.y);}
inline Point operator - (const Point& a, const Point& b) {return Point(a.x-b.x,a.y-b.y);}
inline int operator * (const Point& a, const Point& b) {return a.x*b.x+a.y*b.y;}
inline int operator / (const Point& a, const Point& b) {return a.x*b.y-a.y*b.x;}

bool cmp(const Point& a, const Point& b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}

int n,m,top,tot;
int mx[N],mn[N];

bool is_Zero(int x, int y) {if (y<0||y>=n||mn[y]>mx[y]) return true; return (x<mn[y]||x>mx[y]);}

void convex_hull() {
	sort(p+1,p+tot+1,cmp); //memset(stack,0,sizeof(stack));
	int bs=0;
	for (int i=1;i<=tot;i++) {while ((top>1)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	bs=top;
	for (int i=tot-1;i>=1;i--) {while ((top>bs)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	printf("%d\n",top-1);
	for (int i=top;i>1;i--) printf("%d %d\n",stack[i].x,stack[i].y)	;
}

int main() {

	while (true) {
		scanf("%d%d",&n,&m); if ((n==0)&&(m==0)) break; top=0; tot=0; //memset(q,0,sizeof(q)); memset(p,0,sizeof(p));
		for (int i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].x--,q[i].y--;
		for (int i=0;i<=n;i++) mx[i]=INT_MIN,mn[i]=INT_MAX;
		for (int i=1;i<=m;i++) {
			int tmp=q[i].y;	if (q[i].x<mn[tmp]) mn[tmp]=q[i].x; if (q[i].x>mx[tmp]) mx[tmp]=q[i].x;
		}
		for (int i=1;i<=m;i++) {
			for (int k=0;k<4;k++) {
				int kk=(k+1)%4;
				if ((is_Zero(q[i].x+dx[k],q[i].y+dy[k]))&&(is_Zero(q[i].x+dx[kk],q[i].y+dy[kk])))
				 {
				 	//cout<<"IN"<<tot<<endl;
				 	if (k==0) {p[++tot] = q[i];}
				 	if (k==1) {p[++tot] = Point(q[i].x,q[i].y+1);}
				 	if (k==2) {p[++tot] = Point(q[i].x+1,q[i].y+1);}
				 	if (k==3) {p[++tot] = Point(q[i].x+1,q[i].y);}
				 	//cout<<"OUT"<<tot<<endl;
				 	//cout<<p[i].x<<' '<<p[i].y<<endl;
				 	//cout<<p[tot].x<<' '<<p[tot].y<<endl;
				 }

			}
		}

		//for (int i=1;i<=tot;i++) cout<<p[i].x<<' '<<p[i].y<<endl;

		convex_hull();

	}
	return 0;
}

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<cmath>
#include<algorithm>

const double eps = 1e-9;
const int N = 500005;
const int dx[] = {+0,+1,+0,-1};
const int dy[] = {+1,+0,-1,+0};

using namespace std;

struct Point {
	int x,y;
	Point (int a=0,int b=0) {x=a,y=b;}
}p[N],q[N],stack[N];

inline Point operator + (const Point& a, const Point& b) {return Point(a.x+b.x,a.y+b.y);}
inline Point operator - (const Point& a, const Point& b) {return Point(a.x-b.x,a.y-b.y);}
inline int operator * (const Point& a, const Point& b) {return a.x*b.x+a.y*b.y;}
inline int operator / (const Point& a, const Point& b) {return a.x*b.y-a.y*b.x;}

bool cmp(const Point& a, const Point& b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}

int n,m,top,tot;
int mx[N],mn[N];

bool is_Zero(int x, int y) {if (y<0||y>=n||mn[y]>mx[y]) return true; return (x<mn[y]||x>mx[y]);}

void convex_hull() {
	sort(p+1,p+tot+1,cmp); memset(stack,0,sizeof(stack));
	int bs=0;
	for (int i=1;i<=tot;i++) {while ((top>1)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	bs=top;
	for (int i=tot-1;i>=1;i--) {while ((top>bs)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	printf("%d\n",top-1);
	for (int i=top;i>1;i--) printf("%d %d\n",stack[i].x,stack[i].y)	;
}

int main() {

	while (true) {
		scanf("%d%d",&n,&m); if ((n==0)&&(m==0)) break; top=0; tot=0; //memset(q,0,sizeof(q)); memset(p,0,sizeof(p));
		for (int i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].x--,q[i].y--;
		for (int i=0;i<=n;i++) mx[i]=INT_MIN,mn[i]=INT_MAX;
		for (int i=1;i<=m;i++) {
			int tmp=q[i].y;	if (q[i].x<mn[tmp]) mn[tmp]=q[i].x; if (q[i].x>mx[tmp]) mx[tmp]=q[i].x;
		}
		for (int i=1;i<=m;i++) {
			for (int k=0;k<4;k++) {
				int kk=(k+1)%4;
				if ((is_Zero(q[i].x+dx[k],q[i].y+dy[k]))&&(is_Zero(q[i].x+dx[kk],q[i].y+dy[kk])))
				 {
				 	//cout<<"IN"<<tot<<endl;
				 	if (k==0) {p[++tot] = q[i];}
				 	if (k==1) {p[++tot] = Point(q[i].x,q[i].y+1);}
				 	if (k==2) {p[++tot] = Point(q[i].x+1,q[i].y+1);}
				 	if (k==3) {p[++tot] = Point(q[i].x+1,q[i].y);}
				 	//cout<<"OUT"<<tot<<endl;
				 	//cout<<p[i].x<<' '<<p[i].y<<endl;
				 	//cout<<p[tot].x<<' '<<p[tot].y<<endl;
				 }

			}
		}

		//for (int i=1;i<=tot;i++) cout<<p[i].x<<' '<<p[i].y<<endl;

		convex_hull();

	}
	return 0;
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(A[1],a)<dis(A[1],b);
	return (ll) x1*y2<(ll) x2*y1;
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool cmp3(const cc &a,const cc &b) {
	return dis(A[1],a)<dis(A[1],b);
}
bool cmp4(const cc &a,const cc &b) {
	return dis(A[1],a)>dis(A[1],b);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool check3(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2==(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		i=2;
		while (i<nm && check3(A[1],A[2],A[i+1])) i++;
		sort(A+2,A+i+1,cmp3);
		i=nm;
		while (i>2 && check3(A[1],A[nm],A[i-1])) i--;
		sort(A+i+1,A+nm+1,cmp4);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
int a1[200000], a2[200000];
int s1[200000], s2[200000], d1[200000], d2[200000];

ll rot(ll q, ll w, ll e, ll r, ll t, ll y) {
  return (e - q) * (y - w) - (t - q) * (r - w);
}

int cmp(ll c1, ll c2, ll v1, ll v2) {
  ll S = rot(s1[0], s2[0], c1, c2, v1, v2);
  if (S < 0) {
    return -1;
  }
  if (S > 0) {
    return 1;
  }
  ll len1 = (c1 - s1[0]) * (c1 - s1[0]) + (c2 - s2[0]) * (c2 - s2[0]);
  ll len2 = (v1 - s1[0]) * (v1 - s1[0]) + (v2 - s2[0]) * (v2 - s2[0]);
  if (len1 < len2) {
    return -1;
  }
  if (len1 > len2) {
    return 1;
  }
  return 0;
}
void qs(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  int t1 = s1[y], t2 = s2[y];
  do {
    while (cmp(s1[e], s2[e], t1, t2) < 0) e++;
    while (cmp(s1[r], s2[r], t1, t2) > 0) r--;
    if (e <= r) {
      swap(s1[e], s1[r]);
      swap(s2[e], s2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs(q, r);
  if (e < w) qs(e, w);
}
int cmp2(int c1, int c2, int v1, int v2) {
  if (c1 < v1) {
    return -1;
  }
  if (c1 > v1) {
    return 1;
  }
  if (c2 < v2) {
    return -1;
  }
  if (c2 > v2) {
    return 1;
  }
  return 0;
}
void qs2(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  int t1 = a1[y], t2 = a2[y];
  do {
    while (cmp2(a1[e], a2[e], t1, t2) < 0) e++;
    while (cmp2(a1[r], a2[r], t1, t2) > 0) r--;
    if (e <= r) {
      swap(a1[e], a1[r]);
      swap(a2[e], a2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs2(q, r);
  if (e < w) qs2(e, w);
}

int q, lAns1, lAns2, numV;

int sch(int e, int r) {
  int c1 = 0, c, v;
  for (v = 1<<17; v; v >>= 1) {
    c = c1 + v;
    if ((c < numV) && (cmp2(a1[c], a2[c], e, r) <= 0)) {
      c1 = c;
    }
  }
  if ((a1[c1] != e) || (a2[c1] != r)) {
    return 0;
  }
  return 1;
}
void check(int e, int r, int de, int dr) {
  if (sch(e + de, r) + sch(e, r + dr) == 2) {
    lAns1 = (1 + de) / 2;
    lAns2 = (1 + dr) / 2;
  }
}
int main() {
  #ifdef Vlad_kv
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
  #endif // Vlad_kv
  int w, e, r, t;
  for (scanf("%d", &q); q; scanf("%d", &q)) {
    scanf("%d", &numV);
    for (w = 0; w < numV; w++) {
      scanf("%d%d", &s1[w], &s2[w]);
      s1[w]--;
      s2[w]--;
      a1[w] = s1[w];
      a2[w] = s2[w];
    }
    qs2(0, numV - 1);
    for (w = 1; w < numV; w++) {
      if ((s2[w] < s2[0]) || ((s2[w] == s2[0]) && (s1[w] < s1[0]))) {
        swap(s1[w], s1[0]);
        swap(s2[w], s2[0]);
      }
    }

    qs(1, numV - 1);

    t = 0;
    for (w = 1; w < numV; w++) {
      while (!((t == 0) || (rot(s1[t - 1], s2[t - 1], s1[t], s2[t], s1[w], s2[w]) < 0))) {
        t--;
      }
      t++;
      s1[t] = s1[w];
      s2[t] = s2[w];
    }
    t++;

    for (w = 0; w < t; w++) {
      check(s1[w], s2[w], 1, 1);
      check(s1[w], s2[w], 1, -1);
      check(s1[w], s2[w], -1, 1);
      check(s1[w], s2[w], -1, -1);

      d1[w] = s1[w] + lAns1;
      d2[w] = s2[w] + lAns2;
    }

    r = 0;

    for (w = 1; w < t; w++) {
      if ((d1[w] != d1[r]) || (d2[w] != d2[r])) {
        r++;
        d1[r] = d1[w];
        d2[r] = d2[w];
      }
    }
    while ((d1[r] == d1[0]) && (d2[r] == d2[0])) {
      r--;
    }

    t = r + 1;

    r = 0;
    for (e = 1; e < t; e++) {
      if ((d1[e] < d1[r]) || ((d1[e] == d1[r]) && (d2[e] < d2[r]))) {
        r = e;
      }
    }

    cout << t << "\n";
    e = r;
    do {
      printf("%d %d\n", d1[e], d2[e]);
      e++;
      if (e == t) {
        e = 0;
      }
    } while (e != r);

  }
  return 0;
}

#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;
#define int long long

struct vec {
	int x, y;
	vec(int a = 0, int b = 0) {
		x = a;
		y = b;
	}
	int operator * (vec A) {
		return x * A.x + y * A.y;
	}
	int operator % (vec A) {
		return x * A.y - y * A.x;
	}
	vec (vec A, vec B) {
		x = B.x - A.x;
		y = B.y - A.y;
	}
	int leng() {
		return x * x + y * y;
	}
};

// #define x first
// #define y second

vec cmp_vec;

bool cmp(vec A, vec B) {
	if ((vec(cmp_vec, A) % vec(cmp_vec, B)) == 0) {
		return vec(cmp_vec, A).leng() < vec(cmp_vec, B).leng();
	}
	return ((vec(cmp_vec, A) % vec(cmp_vec, B)) > 0);
}

bool cmp1(vec A, vec B) {
	return A.x < B.x || (A.x == B.x && A.y < B.y);
}

void hull(vector <vec> arr) {
	int n = arr.size();
	sort(arr.begin(), arr.end(), cmp1);
	cmp_vec = arr[0];
	sort(arr.begin() + 1, arr.end(), cmp);
	vector <vec> hul({cmp_vec});
	for (auto x : arr) {
		if (x.x == cmp_vec.x && x.y == cmp_vec.y) continue;
		while (hul.size() > 1 and vec(hul[hul.size() - 2], hul.back()) % vec(hul.back(), x) <= 0) {
			hul.pop_back();
		}
		hul.push_back(x);
	}
	reverse(hul.begin() + 1, hul.end());
	cout << hul.size() << endl;
	for (auto x : hul) {
		cout << x.x << " " << x.y << endl;
	}
}
vector <int> max_hor, min_hor;

bool inside(int x, int y) {
	return x <= max_hor[y] && x >= min_hor[y];
}

void sol (int n, int m) {
	set <pair <int, int> > arr;
	max_hor.clear();
	min_hor.clear();
	max_hor.resize(n, -1e9);
	min_hor.resize(n, 1e9);
	for (int i = 0; i < m; i++) {
		int x, y;
		cin >> x >> y;
		x--;
		y--;
		max_hor[y] = max(max_hor[y], x);
		min_hor[y] = min(min_hor[y], x);
		arr.insert(make_pair(x, y));
	}

	// int t[n][n];
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		t[i][j] = 0;
	// 	}
	// }
	// for (auto x : arr) {
	// 	t[x.first][x.second] = 1;
	// }
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		cout << t[i][j];
	// 	}
	// 	cout << endl;
	// }

	set <pair <int, int> > imp;

	for (auto A : arr) {
		int i = A.first;
		int j = A.second;
		// cout << i << " " << j << endl;
		// cout << inside(i + 1, j + 1) << endl;
		if (not inside(i + 1, j + 1) && not inside(i + 1, j) && not inside(i, j + 1) && arr.count({i + 1, j + 1}) + arr.count({i + 1, j}) + arr.count({i, j + 1}) == 0) {
			imp.insert({i, j});
			// cout << "A\n";
		}
		if (not inside(i - 1, j - 1) && not inside(i - 1, j) && not inside(i, j - 1) && arr.count({i - 1, j - 1}) + arr.count({i - 1, j}) + arr.count({i, j - 1}) == 0) {
			imp.insert({i + 1, j + 1});
			// cout << "B\n";
		}
		if (not inside(i, j - 1) && not inside(i + 1, j - 1) && not inside(i + 1, j) && arr.count({i, j - 1}) + arr.count({i + 1, j - 1}) + arr.count({i + 1, j}) == 0) {
			imp.insert({i, j + 1});
			// cout << "C\n";
		}
		if (not inside(i, j + 1) && not inside(i - 1, j) && not inside(i - 1, j + 1) && arr.count({i, j + 1}) + arr.count({i - 1, j}) + arr.count({i - 1, j + 1}) == 0) {
			imp.insert({i + 1, j});
			// cout << "\t" << i + 1 << " " << j << endl;
			// cout << "D\n";
		}
	}
	// cout << endl;
	vector <vec> tohull;
	for (auto x : imp) {
		// cout << x.first << " " << x.second << endl;
		tohull.push_back(vec(x.first, x.second));
	}
	hull(tohull);
}

signed main() {
	int n, m;
	while (cin >> n) {
		cin >> m;
		if (n == 0) break;
		sol(n, m);
	}
}

#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;
#define int long long

struct vec {
	int x, y;
	vec(int a = 0, int b = 0) {
		x = a;
		y = b;
	}
	int operator * (vec A) {
		return x * A.x + y * A.y;
	}
	int operator % (vec A) {
		return x * A.y - y * A.x;
	}
	vec (vec A, vec B) {
		x = B.x - A.x;
		y = B.y - A.y;
	}
	int leng() {
		return x * x + y * y;
	}
};

// #define x first
// #define y second

vec cmp_vec;

bool cmp(vec A, vec B) {
	if ((vec(cmp_vec, A) % vec(cmp_vec, B)) == 0) {
		return vec(cmp_vec, A).leng() < vec(cmp_vec, B).leng();
	}
	return ((vec(cmp_vec, A) % vec(cmp_vec, B)) < 0);
}

void hull(vector <vec> & arr) {
	int n = arr.size();
	cmp_vec = arr[0];
	sort(arr.begin(), arr.end(), cmp);
	vector <vec> hul({cmp_vec});
	for (auto x : arr) {
		if (x.x == cmp_vec.x && x.y == cmp_vec.y) continue;
		while (hul.size() > 1 and vec(hul[hul.size() - 2], hul.back()) % vec(hul.back(), x) >= 0) {
			hul.pop_back();
		}
		hul.push_back(x);
	}
	cout << hul.size() << endl;
	for (auto x : hul) {
		cout << x.x << " " << x.y << endl;
	}
}
vector <int> max_hor, min_hor;

bool inside(int x, int y) {
	return x <= max_hor[y] && x >= min_hor[y];
}

void sol (int n, int m) {
	set <pair <int, int> > arr;
	max_hor.clear();
	min_hor.clear();
	max_hor.resize(n, -1e9);
	min_hor.resize(n, 1e9);
	for (int i = 0; i < m; i++) {
		int x, y;
		cin >> x >> y;
		x--;
		y--;
		max_hor[y] = max(max_hor[y], x);
		min_hor[y] = min(min_hor[y], x);
		arr.insert(make_pair(x, y));
	}

	// int t[n][n];
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		t[i][j] = 0;
	// 	}
	// }
	// for (auto x : arr) {
	// 	t[x.first][x.second] = 1;
	// }
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		cout << t[i][j];
	// 	}
	// 	cout << endl;
	// }

	set <pair <int, int> > imp;

	for (auto A : arr) {
		int i = A.first;
		int j = A.second;
		// cout << i << " " << j << endl;
		// cout << inside(i + 1, j + 1) << endl;
		if (not inside(i + 1, j + 1) && not inside(i + 1, j) && not inside(i, j + 1) && arr.count({i + 1, j + 1}) + arr.count({i + 1, j}) + arr.count({i, j + 1}) == 0) {
			imp.insert({i, j});
			// cout << "A\n";
		}
		if (not inside(i - 1, j - 1) && not inside(i - 1, j) && not inside(i, j - 1) && arr.count({i - 1, j - 1}) + arr.count({i - 1, j}) + arr.count({i, j - 1}) == 0) {
			imp.insert({i + 1, j + 1});
			// cout << "B\n";
		}
		if (not inside(i, j - 1) && not inside(i + 1, j - 1) && not inside(i + 1, j) && arr.count({i, j - 1}) + arr.count({i + 1, j - 1}) + arr.count({i + 1, j}) == 0) {
			imp.insert({i, j + 1});
			// cout << "C\n";
		}
		if (not inside(i, j + 1) && not inside(i - 1, j) && not inside(i - 1, j + 1) && arr.count({i, j + 1}) + arr.count({i - 1, j}) + arr.count({i - 1, j + 1}) == 0) {
			imp.insert({i + 1, j});
			// cout << "\t" << i + 1 << " " << j << endl;
			// cout << "D\n";
		}
	}
	// cout << endl;
	vector <vec> tohull;
	for (auto x : imp) {
		// cout << x.first << " " << x.second << endl;
		tohull.push_back(vec(x.first, x.second));
	}
	hull(tohull);
}

signed main() {
	int n, m;
	while (cin >> n) {
		cin >> m;
		if (n == 0) break;
		sol(n, m);
	}
}

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define ii pair<int,int>
#define INF 1000000000
int g[510][510];
int n,m;
vector<ii> p,u,d;
int ccw(ii a,ii b,ii c) {
	int dx1=b.first-a.first,dy1=b.second-a.second;
	int dx2=c.first-b.first,dy2=c.second-b.second;
	return (dx1*dy2-dx2*dy1>=0);
}
bool cmp(ii a,ii b) {
	if (a.first==b.first) return a.second>b.second;
	return a.first<b.first;
}
set<ii> s;
int l[100010],r[100010],x,y;
vector<ii> pt;
bool in(int a,int b) {
	if (s.find(mp(a,b))!=s.end()) return 1;
	if (a>=l[b] && a<=r[b]) return 1;
	return 0;
}
int dirx[]={-1,0,1,1,1,0,-1,-1};
int diry[]={1,1,1,0,-1,-1,-1,0};
bool can[8];
int main() {
	while(scanf("%d%d",&n,&m),n!=0) {
		p.clear();
		u.clear();
		d.clear();
		s.clear();
		pt.clear();
		for (int i=0;i<=n;i++) {
			l[i]=INF,r[i]=-2;
		}
		for (int i=0;i<m;i++) {
			scanf("%d%d",&x,&y);
			l[y]=min(l[y],x);
			r[y]=max(r[y],x);
			s.insert(mp(x,y));
			pt.pb(mp(x,y));
		}
		for (int i=0;i<sz(pt);i++) {
			x=pt[i].first,y=pt[i].second;
			for (int j=0;j<8;j++) {
				can[j]=in(x+dirx[j],y+diry[j]);
			}
			if (can[0]&&can[1]&&can[7]) {
				p.pb(mp(x,y+1));
			}
			if (can[1]&&can[2]&&can[3]) {
				p.pb(mp(x+1,y+1));
			}
			if (can[3]&&can[4]&&can[5]) {
				p.pb(mp(x+1,y));
			}
			if (can[5]&&can[6]&&can[7]) {
				p.pb(mp(x,y));
			}
		}
		sort(all(p),cmp);
		p.resize(distance(p.begin(),unique(all(p))));
		u.pb(p[0]);
		for (int i=0;i<sz(p);i++) {
			while(sz(u)>1 && ccw(u[sz(u)-2],u[sz(u)-1],p[i])) {
				u.pop_back();
			}
			u.pb(p[i]);
		}
		d.pb(p[sz(p)-1]);
		for (int i=sz(p)-2;i>=0;i--) {
			while(sz(d)>1 && ccw(d[sz(d)-2],d[sz(d)-1],p[i])) {
				d.pop_back();
			}
			d.pb(p[i]);
		}
		for (int i=1;i<sz(d)-1;i++) {
			u.pb(d[i]);
		}
		int s=sz(u);
		printf("%d\n", s);
		int rr=(min_element(all(u)))-u.begin();
		for (int i=0;i<s;i++) {
			printf("%d %d\n", u[(rr+i)%s].first-1,u[(rr+i)%s].second-1);
		}
	}
}

#include <bits/stdc++.h>
using namespace std;
#define repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,n) repl(i,0,n)
#define mp(a,b) make_pair((a),(b))
#define pb(a) push_back((a))
#define all(x) (x).begin(),(x).end()
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
void _dbg(string){cout<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cout<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

#define INF 1120000000
#define EPS 1e-8
#define long long long // for codeforces

using Point = complex<double>;
#define X real()
#define Y imag()
namespace std {
  bool operator<(const Point &a, const Point &b){
    return a.X != b.X ? a.X < b.X : a.Y < b.Y;
  }
}

double cross(Point a, Point b){ return a.X*b.Y - a.Y*b.X; }

vector<Point> GrahamScan(vector<Point> points){
  uniq(points);
  int n = points.size();
  int k=0;
  vector<Point> qs(2*n);
  for(int i=0; i<n; qs[k++] = points[i++]){
    while(k>1 && cross(qs[k-1] - qs[k-2], points[i] - qs[k-1]) <= 0) k--;
  }
  for(int i=n-2,t=k; i>=0; qs[k++] = points[i--]){
    while(k>t && cross(qs[k-1] -qs[k-2], points[i] - qs[k-1]) <= 0) k--;
  }
  qs.resize(k-1);
  return qs;
}

// 凸多角形の内部判定 O(logn)
// 領域内部なら1、境界上なら2、外部なら0
int inConvex(Point p, const vector<Point>& conv){
  int n = conv.size();
  Point g = (conv[0] + conv[n/3] + conv[n*2/3])/3.0;
  if (g == p) return 1;
  Point gp = p - g;

  int l = 0, r = n;
  while(r-l>1){
    int mid = (l+r)/2;
    Point gl = conv[l] - g;
    Point gm = conv[mid] - g;
    if(cross(gl, gm) > 0){
      if(cross(gl, gp) >= 0 && cross(gm, gp) <= 0) r = mid;
      else l = mid;
    }
    else {
      if(cross(gl, gp) <= 0 && cross(gm, gp) >= 0) l = mid;
      else r = mid;
    }
  }
  r %= n;
  double cr = cross(conv[l] - p, conv[r] - p);
  return abs(cr)<EPS ? 2 : cr < 0 ? 0 : 1;
}

void solve(int n, int m){
  vector<Point> p(m);
  rep(i,m){
    int x,y;
    scanf("%d %d", &x, &y);
    x--;y--;
    p[i] = {x,y};
  }

  auto hull = GrahamScan(p);

  auto iszero = [&](int i, int j){
    if(i<0 || i>=n || j<0 || j>=n) return false;
    if(inConvex(Point{i,j}, hull)>0) return false;
    return true;
  };

  vector<Point> cand;

  for(auto po : p) rep(i,2) rep(j,2){
    int x = po.X+i, y = po.Y+j;
    if(x<=0 || x>=n || y<=0 || y>=n) continue;
    if([&](){
      rep(dx,2)rep(dy,2)if(iszero(x-dx,y-dy)) return false;
      return true;
    }()){
      cand.pb(Point(x,y));
    }
  }

  vector<Point> res = GrahamScan(cand);

  int sz =  res.size();
  printf("%d\n", sz);
  rep(i,sz) printf("%.0f %.0f\n", res[(sz-i)%sz].X, res[(sz-i)%sz].Y);
}

int main(){
  int n,m;
  while(cin>>n>>m, n|m){
    solve(n,m);
  }

  return 0;
}

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
#include <queue>
#include <map>

using namespace std;

#define mp make_pair
#define pb push_back
#define ll long long

#define maxN 200011

struct Point {
    ll x, y;

    bool operator<(const Point& who) const {
        return mp(x, y) < mp(who.x, who.y);
    }

    bool operator==(const Point& who) const {
        return mp(x, y) == mp(who.x, who.y);
    }
};

int dim, n, i, cnt;
Point C[maxN];
map<Point, bool> M;
bool up, down, le, ri;
vector<Point> data, Hull;

ll cross(Point A, Point B, Point C) {
    B.x -= A.x;
    B.y -= A.y;

    C.x -= A.x;
    C.y -= A.y;

    return B.x * C.y - B.y * C.x;
}

void build_hull() {
    Hull.clear();
    sort(data.begin(), data.end());
    data.resize(unique(data.begin(), data.end()) - data.begin());
    dim = 2;
    for (auto p : data) {
        while (Hull.size() >= dim) {
            if (cross(Hull[Hull.size() - 2], Hull.back(), p) < 0) break;
            Hull.pop_back();
        }
        Hull.pb(p);
    }

    data.pop_back();
    reverse(data.begin(), data.end());
    dim = Hull.size() + 1;
    for (auto p : data) {
        while (Hull.size() >= dim) {
            if (cross(Hull[Hull.size() - 2], Hull.back(), p) < 0) break;
            Hull.pop_back();
        }
        Hull.pb(p);
    }

    Hull.pop_back();
}

void build_hull_of_cells() {
    int i;

    data.clear();
    for (i = 1; i <= n; i++) data.pb(C[i]);
    build_hull();

    n = 0;
    for (auto e : Hull) C[++n] = e;
    data.clear();
}

int main()
{
    //freopen("test.in","r",stdin);

    while (scanf("%d%d", &dim, &n)) {
        if (dim == 0 && n == 0) return 0;
        M.clear();
        data.clear();

        for (i = 1; i <= n; i++) scanf("%lld%lld", &C[i].x, &C[i].y), M[C[i]] = true;
        build_hull_of_cells();
        for (i = 1; i <= n; i++) {
            auto act = C[i];
            cnt = 0;

            up = M[{act.x, act.y + 1}]; cnt += up;
            down = M[{act.x, act.y - 1}]; cnt += down;
            le = M[{act.x - 1, act.y}]; cnt += le;
            ri = M[{act.x + 1, act.y}]; cnt += ri;

            if (cnt != 2) continue;
            if (up && le) data.pb({act.x - 1, act.y});
            if (up && ri) data.pb({act.x, act.y});
            if (down && le) data.pb({act.x - 1, act.y - 1});
            if (down && ri) data.pb({act.x, act.y - 1});
        }

        build_hull();
        printf("%d\n", Hull.size());
        for (auto e : Hull)
            printf("%lld %lld\n", e.x, e.y);
    }

    return 0;
}

/* -*- coding: utf-8 -*-
 *
 * 0690B3.cc: B3. Recover Polygon (hard)
 */

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<deque>
#include<algorithm>
#include<numeric>
#include<utility>
#include<complex>
#include<functional>

using namespace std;

/* constant */

const int MAX_N = 100000;
const int MAX_M = 200000;
const int INF = 1 << 30;
const int dxs[] = { 1, 0, -1, 0 }, dys[] = { 0, 1, 0, -1 };

/* typedef */

template <typename T>
struct Pt {
  T x, y;
  Pt() {}
  Pt(T _x, T _y) : x(_x), y(_y) {}
  Pt(const Pt<T> &p) : x(p.x), y(p.y) {}

  Pt<T> operator+(const Pt<T> p) const { return Pt<T>(x + p.x, y + p.y); }
  Pt<T> operator-() const { return Pt<T>(-x, -y); }
  Pt<T> operator-(const Pt<T> p) const { return Pt<T>(x - p.x, y - p.y); }
  Pt<T> operator*(T t) const { return Pt<T>(x * t, y * t); }
  Pt<T> operator/(T t) const { return Pt<T>(x / t, y / t); }
  T dot(Pt<T> v) const { return x * v.x + y * v.y; }
  T cross(Pt<T> v) const { return x * v.y - y * v.x; }
  Pt<T> mid(const Pt<T> p) { return Pt<T>((x + p.x) / 2, (y + p.y) / 2); }
  T d2() { return x * x + y * y; }
  double d() { return sqrt(d2()); }

  Pt<T> rot(double th) {
    double c = cos(th), s = sin(th);
    return Pt<T>(c * x - s * y, s * x + c * y);
  }

  bool operator==(const Pt<T> pt) const { return x == pt.x && y == pt.y; }
  bool operator<(const Pt<T> &pt) const {
    return x < pt.x || (x == pt.x && y < pt.y);
  }

  void print() { printf("(%d,%d)", x, y); }
};

typedef Pt<int> pt;
typedef vector<pt> vpt;

/* global variables */

int lxs[MAX_N], rxs[MAX_N];
pt sps[MAX_M], ps[MAX_M];

/* subroutines */

void convex_hull(int n, pt ps[], vpt& chs) {
  vpt lhs, uhs;

  lhs.push_back(ps[0]);
  lhs.push_back(ps[1]);
  for (int i = 2; i < n; i++) {
    while (lhs.size() >= 2) {
      int ln = lhs.size();
      pt &lh0 = lhs[ln - 2], &lh1 = lhs[ln - 1];
      if ((lh1 - lh0).cross(ps[i] - lh1) > 0) break;
      lhs.pop_back();
    }
    lhs.push_back(ps[i]);
  }

  uhs.push_back(ps[n - 1]);
  uhs.push_back(ps[n - 2]);
  for (int i = n - 3; i >= 0; i--) {
    while (uhs.size() >= 2) {
      int un = uhs.size();
      pt &uh0 = uhs[un - 2], &uh1 = uhs[un - 1];
      if ((uh1 - uh0).cross(ps[i] - uh1) > 0) break;
      uhs.pop_back();
    }
    uhs.push_back(ps[i]);
  }

  lhs.pop_back();
  uhs.pop_back();

  chs.clear();
  chs.reserve(lhs.size() + uhs.size());
  chs.assign(lhs.begin(), lhs.end());
  chs.insert(chs.end(), uhs.begin(), uhs.end());
}

inline void setmin(int &a, int b) { if (a > b) a = b; }
inline void setmax(int &a, int b) { if (a < b) a = b; }

inline bool iszero(int n, int x, int y) {
  return (x < 0 || x >= n || y < 0 || y >= n || x < lxs[y] || x > rxs[y]);
}

/* main */

int main() {
  //freopen("input.txt", "r", stdin);
  //freopen("output.txt", "w", stdout);

  for (int n, m; scanf("%d%d", &n, &m) == 2 && n > 0;) {
    fill(lxs, lxs + n, INF);
    fill(rxs, rxs + n, -1);

    for (int i = 0; i < m; i++) {
      scanf("%d%d", &sps[i].x, &sps[i].y);
      sps[i].x--, sps[i].y--;
      setmin(lxs[sps[i].y], sps[i].x);
      setmax(rxs[sps[i].y], sps[i].x);
    }
    sort(sps, sps + m);

    int l = 0;
    for (int i = 0; i < m; i++) {
      int x = sps[i].x, y = sps[i].y;
      int c = 0, b = 0;
      for (int di = 0; di < 4; di++) {
	int vx = x + dxs[di], vy = y + dys[di];
	if (! iszero(n, vx, vy)) c++, b |= (1 << di);
      }

      if (c == 2) {
	//printf("(%d,%d)=%d\n", x, y, b);
	switch (b) {
	case  3: ps[l] = pt(x + 1, y + 1); break;
	case  6: ps[l] = pt(x, y + 1); break;
	case 12: ps[l] = pt(x, y); break;
	case  9: ps[l] = pt(x + 1, y); break;
	}
	l++;
      }
    }

    sort(ps, ps + l);
    l = unique(ps, ps + l) - ps;
    //printf("l=%d\n", l);
    //for (int i = 0; i < l; i++) printf("(%d,%d)\n", ps[i].x, ps[i].y);

    vpt cps;
    convex_hull(l, ps, cps);

    int k = cps.size();
    printf("%d\n", k);
    for (int i = 0, j = 0; i < k; i++, j = (j + k - 1) % k)
      printf("%d %d\n", cps[j].x, cps[j].y);
  }
  return 0;
}

//#pragma comment(linker, "/STACK:134217728")

#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <memory>
#include <cctype>
#include <cstring>
#include <vector>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <numeric>
using namespace std;

typedef long long Int;
typedef pair<int,int> PII;
typedef vector<int> VInt;

#define FOR(i, a, b) for(i = (a); i < (b); ++i)
#define RFOR(i, a, b) for(i = (a) - 1; i >= (b); --i)
#define CLEAR(a, b) memset(a, b, sizeof(a))
#define SIZE(a) int((a).size())
#define ALL(a) (a).begin(),(a).end()
#define PB push_back
#define MP make_pair

#define MAX (1 << 21)

const int DX[] = { -1, 1, 0, 0, -1, -1,  1, 1 };
const int DY[] = { 0, 0, -1, 1, -1,  1, -1, 1 };

map<Int, int> Map;
int X[MAX];
int Y[MAX];
int Z[MAX];
PII V[MAX];
int gCnt;

Int getKey(int x, int y)
{
	return (Int(x) << 20) | y;
}

int check(int x, int y)
{
	Int key = getKey(x, y);
	return Map.count(key) == 0 ? -1 : Map[key];
}

int getPos(int x, int y)
{
	Int key = getKey(x, y);
	if(Map.count(key) == 0)
	{
		Map[key] = gCnt;
		X[gCnt] = x;
		Y[gCnt] = y;
		++gCnt;
	}

	return Map[key];
}

PII sub(const PII& a, const PII& b)
{
	return PII(a.first - b.first, a.second - b.second);
}

Int cross(const PII& a, const PII& b)
{
	return Int(a.first)*b.second - Int(a.second)*b.first;
}

int main()
{
	int n, m;
	while(true)
	{
		scanf("%d%d", &n, &m);
		if (n == 0 && m == 0) break;

		Map.clear();
		gCnt = 0;

		int i, j, k;
		FOR(i, 0, m)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			Z[getPos(x, y)] = 0;
		}

		FOR(i, 0, m)
			FOR(j, 0, 8)
			{
				int x = X[i] + DX[j];
				int y = Y[i] + DY[j];
				if(check(x, y) == -1)
					Z[getPos(x, y)] = 1;
			}

		int pos = 0;
		FOR(i, 0, gCnt)
			if (PII(X[i], Y[i]) < PII(X[pos], Y[pos]))
				pos = i;

		queue<int> q;
		q.push(pos);
		Z[pos] = -1;
		while (!q.empty())
		{
			pos = q.front();
			q.pop();
			FOR(i, 0, 4)
			{
				int x = X[pos] + DX[i];
				int y = Y[pos] + DY[i];
				int z = check(x, y);
				if(z != -1 && Z[z] == 1)
				{
					Z[z] = -1;
					q.push(z);
				}
			}
		}

		set<Int> candidates;
		FOR(i, 0, m)
			FOR(j, 0, 2)
			FOR(k, 0, 2)
			candidates.insert(getKey(X[i] - j, Y[i] - k));

		int cnt = 0;
		for (auto it = candidates.begin(); it != candidates.end(); ++it)
		{
			Int key = *it;
			int x = key >> 20;
			int y = key & ((1 << 20) - 1);

			FOR(j, 0, 4)
			{
				int z = check(x + (j >> 1), y + (j & 1));
				if (z == -1) throw 0;
				if (Z[z] == -1) break;
			}

			if (j == 4)
			{
				V[cnt] = PII(x, y);
				++cnt;
			}
		}

		sort(V, V + cnt);
		VInt s1, s2;
		s1.push_back(0);
		FOR(i, 1, cnt)
		{
			while (SIZE(s1) > 1 && cross(sub(V[s1.back()], V[s1[SIZE(s1) - 2]]), sub(V[i], V[s1.back()])) >= 0)
				s1.pop_back();

			s1.push_back(i);
		}
		s2.push_back(0);
		FOR(i, 1, cnt)
		{
			while (SIZE(s2) > 1 && cross(sub(V[s2.back()], V[s2[SIZE(s2) - 2]]), sub(V[i], V[s2.back()])) <= 0)
				s2.pop_back();

			s2.push_back(i);
		}

		vector<PII> res;
		FOR(i, 0, SIZE(s1))
			res.push_back(V[s1[i]]);
		RFOR(i, SIZE(s2) - 1, 1)
			res.push_back(V[s2[i]]);

		printf("%d\n", SIZE(res));
		FOR(i, 0, SIZE(res))
			printf("%d %d\n", res[i].first, res[i].second);
	}

	return 0;
};

//#pragma comment(linker, "/STACK:134217728")

#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <memory>
#include <cctype>
#include <cstring>
#include <vector>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <numeric>
using namespace std;

typedef long long Int;
typedef pair<int,int> PII;
typedef vector<int> VInt;

#define FOR(i, a, b) for(i = (a); i < (b); ++i)
#define RFOR(i, a, b) for(i = (a) - 1; i >= (b); --i)
#define CLEAR(a, b) memset(a, b, sizeof(a))
#define SIZE(a) int((a).size())
#define ALL(a) (a).begin(),(a).end()
#define PB push_back
#define MP make_pair

#define MAX (1 << 21)

const int DX[] = { -1, 1, 0, 0, -1, -1,  1, 1 };
const int DY[] = { 0, 0, -1, 1, -1,  1, -1, 1 };

map<Int, int> Map;
int X[MAX];
int Y[MAX];
int Z[MAX];
PII V[MAX];
int gCnt;

Int getKey(int x, int y)
{
	return (Int(x) << 20) | y;
}

int check(int x, int y)
{
	Int key = getKey(x, y);
	return Map.count(key) == 0 ? -1 : Map[key];
}

int getPos(int x, int y)
{
	Int key = getKey(x, y);
	if(Map.count(key) == 0)
	{
		Map[key] = gCnt;
		X[gCnt] = x;
		Y[gCnt] = y;
		++gCnt;
	}

	return Map[key];
}

PII sub(const PII& a, const PII& b)
{
	return PII(a.first - b.first, a.second - b.second);
}

Int cross(const PII& a, const PII& b)
{
	return Int(a.first)*b.second - Int(a.second)*b.first;
}

int main()
{
	int n, m;
	while(true)
	{
		scanf("%d%d", &n, &m);
		if (n == 0 && m == 0) break;

		Map.clear();
		gCnt = 0;

		int i, j, k;
		FOR(i, 0, m)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			Z[getPos(x, y)] = 0;
		}

		FOR(i, 0, m)
			FOR(j, 0, 8)
			{
				int x = X[i] + DX[j];
				int y = Y[i] + DY[j];
				if(check(x, y) == -1)
					Z[getPos(x, y)] = 1;
			}

		vector<Int> v;
		FOR(i, 0, gCnt)
			if (Z[i] == 1)
				v.push_back(getKey(X[i], Y[i]));

		sort(ALL(v));
		FOR(j, 0, SIZE(v))
		{
			Int key = v[j];
			int x = key >> 20;
			int y = key & ((1 << 20) - 1);
			int pos = check(x, y);
			if (Z[pos] != 1) continue;

			deque<int> q;
			q.push_front(pos);
			Z[pos] = -1;
			while (!q.empty())
			{
				pos = q.front();
				q.pop_front();
				FOR(i, 0, 4)
				{
					int x = X[pos] + DX[i];
					int y = Y[pos] + DY[i];
					int z = check(x, y);
					if (z != -1 && 0 <= Z[z] && Z[z] <= 1)
					{
						if(Z[z] == 1 && Z[pos] == -1)
						{
							Z[z] = -1;
							q.push_front(z);
						}
						else
						{
							Z[z] = 2;
							q.push_back(z);
						}
					}
				}
			}
		}

		set<Int> candidates;
		FOR(i, 0, m)
			FOR(j, 0, 2)
			FOR(k, 0, 2)
			candidates.insert(getKey(X[i] - j, Y[i] - k));

		int cnt = 0;
		for (auto it = candidates.begin(); it != candidates.end(); ++it)
		{
			Int key = *it;
			int x = key >> 20;
			int y = key & ((1 << 20) - 1);

			FOR(j, 0, 4)
			{
				int z = check(x + (j >> 1), y + (j & 1));
				if (z == -1) throw 0;
				if (Z[z] == -1) break;
			}

			if (j == 4)
			{
				V[cnt] = PII(x, y);
				++cnt;
			}
		}

		sort(V, V + cnt);
		VInt s1, s2;
		s1.push_back(0);
		FOR(i, 1, cnt)
		{
			while (SIZE(s1) > 1 && cross(sub(V[s1.back()], V[s1[SIZE(s1) - 2]]), sub(V[i], V[s1.back()])) >= 0)
				s1.pop_back();

			s1.push_back(i);
		}
		s2.push_back(0);
		FOR(i, 1, cnt)
		{
			while (SIZE(s2) > 1 && cross(sub(V[s2.back()], V[s2[SIZE(s2) - 2]]), sub(V[i], V[s2.back()])) <= 0)
				s2.pop_back();

			s2.push_back(i);
		}

		vector<PII> res;
		FOR(i, 0, SIZE(s1))
			res.push_back(V[s1[i]]);
		RFOR(i, SIZE(s2) - 1, 1)
			res.push_back(V[s2[i]]);

		printf("%d\n", SIZE(res));
		FOR(i, 0, SIZE(res))
			printf("%d %d\n", res[i].first, res[i].second);
	}

	return 0;
};

#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>
#include <cstdio>
#include <set>

const int dx[] = {1, 0, -1, 0};
const int dy[] = {0, 1, 0, -1};

using namespace std;

#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)
#define TRACE(x) cout << #x << " = " << x << endl
#define _ << " _ " <<

typedef long long llint;

const int MAX = 100005;

typedef long long llint;
typedef pair<int, int> Pt;
#define x first
#define y second

int convexHull(Pt *a, int n) {
  rotate(a, min_element(a, a + n), a + n);

  auto ccw = [](const Pt &a, const Pt &b, const Pt &c) {
    llint ccw = a.x*llint(b.y-c.y) + b.x*llint(c.y-a.y) + c.x*llint(a.y-b.y);
    return ccw < 0 ? -1 : ccw > 0;
  };

  auto dist = [](const Pt &a, const Pt &b) {
    return llint(a.x-b.x)*(a.x-b.x) + llint(a.y-b.y)*(a.y-b.y);
  };

  sort(a + 1, a + n, [&a, &ccw, &dist](const Pt &x, const Pt &y) {
      int c = ccw(a[0], x, y);
      if (c) return c > 0;
      return dist(a[0], x) < dist(a[0], y);
    }
  );

  int m = 0;
  REP(i, n) {
    while (m >= 2 && ccw(a[m-2], a[m-1], a[i]) <= 0) m--;
    a[m++] = a[i];
  }

  return m;
}

int touch[MAX], cookie;
int row_lo[MAX];
int row_hi[MAX];
set< pair< int, int > > M, F;

bool is_four(int x, int y) {
  if (x < 0 || x > MAX) return false;
  if (touch[x] != cookie) return false;
  if (M.find({x, y}) != M.end()) return false;
  return y >= row_lo[x] && y <= row_hi[x];
}

int main(void) {
  int n, m;
  while (scanf("%d%d", &n, &m) == 2) {
    if (n == 0) break;
    ++cookie;

    M.clear();
    F.clear();

    REP(i, m) {
      int x, y;
      scanf("%d%d", &x, &y);
      M.insert({x, y});

      if (touch[x] != cookie) {
	touch[x] = cookie;
	row_lo[x] = y;
	row_hi[x] = y;
      }

      row_lo[x] = min(row_lo[x], y);
      row_hi[x] = max(row_hi[x], y);
    }

    for (auto c : M) {
      REP(d, 4) {
	int x = c.first + dx[d];
	int y = c.second + dy[d];

	if (is_four(x, y))
	  F.insert({x, y});
      }
    }

    for (auto f : F) M.insert(f);

    vector<Pt> v;
    for (auto c : M)
      if (M.find({c.first + 1, c.second}) != M.end() &&
	  M.find({c.first, c.second + 1}) != M.end() &&
	  M.find({c.first + 1, c.second + 1}) != M.end())
	v.push_back({c.first, c.second});

    int m = convexHull(&v[0], v.size());
    printf("%d\n", m);
    reverse(v.begin() + 1, v.begin() + m);
    REP(i, m) {
      printf("%d %d\n", v[i].x, v[i].y);
    }
  }

  return 0;
}

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const ll d[8][2]={{0,1},{-1,0},{0,-1},{1,0},{1,1},{-1,1},{-1,-1},{1,-1}};
const ll t[4][2]={{0,0},{-1,0},{-1,-1},{0,-1}};
struct Point
{
    ll x,y;
    Point(){}
    Point(ll _x,ll _y):x(_x),y(_y){}
    Point operator - (const Point &t)const
    {
        return Point(x-t.x,y-t.y);
    }
    ll operator * (const Point &t)const
    {
        return x*t.y-y*t.x;
    }
    ll dis2()
    {
        return x*x+y*y;
    }
    bool operator < (const Point &t)const
    {
        return x==t.x ? y<t.y : x<t.x;
    }
}in[200005],p[800005],stk[800005];
bool cmp(const Point &a,const Point &b)
{
    return (a-p[0])*(b-p[0]) ? (a-p[0])*(b-p[0])<0 : (a-p[0]).dis2()<(b-p[0]).dis2();
}
int Graham(int n)
{
    sort(p,p+n);
    sort(p+1,p+n,cmp);
    int top=0;
    for(int i=0;i<n;i++)
    {
        while(top>1 && (p[i]-stk[top-1])*(stk[top-1]-stk[top-2])<=0)top--;
        stk[top++]=p[i];
    }
    if(top>2)while(top>1 && (p[0]-stk[top-1])*(stk[top-1]-stk[top-2])<=0)top--;
    return top;
}
map<ll,ll>mx,mi;
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m),n+m)
    {
        for(int i=0;i<m;i++)
            scanf("%I64d%I64d",&in[i].x,&in[i].y);
        mx.clear(),mi.clear();
        for(int i=0;i<m;i++)
        {
            mx[in[i].x]=0;
            mi[in[i].x]=n+1;
        }
        for(int i=0;i<m;i++)
        {
            mx[in[i].x]=max(mx[in[i].x],in[i].y);
            mi[in[i].x]=min(mi[in[i].x],in[i].y);
        }
        int tot=0;
        for(int i=0;i<m;i++)
        {
            bool isok[4]={1,1,1,1};
            for(int j=0;j<4;j++)
            {
                int tx=in[i].x+d[j][0];
                int ty=in[i].y+d[j][1];
                if(mx.lower_bound(tx)==mx.end()
                || mx[tx]<ty || mi[tx]>ty)
                    isok[j]=isok[(j+1)%4]=0;
            }
            for(int j=4;j<8;j++)
            {
                int tx=in[i].x+d[j][0];
                int ty=in[i].y+d[j][1];
                if(mx.lower_bound(tx)==mx.end()
                || mx[tx]<ty || mi[tx]>ty)
                    isok[j-4]=0;
            }
            for(int j=0;j<4;j++)if(isok[j])
                p[tot++]=Point(in[i].x+t[j][0],in[i].y+t[j][1]);
        }
        int res=Graham(tot);
        printf("%d\n",res);
        for(int i=0;i<res;i++)
            printf("%I64d %I64d\n",stk[i].x,stk[i].y);
    }
    return 0;
}

#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cctype>
#include <vector>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 100050;

struct Point{
	int x, y;
	Point(int x = 0,int y = 0) : x(x), y(y) { }
};
typedef Point Vec;
//向量+向量 = 向量，点+向量 = 点
Vec operator +(Vec A,Vec B){return Vec(A.x+B.x,A.y+B.y);}
//点-点 = 向量
Vec operator -(Point A,Point B){return Vec(A.x-B.x,A.y-B.y);}
//向量*数 = 向量
Vec operator *(Vec A,int p){return Vec(A.x*p,A.y*p);}
//向量/数 = 向量
Vec operator /(Vec A,int p){return Vec(A.x/p,A.y/p);}

int dcmp(int x){
	if(x == 0) return 0;else return x<0? -1: 1;
}

bool operator <(const Point& a,const Point& b){
	return a.x<b.x || (a.x == b.x && a.y<b.y);
}

bool operator == (const Point& a,const Point &b){
	return dcmp(a.x-b.x)==0 &&dcmp(a.y-b.y) == 0;
}

int Cross(Vec A,Vec B){return A.x*B.y - A.y*B.x;}

vector<Point> ConvexHull(vector<Point> p){
	sort(p.begin(),p.end());
	//删除重复点
	p.erase(unique(p.begin(),p.end()),p.end());
	int n = p.size();
	vector<Point> ch(n+1);
	int m = 0;
	for(int i=0;i<n;i++){
		while(m>1 && dcmp(Cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])) <= 0) m--;         //若需要把边线上的点也算上，把等号去掉
		ch[m++] = p[i];
	}
	int k = m;
	for(int i = n-2;i>=0;i--){
		while(m > k && dcmp(Cross(ch[m-1] - ch[m-2] , p[i]-ch[m-2] )) <= 0)m--;
		ch[m++] = p[i];
	}
	if(n > 1)m--;
	ch.resize(m);
	return ch;
}

int rows[maxn], rowb[maxn], cols[maxn], colb[maxn];
int N, M;
int t1, t2, t3, t4;
vector < Point > p;
vector < Point > v;
Point now[15];
int gox[] = { 0, -1, 0, 1, -1, 1, -1, 0, 1 };
int goy[] = { 0, 1, 1, 1, 0, 0, -1, -1, -1 };

void init() {
    memset(rowb, 0, sizeof(rowb));
    memset(colb, 0, sizeof(colb));
    memset(rows, 0x3f, sizeof(rows));
    memset(cols, 0x3f, sizeof(cols));
    p.clear();
    v.clear();
}

int jud(Point n1, Point n2, Point n3, Point n4) {
    Point a[6];
    //cout << " VVV " << endl;
    a[1] = n1; a[2] = n2; a[3] = n3; a[4] = n4;
    for (int i = 1; i <= 4; i++) {
        if (a[i].y < rows[a[i].x] || a[i].y > rowb[a[i].x]) return 0;
        if (a[i].x < cols[a[i].y] || a[i].x > colb[a[i].y]) return 0;
    }
   // cout << " KKK " << endl;
    return 1;
}

int main() {
    while (~scanf("%d %d", &N, &M) && N) {
        init();
        for (int i = 1; i <= M; i++) {
            scanf("%d %d", &t1, &t2);
            t3 = t1;
            t4 = t2;
            v.push_back(Point(t3, t4));
            rows[t3] = min(t4, rows[t3]);
            rowb[t3] = max(t4, rowb[t3]);
            cols[t4] = min(t3, cols[t4]);
            colb[t4] = max(t3, colb[t4]);
            //cout << t3 << " TTT " << t4 << " " << rows[t3] << " " << rowb[t3] << " RRR " << cols[t4] << " " << colb[t4] << endl;
        }
        for (int i = 0; i < v.size(); i++) {
            now[0] = v[i];
            for (int j = 1; j <= 8; j++) {
                now[j].x = v[i].x + gox[j];
                now[j].y = v[i].y + goy[j];
            }
            if (jud(now[1], now[2], now[4], now[0])) { p.push_back(now[2]); }
            if (jud(now[2], now[3], now[0], now[5])) { p.push_back(now[3]); }
            if (jud(now[4], now[0], now[6], now[7])) { p.push_back(now[0]); }
            if (jud(now[0], now[5], now[7], now[8])) { p.push_back(now[5]); }
            //cout << p.size() << p
        }
        p = ConvexHull(p);
        printf("%d\n", p.size());
        if (p.size()) {
            printf("%d %d\n", p[0].x - 1, p[0].y - 1);
        }
        for (int i = p.size() - 1; i >= 1; i--) {
            printf("%d %d\n", p[i].x - 1, p[i].y - 1);
        }
    }
    return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define N 810000
int n,T,cnt,top,m;
struct poi
{
	int x,y;
	poi(){}
	poi(int x,int y):x(x),y(y){}
	friend bool operator == (const poi &r1,const poi &r2)
	{return r1.x==r2.x&&r1.y==r2.y;}
	friend bool operator < (const poi &r1,const poi &r2)
	{
		if(r1.x==r2.x)return r1.y<r2.y;
		return r1.x<r2.x;
	}
	friend int operator ^ (const poi &r1,const poi &r2)
	{return r1.x*r2.y-r2.x*r1.y;};
	friend poi operator - (const poi &r1,const poi &r2)
	{return poi(r1.x-r2.x,r1.y-r2.y);};
}a[N],st[N],b[N];
int xl[N],xr[N],yl[N],yr[N];
int onleft(poi p1,poi p2,poi p3)
{
	return ((p1-p2)^(p3-p2))>=0;
}
int check(int x,int y)
{
	for(int i=0;i<=1;i++)
		for(int j=0;j<=1;j++)
			if(xl[y+j]>x+i||xr[y+j]<x+i||yl[x+i]>y+j||yr[x+i]<y+j)
				return 0;
	return 1;
}
int main()
{
	//freopen("tt.in","r",stdin);
	memset(xl,0x3f,sizeof(xl));
	memset(yl,0x3f,sizeof(yl));
	while(scanf("%d%d",&n,&m)!=EOF&&n)
	{
		top=0;cnt=0;
		for(int i=1,x,y;i<=m;i++)
		{
			scanf("%d%d",&x,&y);b[i]=poi(x,y);
			xl[y]=min(xl[y],x);xr[y]=max(xr[y],x);
			yl[x]=min(yl[x],y);yr[x]=max(yr[x],y);
		}
		for(int i=1;i<=m;i++)
			for(int j=0;j<=1;j++)
				for(int k=0;k<=1;k++)
					if(check(b[i].x-j,b[i].y-k))
						a[++cnt]=poi(b[i].x-j,b[i].y-k);

		sort(a+1,a+1+cnt);
		cnt=unique(a+1,a+1+cnt)-a-1;
		for(int i=1;i<=cnt;i++)
		{
			while(top>=2&&onleft(st[top],st[top-1],a[i]))
				top--;
			st[++top]=a[i];
		}
		int t=top;
		for(int i=cnt-1;i>=1;i--)
		{
			while(top>t&&onleft(st[top],st[top-1],a[i]))
				top--;
			st[++top]=a[i];
		}
		printf("%d\n",top-1);
		for(int i=1;i<top;i++)
			printf("%d %d\n",st[i].x,st[i].y);
		for(int i=1,x,y;i<=m;i++)
		{
			x=b[i].x;y=b[i].y;
			xl[y]=1<<30;xr[y]=0;
			yl[x]=1<<30;yr[x]=0;
		}
	}
	return 0;
}

#define _ijps 0
#define _CRT_SECURE_NO_DEPRECATE
#pragma comment(linker, "/STACK:667772160")
#include <iostream>
#include <cmath>
#include <vector>
#include <time.h>
#include <map>
#include <set>
#include <deque>
#include <cstdio>
#include <cstdlib>
#include <unordered_map>
#include <bitset>
#include <algorithm>
#include <string>
#include <fstream>
#include <assert.h>
#include <list>
#include <cstring>
using namespace std;

#define name ""
typedef unsigned long long ull;
typedef long long ll;
#define mk make_pair
#define forn(i, n) for(ll i = 0; i < (ll)n; i++)
#define fornn(i, q, n) for(ll i = (ll)q; i < (ll)n; i++)
#define times clock() * 1.0 / CLOCKS_PER_SEC

struct __isoff{
	__isoff(){
		if (_ijps)
			freopen("input.txt", "r", stdin), freopen("output.txt", "w", stdout);//, freopen("test.txt", "w", stderr);
		//else freopen(name".in", "r", stdin), freopen(name".out", "w", stdout);
		//ios_base::sync_with_stdio(0);
		//srand(time(0));
		srand('C' + 'T' + 'A' + 'C' + 'Y' + 'M' + 'B' + 'A');
	}
	~__isoff(){
		//if(_ijps) cout<<times<<'\n';
	}
} __osafwf;
const ull p1 = 31;
const ull p2 = 29;
const double eps = 1e-8;
const double pi = acos(-1.0);

const int infi = 1e9 + 7;
const ll inf = 1e18 + 7;
const ll dd = 7e5 + 7;
const ll mod = 1e9 + 7;
const ll mod2 = 1e6 + 3;

pair<int, int> TT;

ll vec(pair<int, int> a, pair<int, int> b, pair<int, int> c){
	a.first -= b.first;
	a.second -= b.second;
	c.first -= b.first;
	c.second -= b.second;
	return 1ll * a.first * c.second - 1ll * a.second * c.first;
}

ll dis(pair<int, int> a, pair<int, int> b){
	a.first -= b.first;
	a.second -= b.second;
	return 1ll * a.first * a.first + 1ll * a.second * a.second;
}

bool cmp(pair<int, int> a, pair<int, int> b){
	int t = vec(a, TT, b);
	if(t == 0){
		return dis(a, TT) < dis(b, TT);
	}
	return t < 0;
}

vector<pair<int, int> > Con(vector<pair<int, int> > G){
	int m = G.size();
	forn(i, m){
		if(G[i] < G[0]){
			swap(G[i], G[0]);
		}
	}
	TT = G[0];
	sort(G.begin() + 1, G.end(), cmp);
	vector<pair<int, int> > E;
	forn(i, m){
		while(E.size() > 1 && vec(E[E.size() - 2], E[E.size() - 1], G[i]) <= 0){
			E.pop_back();
		}
		E.push_back(G[i]);
	}
	return E;
}

int main(){
	int n, m;
	while(cin >> n >> m){
		if(n == 0)
			return 0;
		map<int, map<int, int> > T;
		vector<pair<int, int> > Z, W;
		forn(i, m){
			int x, y;
			cin >> x >> y;
			T[x][y] = 1;
			Z.push_back(mk(x, y));
		}
		W = Z;
		Z = Con(Z);
		forn(i, Z.size()){
			T[Z[i].first][Z[i].second] = 2;
		}
		vector<pair<int, int> > G;
		forn(k, m){
			int i = W[k].first;
			int j = W[k].second;
			if(T[i][j] == 2){
				if(T[i - 1][j] > 0 && T[i][j - 1] > 0 && T[i + 1][j] == 0 && T[i][j + 1] == 0){
					G.push_back(mk(i, j));
				}
				if(T[i + 1][j] > 0 && T[i][j + 1] > 0 && T[i - 1][j] == 0 && T[i][j - 1] == 0){
					G.push_back(mk(i + 1, j + 1));
				}
				if(T[i + 1][j] > 0 && T[i][j - 1] > 0 && T[i - 1][j] == 0 && T[i][j + 1] == 0){
					G.push_back(mk(i + 1, j));
				}
				if(T[i - 1][j] > 0 && T[i][j + 1] > 0 && T[i + 1][j] == 0 && T[i][j - 1] == 0){
					G.push_back(mk(i, j + 1));
				}
			}
		}
		forn(i, G.size()){
			G[i].first -= 1;
			G[i].second -= 1;
		}
		sort(G.begin(), G.end());
		G.resize(unique(G.begin(), G.end()) - G.begin());
		auto E = Con(G);
		cout << E.size() << '\n';
		forn(i, E.size()){
			cout << E[i].first << ' ' << E[i].second << '\n';
		}
	}
}

#include <bits/stdc++.h>

using namespace std;

#define F first
#define S second
#define pb push_back
#define mp make_pair

long long vectorMult(pair<int, int> a, pair<int, int> b, pair<int, int> c) {
    return (c.F - a.F) * 1ll * (b.S - a.S) - (c.S - a.S) * 1ll * (b.F - a.F);
}

bool cmp(pair<int, int> a, pair<int, int> b) {
	return a.F < b.F || a.F == b.F && a.S < b.S;
}

vector<pair<int, int> > convex_hull(vector<pair<int, int> > t) {
    if (t.size() == 1) return t;
    sort(t.begin(), t.end(), cmp);
    vector<pair<int, int> > up, down;
    auto l = t[0];
    auto r = t.back();
    up.pb(t[0]);
    down.pb(t[0]);
    for (int i = 1; i < t.size(); i++) {
        if (vectorMult(l, r, t[i]) <= 0) {
            while (up.size() >= 2 && vectorMult(up[up.size() - 2], up.back(), t[i]) <= 0) {
                up.pop_back();
            }
            up.pb(t[i]);
        }
        if (vectorMult(l, r, t[i]) >= 0) {
            while (down.size() >= 2 && vectorMult(down[down.size() - 2], down.back(), t[i]) >= 0) {
                down.pop_back();
            }
            down.pb(t[i]);
        }
    }
    up.insert(up.end(), down.rbegin() + 1, down.rend() - 1);
    if (up.size() == 2 && up[0] == up[1]) up.pop_back();
    return up;
}

bool check(int x, int y, map<int, int> &l, map<int, int> &r, set<pair<int, int> > &s) {
    if (s.count(mp(x, y))) return true;
    if (!l.count(y)) return false;
//    if (l[y] <= x && r[y] >= x) {
//        cerr << x << " " << y << " Check passed" << endl;
//    }
    return l[y] <= x && r[y] >= x;
}

int main(){
    ios_base::sync_with_stdio(0);
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#endif // LOCAL
while (true) {
    int n, m;
    cin >> n >> m;
    if (n == 0) break;
    vector<pair<int, int> > t(m);
    set<pair<int, int> > s, ms;
    map<int, int> l, r;
    for (int i = 0; i < m; i++) {
        cin >> t[i].F >> t[i].S;
        s.insert(t[i]);
        ms.insert(t[i]);
        s.insert(mp(t[i].F + 1, t[i].S));
        s.insert(mp(t[i].F + 1, t[i].S + 1));
        s.insert(mp(t[i].F + 1, t[i].S - 1));
        s.insert(mp(t[i].F - 1, t[i].S));
        s.insert(mp(t[i].F - 1, t[i].S + 1));
        s.insert(mp(t[i].F - 1, t[i].S - 1));
        s.insert(mp(t[i].F, t[i].S - 1));
        s.insert(mp(t[i].F, t[i].S + 1));
        int y = t[i].S;
        if (l.count(y)) {
            l[y] = min(l[y], t[i].F);
            r[y] = max(r[y], t[i].F);
        } else {
            l[y] = t[i].F;
            r[y] = t[i].F;
        }
    }
    vector<pair<int, int> > f;
    //cerr << "sfas" << endl;
    for (auto &it : s) {
        if (check(it.F, it.S, l, r, ms) && check(it.F + 1, it.S, l, r, ms) && check(it.F, it.S + 1, l, r, ms) && check(it.F + 1, it.S + 1, l, r, ms)) {
            //cerr << it.F << " " << it.S << endl;
            f.pb(mp(it.F, it.S));
        }
    }
    //cerr << "before:" << endl;
    //for (auto it : t) cerr << it.F << " " << it.S << endl;
    //cerr << "after:" << endl;
    f = convex_hull(f);
    //for (auto it : t) cerr << it.F << " " << it.S << endl;
    int mn = 0;
    for (int i = 1; i < f.size(); i++) if (f[i] < f[mn]) {
        mn = i;
    }
    vector<pair<int, int> > ans;
    ans.insert(ans.end(), f.begin() + mn, f.end());
    ans.insert(ans.end(), f.begin(), f.begin() + mn);
    cout << ans.size() << endl;
    for (auto it : ans) cout << it.F << " " << it.S << endl;
}
    return 0;
}

#include <iostream>
#include <vector>
#include <cmath>
#include <cassert>
#include <algorithm>
#include <map>

using namespace std;

#define forsn(i,s,n) for (int i = (s);i < (int)(n);i++)
#define forn(i,n) forsn(i,0,n)
#define dforsn(i,s,n) for (int i = ((n) - 1);i >= (int)(s);i--)
#define dforn(i,n) dforsn(i,0,n)
#define all(v) (v).begin(), (v).end()

typedef double T;
const T EPS = 1e-7;
struct PT {
	 T x, y;
	 PT() {}
	 PT(T xx, T yy) : x(xx), y(yy) {}
	bool operator<(const PT &rhs) const { return make_pair(y,x) < make_pair(rhs.y,rhs.x); }
	bool operator==(const PT &rhs) const { return make_pair(y,x) == make_pair(rhs.y,rhs.x); }
};

T cross(PT p, PT q) { return p.x*q.y-p.y*q.x; }
T area2(PT a, PT b, PT c) { return cross(a,b) + cross(b,c) + cross(c,a); }

bool between(const PT &a, const PT &b, const PT &c) {
	return (fabs(area2(a,b,c)) < EPS && (a.x-b.x)*(c.x-b.x) <= 0 && (a.y-b.y)*(c.y-b.y) <= 0);
}
void ConvexHull(vector<PT> &pts) {
	 sort(pts.begin(), pts.end());
	 pts.erase(unique(pts.begin(), pts.end()), pts.end());
	 vector<PT> up, dn;
	for (int i = 0; i < (int)pts.size(); i++) {
	while (up.size() > 1 && area2(up[up.size()-2], up.back(), pts[i]) >= 0) up.pop_back();
	while (dn.size() > 1 && area2(dn[dn.size()-2], dn.back(), pts[i]) <= 0) dn.pop_back();
 up.push_back(pts[i]);
 dn.push_back(pts[i]);
 }
 pts = dn;
for (int i = (int) up.size() - 2; i >= 1; i--) pts.push_back(up[i]);
if (pts.size() <= 2) return;
 dn.clear();
 dn.push_back(pts[0]);
 dn.push_back(pts[1]);
for (int i = 2; i < (int)pts.size(); i++) {
if (between(dn[dn.size()-2], dn[dn.size()-1], pts[i])) dn.pop_back();
 dn.push_back(pts[i]);
 }
if (dn.size() >= 3 && between(dn.back(), dn[0], dn[1])) {
 dn[0] = dn.back();
 dn.pop_back();
 }
 pts = dn;
}

ostream& operator<<(ostream& os, PT p) {
	return os << p.y << ' ' << p.x;
}

map<int, vector<int> > known;
map<int, vector<int> > known2;

int main() {
	int n, m;
	while (cin >> n >> m, n) {
		known.clear();
		known2.clear();
		forn(i, m) {
			int x, y; cin >> x >> y;
			known[x].push_back(y);
			known2[y].push_back(x);
		}
		for (auto kv : known) sort(kv.second.begin(), kv.second.end());
		for (auto kv : known2) sort(kv.second.begin(), kv.second.end());

		vector<PT> pts;
		for (auto kv : known) {
			int first = *(kv.second.begin());
			//~ cout << "Chusmeo " << kv.first << ' ' << first << endl;
			if (known.find(kv.first - 1) == known.end() || *known[kv.first - 1].begin() > first) {
				//~ cout << kv.first << ' ' << first << endl;
				pts.push_back({(double)(first), (double)(kv.first)});
			}
		}
		for (auto kv : known) {
			int first = *(kv.second.begin());
			//~ cout << "Chusmeo " << kv.first << ' ' << first << endl;
			if (known.find(kv.first + 1) == known.end() || *known[kv.first + 1].begin() > first) {
				//~ cout << kv.first << ' ' << first << endl;
				pts.push_back({(double)(first), (double)(kv.first - 1)});
			}
		}

		//~ cout << "=======\n";

		//~ for (auto kv : known) reverse(kv.second.begin(), kv.second.end());
		for (auto kv : known) {
			int first = *(kv.second.rbegin());
			//~ cout << "Chusmeo " << kv.first << ' ' << first << endl;
			if (known.find(kv.first - 1) == known.end() || *known[kv.first - 1].rbegin() < first) {
				//~ cout << kv.first << ' ' << first - 1 << endl;
				pts.push_back({(double)(first - 1), (double)(kv.first)});
			}
		}
		for (auto kv : known) {
			int first = *(kv.second.rbegin());
			//~ cout << "Chusmeo " << kv.first << ' ' << first << endl;
			if (known.find(kv.first + 1) == known.end() || *known[kv.first + 1].rbegin() < first) {
				//~ cout << kv.first << ' ' << first - 1 << endl;
				pts.push_back({(double)(first - 1), (double)(kv.first - 1)});
			}
		}

		ConvexHull(pts);

		cout << pts.size() << endl;
		forn(i, pts.size()) {
			cout << pts[i] << endl;
		}
		//~ cout << "=============\n";
	}
}

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
#define pb push_back
#define mp make_pair
typedef pair<int, int> PII;

int n, m;
set<PII> have;
int x[200005], y[200005];
int mnx[100005], mxx[100005], mny[100005], mxy[100005];

inline bool check(int x, int y) {
    return have.find(mp(x, y)) != have.end();
}

bool cw(const PII &a, const PII &b, const PII &c) {
    return (LL)(b.first - a.first) * (c.second - a.second) - (LL)(b.second - a.second) * (c.first - a.first) < 0;
}

vector<PII> hull(vector<PII> p) {
    int n = p.size();
    if (n <= 1) return p;
    int k = 0;
    sort(p.begin(), p.end());
    vector<PII> q(n * 2);
    for (int i = 0; i < n; q[k++] = p[i++]) {
        while (k >= 2 && !cw(q[k - 2], q[k - 1], p[i])) {
            --k;
        }
    }
    for (int i = n - 2, t = k; i >= 0; q[k++] = p[i--]) {
        while (k > t && !cw(q[k - 2], q[k - 1], p[i])) {
            --k;
        }
    }
    q.resize(k - 1 - (q[0] == q[1]));
    return q;
}

int main() {
    //freopen("input.txt", "r", stdin);
    while (true) {
        scanf("%d%d", &n, &m);
        if (n == 0) break;
        for (int i = 0; i < m; ++i) {
            scanf("%d%d", x + i, y + i);
        }
        have.clear();
        for (int i = 0; i <= n; ++i) {
            mnx[i] = mny[i] = 1e9;
            mxx[i] = mxy[i] = -1e9;
        }
        for (int i = 0; i < m; ++i) {
            have.insert(mp(x[i], y[i]));
            mnx[y[i]] = min(mnx[y[i]], x[i] - 1);
            mxx[y[i]] = max(mxx[y[i]], x[i]);
            mny[x[i]] = min(mny[x[i]], y[i] - 1);
            mxy[x[i]] = max(mxy[x[i]], y[i]);
        }
        //cerr << mxx << ' ' << mxy << endl;
        vector<PII> bad;
        for (int i = 0; i < m; ++i) {
            bad.pb(mp(x[i], y[i]));
            bad.pb(mp(x[i] - 1, y[i]));
            bad.pb(mp(x[i], y[i] - 1));
            bad.pb(mp(x[i] - 1, y[i] - 1));
        }
        bad = hull(bad);
        set<PII> badSet;
        for (PII x : bad) badSet.insert(x);
        vector<PII> p;
        for (int i = 0; i < m; ++i) {
            int xx = x[i];
            int yy = y[i];
            int ch1 = check(xx, yy);
            int ch2 = check(xx + 1, yy);
            int ch3 = check(xx + 1, yy + 1);
            int ch4 = check(xx, yy + 1);
            int sum = ch1 + ch2 + ch3 + ch4;
            if (sum >= 3 && xx != mnx[yy] && xx != mnx[yy + 1] && yy != mny[xx] && yy != mny[xx + 1] &&
                xx != mxx[yy] && xx != mxx[yy + 1] && yy != mxy[xx] && yy != mxy[xx + 1]) {
                p.pb(mp(xx, yy));
            }

            xx = x[i] - 1;
            yy = y[i] - 1;
            ch1 = check(xx, yy);
            ch2 = check(xx + 1, yy);
            ch3 = check(xx + 1, yy + 1);
            ch4 = check(xx, yy + 1);
            sum = ch1 + ch2 + ch3 + ch4;
            if (sum >= 3 && xx != mnx[yy] && xx != mnx[yy + 1] && yy != mny[xx] && yy != mny[xx + 1] &&
                xx != mxx[yy] && xx != mxx[yy + 1] && yy != mxy[xx] && yy != mxy[xx + 1]) {
                p.pb(mp(xx, yy));
            }
        }
        p = hull(p);
        printf("%d\n", (int)p.size());
        for (PII z : p) {
            printf("%d %d\n", z.first, z.second);
        }
    }
    return 0;
}

#include <bits/stdc++.h>

#define FO(i,a,b) for (int i = (a); i < (b); i++)
#define sz(v) int(v.size())

using namespace std;

#include <bits/stdc++.h>

#define INF 1000000010
//PAIRS:
#define mp make_pair
#define fi first
#define se second
typedef pair<int,int> pii;
typedef long long ll;

struct point {
    ll x, y;
    int id;
    point (){};
    point (ll _x, ll _y, int _id) : x(_x), y(_y), id(_id) {};
};

struct vect {
    ll x, y;
    vect (){};
    vect (ll _x, ll _y) : x(_x), y(_y) {};
    vect (point a, point b) : x(b.x-a.x), y(b.y-a.y) {};
};

//Returns the signed norm of a x b
ll crossProductNorm (vect a, vect b) {
    return a.x*b.y-b.x*a.y;
}

//Returns true if b is ccw of a
bool isCCW (vect a, vect b) {
    return crossProductNorm (a,b) < 0;
}

ll dst(point a, point b) {
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}

point refPoint;
//Returns true if a is clockwise of b with reference to refPoint
bool compCW (point a, point b) {
    vect aVect (refPoint, a);
    vect bVect (refPoint, b);
    return isCCW (aVect,bVect) || (
            crossProductNorm(aVect,bVect) == 0 && dst(refPoint,a) <
            dst(refPoint,b)
            );
}

// Also sorts it wrt lowest point:
vector <point> constructConvexHull (vector <point> &pts) {
    if (pts.empty()) {
        vector <point> v;
        return v;
    }
    int minY = pts[0].y, minX = pts[0].x;
    int minYP = 0;
    FO (i,1,pts.size()) if (pts[i].y < minY || (pts[i].y == minY && pts[i].x < minX)) minY = pts[i].y, minX = pts[i].x, minYP = i;
    refPoint = pts[minYP];
    pts.erase (pts.begin()+minYP);
    sort (pts.begin(),pts.end(),compCW);
    pts.insert (pts.begin(), refPoint);
    //printf ("Outputting sorted pts:\n");
    //FO (i,0,pts.size()) printf ("%d: %lld %lld\n", pts[i].id, pts[i].x, pts[i].y);

    vector <point> myCH;
    myCH.push_back (pts[0]);
    FO (i,1,pts.size()) {
        while (myCH.size() >= 2) {
            vect v1(myCH[myCH.size()-1],pts[i]);
            vect v2(myCH[myCH.size()-2],myCH[myCH.size()-1]);
            if (!isCCW (v2, v1)) myCH.pop_back();
            else break;
        }
        myCH.push_back (pts[i]);
    }
    while (myCH.size() > 2) {
        vect v1(myCH[myCH.size()-1],pts[0]);
        vect v2(myCH[myCH.size()-2],myCH[myCH.size()-1]);
        if (!isCCW (v2, v1)) myCH.pop_back();
        else break;
    }

    return myCH;
}

pair<int,int> mny[100005], mnx[100005], mxy[100005], mxx[100005];
int T;

int main() {
    while (1) {
        int n, M; scanf("%d %d", &n, &M);
        if (n == 0) return 0;
        set<pair<int,int> > tp;
        set<pair<int,int> > cnd;
        T++;
        FO(t,0,M) {
            int x, y;
            scanf("%d %d", &x, &y); x--; y--;
            tp.emplace(x,y);
            if (mny[x].second != T) mny[x] = mp(y,T);
            if (mxy[x].second != T) mxy[x] = mp(y,T);
            if (mnx[y].second != T) mnx[y] = mp(x,T);
            if (mxx[y].second != T) mxx[y] = mp(x,T);

            mny[x].first = min(mny[x].first, y);
            mxy[x].first = max(mxy[x].first, y);

            mnx[y].first = min(mnx[y].first, x);
            mxx[y].first = max(mxx[y].first, x);
            FO(dy,-1,2) FO(dx,-1,2) {
                cnd.emplace(x+dx,y+dy);
            }
        }
        vector<point> vp;
        for (auto p : cnd) {
            int x = p.first, y = p.second;
            int cnt = 0;
            FO(dy,-1,1) FO(dx,-1,1) {
                cnt += tp.count(mp(x+dx,y+dy));
            }
            if (cnt == 4) {
                //printf("(%d,%d)\n", x, y);
                vp.emplace_back(x,y,0);
            } else if (cnt == 3) {
                FO(dy,-1,1) FO(dx,-1,1) {
                    if (!tp.count(mp(x+dx,y+dy))) {
                        int nx = x+dx, ny = y+dy;
                        if (mny[nx].first > ny || mxy[nx].first < ny ||
                                mnx[ny].first > nx || mxx[ny].first < nx) {
                        } else {
                            vp.emplace_back(x,y,0);
                        }
                    }
                }
            }
        }
        vector<point> ch = constructConvexHull(vp);
        int m = sz(ch);
        int mp = 0;
        FO(i,1,m) if (ch[i].x < ch[mp].x || (ch[i].x == ch[mp].x &&
                ch[i].y < ch[mp].y)) mp = i;
        printf("%d\n", m);
        FO(i,0,m) printf("%lld %lld\n", ch[(mp+i)%m].x, ch[(mp+i)%m].y);
    }
}

#define pb push_back
#define mp make_pair
#define first x
#define second y
#define lsb(x) x & -x
#define l(x) (x<<1)
#define r(x) ((x<<1)|1)
#include<bits/stdc++.h>
#include<sstream>
using namespace std;
typedef long long LL;
typedef long double LD;
typedef vector<int> VI;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
// primes less than 100
const int PRIM[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};
const int MOD = 1000000007;
const int NMAX = 500066;
const double EPS = 1e-12;
const int INF16 = 32000;
const int INF = 0x3F3F3F3F;
const LL INF64 = LL(1e18);
const int dx[]={-1,1,0,0,1,-1,1,-1};
const int dy[]={0,0,1,-1,1,1,-1,-1};

int n,m;
PII lu, rd;
PII A[NMAX];
char c;
PII h[NMAX];
PII vaux[NMAX];
int nxt[NMAX], prv[NMAX];
int coordx[NMAX], coordy[NMAX];
int minx[NMAX], miny[NMAX], maxx[NMAX], maxy[NMAX];

bool cmp(PII l, PII r)
{
    return l.x<r.x || (l.x==r.x && l.y<r.y);
}

bool d(PII &a,PII &b,PII &c)
{
    return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x)<0;
}
int cp(PII &a,PII &b,PII &c)
{
    return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x);
}

bool isin(PII p)
{
    int l=1, r=m;
    while(r-l>5)
    {
        int pivot=(l+r)>>1;
        if(A[pivot]>p)
            r=pivot;
        else
            l=pivot;
    }
    bool q=0;
    for(l; l<=r; ++l)
        if(A[l]==p)
            q=1;
    q=0;
    for(int i=1; i<=m; ++i)
        if(A[i]==p)
            q=1;

    if(!coordx[p.x] || !coordy[p.y])
        return 0;

    if(minx[p.x]<=p.y && p.y<=maxx[p.x] && miny[p.y]<=p.x && p.x<=maxy[p.y])
        return 1;
    else
        return 0;

    return q;
}

void read()
{
    for(int i=1; i<=m; ++i){
        cin>>A[i].y>>A[i].x;
        minx[A[i].x]=min(minx[A[i].x], A[i].y);
        maxx[A[i].x]=max(maxx[A[i].x], A[i].y);
        miny[A[i].y]=min(miny[A[i].y], A[i].x);
        maxy[A[i].y]=max(maxy[A[i].y], A[i].x);
        coordx[A[i].x]=1;
        coordy[A[i].y]=1;
    }
    sort(A+1, A+1+m);
    set<PII> v;
    for(int k=1; k<=m; ++k){
        int i=A[k].x;
        int j=A[k].y;

        if(isin({i-1, j-1})==0 && isin({i-1, j})==0 && isin({i, j-1})==0)
        {
            v.insert({j, i});
        }
        if(isin({i+1, j-1})==0 && isin({i, j-1})==0 && isin({i+1, j})==0)
        {
            v.insert({j, i-1});
        }
        if(isin({i-1, j+1})==0 && isin({i-1, j})==0 && isin({i, j+1})==0)
        {
            v.insert({j-1, i});
        }
        if(isin({i+1, j+1})==0 && isin({i+1, j})==0 && isin({i, j+1})==0)
        {
            v.insert({j-1, i-1});
        }
    }
    int k=0;
    for(auto p: v)
        vaux[k++]=p;

    reverse_copy(vaux, vaux+k-1, vaux+k);
    int i=0, j=0;
    for(i=0;i<2*k-1;h[j++]=vaux[i++])
        while(j>1&&d(h[j-2],h[j-1],vaux[i]))--j;
    j--;

    k=j;
    for(int i=0; i<k; ++i)
        nxt[i]=i+1;
    nxt[k-1]=0;
    for(int i=0; i<k; ++i)
        prv[i]=i-1;
    prv[0]=k-1;
    i=0;
    j=0;
    while(j<2*k)
    {
        if(cp(h[prv[i]], h[i], h[nxt[i]])==0)
            prv[nxt[i]]=prv[i], nxt[prv[i]]=nxt[i];
        i=nxt[i];
        j++;
    }
    int bi=i;
    PII mp={INF, INF};
    int mi;

    if(h[bi]<mp)
        mp=h[bi], mi=bi;
    int rs=1;
    while(nxt[i]!=bi)
    {
        i=nxt[i];
        if(h[i]<mp)
            mp=h[i], mi=i;
        rs++;
    }

    cout<<rs<<'\n';
    cout<<h[mi].x<<" "<<h[mi].y<<"\n";
    i=mi;
    while(h[prv[i]]!=h[mi])
    {
        i=prv[i];
        cout<<h[i].x<<" "<<h[i].y<<"\n";
    }
    for(int i=1; i<=m; ++i)
    {
        coordx[A[i].x]=0;
        coordy[A[i].y]=0;
        minx[A[i].x]=INF;
        miny[A[i].y]=INF;
        maxx[A[i].x]=0;
        maxy[A[i].y]=0;
    }
}

int main()
{
    //freopen("input.in", "rt", stdin);
    memset(minx, INF, sizeof(minx));
    memset(miny, INF, sizeof(miny));
    while(cin>>n>>m)
    {
        if(n==0){
            return 0;
        }
        read();
    }
    return 0;
}

#include <bits/stdc++.h>
using namespace std;

const int MAX = (int)1E5 + 10;
const int dx[] = {0, -1, 0, 1};
const int dy[] = {-1, 0, 1, 0};

int n, m, cookie;
set<pair<int, int> > A, B;
int touch[MAX], minr[MAX], maxr[MAX];
vector<pair<int, int> > cv;

bool is_four(int x, int y){
    if(x < 1 || x > n) return false;
    if(touch[x] != cookie) return false;
    if(A.find(make_pair(x, y)) != A.end()) return false;
    return minr[x] <= y && y <= maxr[x];
}

long long sqr(long long a){
    return a*a;
}

long long dist(const pair<int, int>& a, const pair<int, int>& b){
    return sqr(a.first - b.first) + sqr(a.second - b.second);
}

long long ccw(const pair<int, int>& o, const pair<int, int>& a, const pair<int, int>& b){
    return (long long)(a.first - o.first)*(b.second - o.second) - (long long)(a.second - o.second)*(b.first - o.first);
}

bool cmp(const pair<int, int>& l, const pair<int, int>& r){
    long long c = ccw(cv[0], l, r);
    return c < 0 || (c == 0 && dist(cv[0], l) < dist(cv[0], r));
}

void graham_scan(){
    for(int i = 1; i < (int)cv.size(); i++)
    if(cv[i].first < cv[0].first || (cv[i].first == cv[0].first && cv[i].second < cv[0].second)) swap(cv[i], cv[0]);

    sort(cv.begin() + 1, cv.end(), cmp);

    cv.push_back(cv[0]);
    int top = 1;
    for(int i = 2; i < (int)cv.size(); i++){
        while(top > 0 && ccw(cv[top - 1], cv[top], cv[i]) >= 0) top--;
        cv[++top] = cv[i];
    }
    cv.resize(top);
}

int main(){
    while(true){
        A.clear();
        B.clear();
        cv.resize(0);

        scanf("%d%d", &n, &m);
        if(n == 0 && m == 0) break;

        cookie++;

        for(int i = 0; i < m; i++){
            int x, y; scanf("%d%d", &x, &y);
            A.insert(make_pair(x, y));

            if(touch[x] != cookie){
                touch[x] = cookie;
                minr[x] = y;
                maxr[x] = y;
            }

            minr[x] = min(minr[x], y);
            maxr[x] = max(maxr[x], y);
        }

        for(auto a : A){
            for(int i = 0; i < 4; i++){
                int x = a.first + dx[i];
                int y = a.second + dy[i];
                if(is_four(x, y)) B.insert(make_pair(x, y));
            }
        }

        for(auto b : B) A.insert(b);

        for(auto a : A)
        if(A.find(make_pair(a.first + 1, a.second)) != A.end()
        && A.find(make_pair(a.first, a.second + 1)) != A.end()
        && A.find(make_pair(a.first + 1, a.second + 1)) != A.end()){
            cv.push_back(a);
        }

        graham_scan();

        printf("%d\n", (int)cv.size());
        for(auto v : cv) printf("%d %d\n", v.first, v.second);
    }
}

#include <bits/stdc++.h>
#define int long long
#define FOR(i,a,b) for(int i=(a),_b=(b); i<=_b; ++i)
#define FORD(i,a,b) for(int i=(a),_b=(b); i>=_b; --i)
#define REP(i,a) for(int i=0,_a=(a); i < _a; ++i)

#define DEBUG(X) { cout << #X << " = " << (X) << endl; }
#define PR(A,n)  { cout << #A << " = "; FOR(_,1,n) cout << A[_] << ' '; cout << endl; }
#define PR0(A,n) { cout << #A << " = "; REP(_,n) cout << A[_] << ' '; cout << endl; }

#define sqr(x) ((x) * (x))
#define ll long long
#define __builtin_popcount __builtin_popcountll
#define SZ(x) ((int) (x).size())
using namespace std;

double safe_sqrt(double x) {
    return sqrt(max((double)0.0,x));
}
int GI(ll& x) {
    return scanf("%lld", &x);
}
#define EPS 1e-6
const double PI = acos(-1.0);

double DEG_to_RAD(double d) { return d * PI / 180.0; }
double RAD_to_DEG(double r) { return r * 180.0 / PI; }

inline int cmp(double a, double b) {
    return (a < b - EPS) ? -1 : ((a > b + EPS) ? 1 : 0);
}

struct Point { // <--> Vector
    double x, y;
    Point(double x = 0.0, double y = 0.0) : x(x), y(y) {}

    Point operator + (const Point& a) const { return Point(x+a.x, y+a.y); }
    Point operator - (const Point& a) const { return Point(x-a.x, y-a.y); }
    Point operator * (double k) const { return Point(x*k, y*k); }
    Point operator / (double k) const { return Point(x/k, y/k); }

    bool operator<(const Point &rhs) const { return make_pair(y,x) < make_pair(rhs.y,rhs.x); }
    bool operator==(const Point &rhs) const { return make_pair(y,x) == make_pair(rhs.y,rhs.x); }

    double operator * (const Point& a) const { return x*a.x + y*a.y; } // dot product
    double operator % (const Point& a) const { return x*a.y - y*a.x; } // cross product

    int cmp(Point q) const { if (int t = ::cmp(x,q.x)) return t; return ::cmp(y,q.y); }

    Point conj() { return Point(x, -y); }
    double norm() { return x*x + y*y; }

    // Note: There are 2 ways for implementing len():
    // 1. sqrt(norm()) --> fast, but inaccurate (produce some values that are of order X^2)
    // 2. hypot(x, y) --> slow, but much more accurate
    double len() { return sqrt(norm()); }

    Point rotate(double alpha) {
        double cosa = cos(alpha), sina = sin(alpha);
        return Point(x * cosa - y * sina, x * sina + y * cosa);
    }
};

int ccw(Point a, Point b, Point c) {
    return cmp((b-a)%(c-a),0);
}
typedef vector< Point > Polygon;

double area2(Point a, Point b, Point c) { return a%b + b%c + c%a; }
bool between(const Point &a, const Point &b, const Point &c) {
    return (fabs(area2(a,b,c)) < EPS && (a.x-b.x)*(c.x-b.x) <= 0 && (a.y-b.y)*(c.y-b.y) <= 0);
}

void ConvexHull(vector<Point> &pts) {
    sort(pts.begin(), pts.end());
    pts.erase(unique(pts.begin(), pts.end()), pts.end());
    vector<Point> up, dn;
    for (int i = 0; i < pts.size(); i++) {
        while (up.size() > 1 && area2(up[up.size()-2], up.back(), pts[i]) >= 0) up.pop_back();
        while (dn.size() > 1 && area2(dn[dn.size()-2], dn.back(), pts[i]) <= 0) dn.pop_back();
        up.push_back(pts[i]);
        dn.push_back(pts[i]);
    }
    pts = dn;
    for (int i = (int) up.size() - 2; i >= 1; i--) pts.push_back(up[i]);

    if (pts.size() <= 2) return;
    dn.clear();
    dn.push_back(pts[0]);
    dn.push_back(pts[1]);
    for (int i = 2; i < pts.size(); i++) {
        if (between(dn[dn.size()-2], dn[dn.size()-1], pts[i])) dn.pop_back();
        dn.push_back(pts[i]);
    }
    if (dn.size() >= 3 && between(dn.back(), dn[0], dn[1])) {
        dn[0] = dn.back();
        dn.pop_back();
    }
    pts = dn;
}
istream& operator >> (istream& cin, Point& p) {
    cin >> p.x >> p.y;
    return cin;
}
ostream& operator << (ostream& cout, Point& p) {
    cout << p.x << ' ' << p.y;
    return cout;
}
#define Det(a,b,c) ((double)(b.x-a.x)*(double)(c.y-a.y)-(double)(b.y-a.y)*(c.x-a.x))
bool in_convex(vector<Point>& l, Point p){
    int a = 1, b = l.size()-1, c;
    if (Det(l[0], l[a], l[b]) > 0) swap(a,b);
    // Allow on edge --> if (Det... > 0 || Det ... < 0)
    if (Det(l[0], l[a], p) >= 0 || Det(l[0], l[b], p) <= 0) return false;
    while(abs(a-b) > 1) {
        c = (a+b)/2;
        if (Det(l[0], l[c], p) > 0) b = c; else a = c;
    }
    // Alow on edge --> return Det... <= 0
    return Det(l[a], l[b], p) < 0;
}
Polygon cv123;
set< pair<int,int> > all123;

bool ok(int x, int y) {
    return all123.count(make_pair(x, y))
        || in_convex(cv123, Point(x, y));
}

bool check(int x, int y) {
    return ok(x, y) && ok(x+1, y) && ok(x, y+1) && ok(x+1, y+1);
}

#undef int
int main() {
#define int long long
    ios :: sync_with_stdio(0); cin.tie(0);
    cout << (fixed) << setprecision(9);
    int n, m;
    while (GI(n) == 1 && GI(m) == 1 && n && m) {
        // Generate magic polygon for checking 0 - 4
        all123.clear();
        cv123.clear();
        FOR(i,1,m) {
            int x, y; GI(x); GI(y);
            all123.insert(make_pair(x, y));
            cv123.push_back(Point(x, y));
        }
        ConvexHull(cv123);

        // Generate candidate points
        set< pair<int,int> > candidates;
        for(auto p : all123) {
            int x = p.first;
            int y = p.second;
            candidates.insert(make_pair(x, y));
            candidates.insert(make_pair(x, y-1));
            candidates.insert(make_pair(x-1, y));
            candidates.insert(make_pair(x-1, y-1));
        }

        // check candidate points
        Polygon all;
        for(auto p : candidates) {
            if (check(p.first, p.second)) all.push_back(Point(p.first, p.second));
        }
        ConvexHull(all);

        // print answer
        if (ccw(all[0], all[1], all[2]) > 0) reverse(all.begin(), all.end());

        vector< pair<int,int> > res;
        for(auto p : all) {
            res.push_back(make_pair(
                        (int) (round(p.x) + 1e-6),
                        (int) (round(p.y) + 1e-6)));
        }
        int start = 0;
        FOR(i,1,SZ(res)-1)
            if (res[i] < res[start]) start = i;

        cout << SZ(res) << '\n';
        REP(i,SZ(res)) {
            int u = (i + start) % SZ(res);
            cout << res[u].first << ' ' << res[u].second << '\n';
        }
    }
}

#include <bits/stdc++.h>
using namespace std;

#define FOR(i, a, b) for (int i = (int)(a); i < (int)(b); ++i)
#define REP(i, n) FOR(i, 0, n)
#define TRACE(x) cerr << #x << " = " << x << endl
#define _ << " _ " <<

#define pb push_back
#define x first
#define y second

typedef long long ll;
typedef pair<int, int> pt;

int N, M;

ll ccw(pt a, pt b, pt c) {
  return (ll)a.x*(b.y-c.y) + (ll)b.x*(c.y-a.y) + (ll)c.x*(a.y-b.y);
}

vector<pt> convex_hull(vector<pt> P) {
  sort(P.begin(), P.end());

  vector<pt> H;
  REP(step, 2) {
    int start = (int)H.size();
    for (auto p : P) {
      while ((int)H.size() >= start + 2 && ccw(H[H.size()-2], H.back(), p) >= 0)
        H.pop_back();
      H.push_back(p);
    }

    reverse(P.begin(), P.end());
    H.pop_back();
  }

  return H;
}

inline bool pt_in_triangle(pt p, pt a, pt b, pt c) {
  return abs(ccw(p, a, b)) + abs(ccw(p, b, c)) + abs(ccw(p, a, c))
      == abs(ccw(a, b, c));
}

inline bool inside(int x, int y, vector<pt> &cv) {
  pt p = {x, y};
  int n = (int)cv.size();
  int lo = 1, hi = n - 1;
  while (lo < hi) {
    int mid = (lo + hi) / 2;
    if (ccw(cv[0], cv[mid], p) < 0) lo = mid + 1;
    else hi = mid;
  }
  return (lo <= n-2 && pt_in_triangle(p, cv[0], cv[lo], cv[lo+1]))
      || (lo >= 2 && pt_in_triangle(p, cv[0], cv[lo], cv[lo-1]));
}

void solve() {
  vector<pt> P;
  REP(i, M) {
    int u, v; cin >> u >> v;
    P.pb({u, v});
  }

  vector<pt> CP = convex_hull(P);
  vector<pt> H;

  auto check = [&](int x, int y) {
    REP(dx, 2) REP(dy, 2)
      if (!inside(x+dx, y+dy, CP))
        return;
    H.pb({x, y});
  };

  for (auto it : P) {
    for (int dx = -1; dx <= 0; ++dx)
      for (int dy = -1; dy <= 0; ++dy)
        check(it.x + dx, it.y + dy);
  }

  H = convex_hull(H);
  cout << (int)H.size() << endl;
  for (auto it : H) cout << it.x << " " << it.y << endl;
}

int main(void) {
  ios_base::sync_with_stdio(false);

  while ((cin >> N >> M) && N) {
    solve();
  }

  return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define uint unsigned
#define pii pair<int,int>
#define pll pair<ll,ll>
#define IT iterator
#define PB push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define CLR(a,v) memset(a,v,sizeof(a));
#define CPY(a,b) memcpy(a,b,sizeof(a));
#define debug puts("wzpakking")
#define y1 ysghysgsygsh
using namespace std;
const int d1[4][2]={{0,1},{-1,0},{0,-1},{1,0}};
const int d2[4][2]={{1,1},{-1,1},{-1,-1},{1,-1}};
const int d3[4][2]={{0,0},{-1,0},{-1,-1},{0,-1}};
const int N=200005;
int n,m,top,ok[4];
map<int,int> mn,mx;
struct P{
	int x,y;
	P(){}
	P(int _x,int _y){
		x=_x; y=_y;
	}
	P operator +(const P &a)const{
		return P(x+a.x,y+a.y);
	}
	P operator -(const P &a)const{
		return P(x-a.x,y-a.y);
	}
	ll operator *(const P &a)const{
		return 1ll*x*a.y-1ll*y*a.x;
	}
	bool operator <(const P &a)const{
		return x==a.x?y<a.y:x<a.x;
	}
	bool operator ==(const P &a)const{
		return x==a.x&&y==a.y;
	}
	ll dis(){
		return 1ll*x*x+1ll*y*y;
	}
}a[N],q[N*4];
bool cmp(P x,P y){
	if (x*y) return x*y>0;
	return x.dis()<y.dis();
}
void Convex_hull(){
	sort(q+1,q+top+1);
	top=unique(q+1,q+top+1)-q-1;
	P bas=a[1];
	//For(i,1,top) cout<<q[i].x<<' '<<q[i].y<<endl;
	For(i,1,top) q[i]=q[i]-bas;
	sort(q+2,q+top+1,cmp);
	//For(i,1,top) cout<<q[i].x<<' '<<q[i].y<<endl;
	n=top; top=1;
	For(i,2,n){
		for (;top>=2&&(q[top]-q[top-1])*(q[i]-q[top])<=0;top--);
		q[++top]=q[i];
	}
	For(i,1,top)
		q[i]=q[i]+bas;
}
bool chk(int x,int y){
	if (mn.find(x)==mn.end()) return 0;
	return mn[x]<=y&&mx[x]>=y;
}
void solve(){
	top=0;
	scanf("%d%d",&n,&m);
	if (!(n+m)) exit(0);
	mn.clear(); mx.clear();
	For(i,1,m) scanf("%d%d",&a[i].x,&a[i].y);
	For(i,1,m) mn[a[i].x]=n+1,mx[a[i].x]=0;
	For(i,1,m){
		mn[a[i].x]=min(mn[a[i].x],a[i].y);
		mx[a[i].x]=max(mx[a[i].x],a[i].y);
	}
	For(i,1,m){
		ok[0]=ok[1]=ok[2]=ok[3]=1;
		For(j,0,3)
			if (!chk(a[i].x+d1[j][0],a[i].y+d1[j][1]))
				ok[j]=ok[(j+1)%4]=0;
		For(j,0,3)
			if (!chk(a[i].x+d2[j][0],a[i].y+d2[j][1]))
				ok[j]=0;
		For(j,0,3) if (ok[j])
			q[++top]=P(a[i].x+d3[j][0],a[i].y+d3[j][1]);
	}
	//cout<<top<<endl;
	Convex_hull();
	reverse(q+2,q+top+1);
	printf("%d\n",top);
	For(i,1,top) printf("%d %d\n",q[i].x,q[i].y);
}
int main(){
	for (;;) solve();
} //hello

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define ii pair<int,int>
#define INF 1000000000
int g[510][510];
int n,m;
vector<ii> p,u,d;
int ccw(ii a,ii b,ii c) {
	int dx1=b.first-a.first,dy1=b.second-a.second;
	int dx2=c.first-b.first,dy2=c.second-b.second;
	return (dx1*dy2-dx2*dy1>=0);
}
bool cmp(ii a,ii b) {
	if (a.first==b.first) return a.second>b.second;
	return a.first<b.first;
}
set<ii> s;
int l[100010],r[100010],x,y;
vector<ii> pt;
bool in(int a,int b) {
	if (s.find(mp(a,b))!=s.end()) return 1;
	if (a>=l[b] && a<=r[b]) return 1;
	return 0;
}
int dirx[]={-1,0,1,1,1,0,-1,-1};
int diry[]={1,1,1,0,-1,-1,-1,0};
bool can[8];
int main() {
	while(scanf("%d%d",&n,&m),n!=0) {
		p.clear();
		u.clear();
		d.clear();
		s.clear();
		pt.clear();
		for (int i=0;i<=n;i++) {
			l[i]=INF,r[i]=-2;
		}
		for (int i=0;i<m;i++) {
			scanf("%d%d",&x,&y);
			l[y]=min(l[y],x);
			r[y]=max(r[y],x);
			s.insert(mp(x,y));
			pt.pb(mp(x,y));
		}
		for (int i=0;i<sz(pt);i++) {
			x=pt[i].first,y=pt[i].second;
			for (int j=0;j<8;j++) {
				can[j]=in(x+dirx[j],y+diry[j]);
			}
			if (can[0]&&can[1]&&can[7]) {
				p.pb(mp(x,y+1));
			}
			if (can[1]&&can[2]&&can[3]) {
				p.pb(mp(x+1,y+1));
			}
			if (can[3]&&can[4]&&can[5]) {
				p.pb(mp(x+1,y));
			}
			if (can[5]&&can[6]&&can[7]) {
				p.pb(mp(x,y));
			}
		}
		sort(all(p),cmp);
		p.resize(distance(p.begin(),unique(all(p))));
		u.pb(p[0]);
		for (int i=0;i<sz(p);i++) {
			while(sz(u)>1 && ccw(u[sz(u)-2],u[sz(u)-1],p[i])) {
				u.pop_back();
			}
			u.pb(p[i]);
		}
		d.pb(p[sz(p)-1]);
		for (int i=sz(p)-2;i>=0;i--) {
			while(sz(d)>1 && ccw(d[sz(d)-2],d[sz(d)-1],p[i])) {
				d.pop_back();
			}
			d.pb(p[i]);
		}
		for (int i=1;i<sz(d)-1;i++) {
			u.pb(d[i]);
		}
		int s=sz(u);
		printf("%d\n", s);
		int rr=(min_element(all(u)))-u.begin();
		for (int i=0;i<s;i++) {
			printf("%d %d\n", u[(rr+i)%s].first-1,u[(rr+i)%s].second-1);
		}
	}
}

#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <iostream>
#include <sstream>
#include <cstring>
#include <numeric>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define F0(i,n) for (int i = 0; i < n; i++)
#define F1(i,n) for (int i = 1; i <= n; i++)
#define CL(a,x) memset(x, a, sizeof(x));
#define SZ(x) ((int)x.size())
const double eps = 1e-10;
const int inf = 1000000009;
int i, j, k, m, n, l;
int ans;
string s[505];

pii head;
int cc(pii A, pii B) {
	A.first -= head.first; A.second -= head.second;
	B.first -= head.first; B.second -= head.second;
	if ((ll)A.first * B.second != (ll)A.second * B.first) return (ll)A.first * B.second < (ll)A.second * B.first;
	return (ll)A.first * A.first + (ll)A.second * A.second < (ll)B.first * B.first + (ll)B.second * B.second;
}

int cmp(pii head, pii A, pii B) {
	A.first -= head.first; A.second -= head.second;
	B.first -= head.first; B.second -= head.second;
	return (ll)A.first * B.second - (ll)A.second * B.first;
}

int main() {
	//freopen("x.in", "r", stdin);

	while (1) {
		cin >> n; if (n == 0) break;

		vector<pii> a;

		/*
		F0(i, n) cin >> s[n - i - 1];
		F0(i, n) F0(j, n) if (s[i][j] != '0' && s[i][j] != '4') {
			a.push_back(pii(j, i));
		}*/
		cin >> m;
		while (m--) {
			scanf("%d%d", &i, &j);
			a.push_back(pii(i - 1, j - 1));
		}

		set<pii> S(a.begin(), a.end());

		sort(a.begin(), a.end());
		F0(i, SZ(a) - 1) if (a[i].first == a[i + 1].first) {
			if (a[i].second + 1 < a[i + 1].second) S.insert(pii(a[i].first, a[i].second + 1));
			if (a[i].second + 2 < a[i + 1].second) S.insert(pii(a[i].first, a[i + 1].second - 1));
		}
		F0(i, SZ(a)) swap(a[i].first, a[i].second);
		sort(a.begin(), a.end());
		F0(i, SZ(a) - 1) if (a[i].first == a[i + 1].first) {
			if (a[i].second + 1 < a[i + 1].second) S.insert(pii(a[i].second + 1, a[i].first));
			if (a[i].second + 2 < a[i + 1].second) S.insert(pii(a[i + 1].second - 1, a[i].first));
		}

		vector<pii> p;
		for (auto& x : S) {
			if (S.count(pii(x.first + 1, x.second)) &&
				S.count(pii(x.first + 1, x.second + 1)) &&
				S.count(pii(x.first, x.second + 1))) p.push_back(pii(x.first + 1, x.second + 1));
		}

		int k = 0;
		F0(i, SZ(p)) if (p[i] < p[k]) k = i;
		swap(p[k], p[0]);
		head = p[0];
		sort(p.begin() + 1, p.end(), cc);
		vector<pii> w;
		w.push_back(p[0]);
		for (int i = 1; i < SZ(p); i++) {
			while (w.size() >= 2 && cmp(w[SZ(w) - 2], w[SZ(w) - 1], p[i]) >= 0) w.pop_back();
			w.push_back(p[i]);
		}

		cout << SZ(w) << endl;
		F0(i, SZ(w)) cout << w[i].first << " " << w[i].second << endl;
	}

	return 0;
}

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <ctype.h>
#include <deque>
#include <queue>
#include <cstring>
#include <set>
#include <list>
#include <map>
#include <random>
#include <unordered_map>
#include <stdio.h>

using namespace std;

typedef long long ll;
typedef std::vector<int> vi;
typedef std::vector<bool> vb;
typedef std::vector<string> vs;
typedef std::vector<double> vd;
typedef std::vector<long long> vll;
typedef std::vector<std::vector<int> > vvi;
typedef vector<vvi> vvvi;
typedef vector<vll> vvll;
typedef std::vector<std::pair<int, int> > vpi;
typedef vector<vpi> vvpi;
typedef std::pair<int, int> pi;
typedef std::pair<ll, ll> pll;
typedef std::vector<pll> vpll;

const long long mod = 1000000007;

#define all(c) (c).begin(),(c).end()
#define sz(c) (int)(c).size()
#define forn(i, a, b) for(int i = a; i < b; i++)

#define pb push_back
#define mp make_pair

struct pt {
    pt(ll x, ll y) : x(x), y(y) {};
    ll x, y;
};

bool cmp (pt a, pt b) {
    return a.x < b.x || a.x == b.x && a.y < b.y;
}

bool cw (pt a, pt b, pt c) {
    return a.x*(b.y-c.y)+b.x*(c.y-a.y)+c.x*(a.y-b.y) < 0;
}

bool ccw (pt a, pt b, pt c) {
    return a.x*(b.y-c.y)+b.x*(c.y-a.y)+c.x*(a.y-b.y) > 0;
}

void convex_hull (vector<pt> & a) {
    if (a.size() == 1)  return;
    sort (a.begin(), a.end(), &cmp);
    pt p1 = a[0],  p2 = a.back();
    vector<pt> up, down;
    up.push_back (p1);
    down.push_back (p1);
    for (size_t i=1; i<a.size(); ++i) {
        if (i==a.size()-1 || cw (p1, a[i], p2)) {
            while (up.size()>=2 && !cw (up[up.size()-2], up[up.size()-1], a[i]))
                up.pop_back();
            up.push_back (a[i]);
        }
        if (i==a.size()-1 || ccw (p1, a[i], p2)) {
            while (down.size()>=2 && !ccw (down[down.size()-2], down[down.size()-1], a[i]))
                down.pop_back();
            down.push_back (a[i]);
        }
    }
    a.clear();
    for (size_t i=0; i<up.size(); ++i)
        a.push_back (up[i]);
    for (size_t i=down.size()-2; i>0; --i)
        a.push_back (down[i]);
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt", "rt", stdin);
    freopen("output.txt", "wt", stdout);
#endif
    while(1) {
        int n,m;
        scanf("%d %d\n", &n, &m);
        if (n==0) break;
        vector<pair<pi, int>> pxu, pxd, pyl, pyr;
        vs a(n);
        vpi lol;
        forn(i,0,m) {
            int x,y;
            scanf("%d %d", &x, &y);

            x--;
            y--;
            lol.pb(mp(x,y));
            pxu.pb(mp(mp(x,y), i));
            pxd.pb(mp(mp(x,-y), i));
            pyl.pb(mp(mp(y,x), i));
            pyr.pb(mp(mp(y,-x), i));
        }
        sort(all(pxu));
        sort(all(pxd));
        sort(all(pyl));
        sort(all(pyr));
        vi ban(m,0);
        int miny = 10000000;
        int maxy = -1;

        forn(i,0,m) {
            if(pxu[i].first.second <= miny) {
                ban[pxu[i].second] = 1;
                miny = pxu[i].first.second;
            }
        }

        miny = 10000000;
        maxy = -1;

        for(int i=m-1;i>=0;i--) {
            if(-pxd[i].first.second > maxy) {
                ban[pxd[i].second] = 1;
                maxy = -pxd[i].first.second;
            }
            if(pxu[i].first.second <= miny) {
                ban[pxu[i].second] = 1;
                miny = pxu[i].first.second;
            }
        }

        vector<pt> pts;
        forn(i,0,m) {
            if(!ban[i]) {
                pts.pb(pt(lol[i].first+1, lol[i].second));
            }
        }

        ban = vi(m,0);
        miny = 10000000;
        maxy = -1;
        forn(i,0,m) {
            if(pxu[i].first.second >= maxy) {
                ban[pxu[i].second] = 1;
                maxy = pxu[i].first.second;
            }
            if(-pxd[i].first.second < miny) {
                ban[pxd[i].second] = 1;
                miny = -pxd[i].first.second;
            }
        }
        miny = 10000000;
        maxy = -1;
        for(int i=m-1; i>=0; i--) {
            if(pxu[i].first.second >= maxy) {
                ban[pxu[i].second] = 1;
                maxy = pxu[i].first.second;
            }
        }

        forn(i,0,m) {
            if(!ban[i]) {
                pts.pb(pt(lol[i].first, lol[i].second+1));
            }
        }
//DONE
        ban = vi(m,0);
        miny = 10000000;
        maxy = -1;
        forn(i,0,m) {
            if(-pxd[i].first.second <= miny) {
                ban[pxd[i].second] = 1;
                miny = -pxd[i].first.second;
            }
            if(pxu[i].first.second > maxy) {
                ban[pxu[i].second] = 1;
                maxy = pxu[i].first.second;
            }
        }
        miny = 10000000;
        maxy = -1;
        for(int i=m-1; i>=0; i--) {
            if(-pxd[i].first.second <= miny) {
                ban[pxd[i].second] = 1;
                miny = -pxd[i].first.second;
            }
        }

        forn(i,0,m) {
            if(!ban[i]) {
                pts.pb(pt(lol[i].first, lol[i].second));
            }
        }

        ban = vi(m,0);
        miny = 10000000;
        maxy = -1;
        forn(i,0,m) {
            if(-pxd[i].first.second >= maxy) {
                ban[pxd[i].second] = 1;
                maxy = -pxd[i].first.second;
            }
        }
        miny = 10000000;
        maxy = -1;
        for(int i=m-1; i>=0; i--) {
            if(-pxd[i].first.second >= maxy) {
                ban[pxd[i].second] = 1;
                maxy = -pxd[i].first.second;
            }
            if(pxu[i].first.second < miny) {
                ban[pxu[i].second] = 1;
                miny = pxu[i].first.second;
            }

        }

        forn(i,0,m) {
            if(!ban[i]) {
                pts.pb(pt(lol[i].first+1, lol[i].second+1));
            }
        }

        convex_hull(pts);
//        forn(i,0,n) printf("%s\n", b[i].c_str());
        int ind = 0;
//        reverse(all(pts));
        forn(i,1,pts.size()) {
            if(pts[i].x < pts[ind].x || (pts[i].x == pts[ind].x && pts[i].y < pts[ind].y)) ind = i;
        }
        vector<pt> pts2;
        forn(i,ind, pts.size()) pts2.pb(pts[i]);
        forn(i,0,ind) pts2.pb(pts[i]);
        pts = std::move(pts2);
        pts2.clear();
//        cout<<pts.size()<<endl;
        printf("%d\n", (int)pts.size());
        for(auto u : pts) printf("%d %d\n", (int)u.x, (int)u.y);
//            cout<<u.y << ' ' << u.x << endl;
//        printf("\n");

    }

//    int minx = n;
//    int miny = n;
//    int maxx = -1;
//    int maxy = -1;
//    forn(i,0,n) forn(j,0,n) if(a[i][j] == '4') {
//        minx=min(minx, i);
//        miny=min(miny, j);
//        maxx=max(maxx, i);
//        maxy=max(maxy, j);
//    }
//    if(minx==n) {
//        cout<<"No";
//        return 0;
//    }
//    vs b(n, string(n,'0'));
//    forn(i,minx,maxx+1) forn(j,miny,maxy+1) {
//        b[i][j] = '4';
//    }
//    if(minx>0) {
//        forn(j,miny,maxy+1) {
//            b[minx-1][j] = '2';
//        }
//        if(miny>0) b[minx-1][miny-1] = '1';
//        if(maxy<n-1) b[minx-1][maxy+1] = '1';
//    }
//    if(maxx<n-1) {
//        forn(j,miny,maxy+1) {
//            b[maxx+1][j] = '2';
//        }
//        if(miny>0) b[maxx+1][miny-1] = '1';
//        if(maxy<n-1) b[maxx+1][maxy+1] = '1';
//    }
//    if(miny>0) {
//        forn(i,minx,maxx+1) {
//            b[i][miny-1] = '2';
//        }
//    }
//    if(maxy<n-1) {
//        forn(i,minx,maxx+1) {
//            b[i][maxy+1] = '2';
//        }
//    }
//    //    forn(i,0,n) cout<<b[i] <<endl;
//    forn(i,0,n) forn(j,0,n) {
//        if(a[i][j]!=b[i][j]) {
//            cout<<"No";
//            return 0;
//        }
//    }
//    cout<<"Yes";

}

#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <cstring>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <list>
#include <cassert>
#include <ctime>
#include <climits>
using namespace std;

#define PB push_back
#define MP make_pair
#define SZ(v) ((int)(v).size())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)
#define REPE(i,n) FORE(i,0,n)
#define FORSZ(i,a,v) FOR(i,a,SZ(v))
#define REPSZ(i,v) REP(i,SZ(v))
typedef long long ll;
typedef unsigned long long ull;
ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); }

const int MAXN=100000;
const int MAXQ=200000;
const int MAXP=MAXQ;
const int DX[]={0,+1,0,-1},DY[]={+1,0,-1,0};
typedef struct P { int x,y; P() {} P(int x,int y):x(x),y(y) {} } P;
bool operator<(const P &a,const P &b) { if(a.x!=b.x) return a.x<b.x; return a.y<b.y; }
const P operator-(const P &a,const P &b) { return P(a.x-b.x,a.y-b.y); }
const int operator^(const P &a,const P &b) { return a.x*b.y-a.y*b.x; }
bool ok(const P &a,const P &b,const P &c) { return ((b-a)^(c-a))<0; }

int n;

P q[MAXQ]; int nq;

P p[MAXP]; int np;

P h[2*MAXP]; int nh;

int mx[MAXN+1],mn[MAXN+1];

bool iszero(int x,int y) { if(y<0||y>=n||mn[y]>mx[y]) return true; return x<mn[y]||x>mx[y]; }
void solve() {
	REP(i,n) mx[i]=INT_MIN,mn[i]=INT_MAX;
	REP(i,nq) { int x=q[i].x,y=q[i].y; if(x<mn[y]) mn[y]=x; if(x>mx[y]) mx[y]=x; }
	np=0;
	REP(i,nq) {
		REP(k,4) {
			int kk=(k+1)%4;
			if(iszero(q[i].x+DX[k],q[i].y+DY[k])&&iszero(q[i].x+DX[kk],q[i].y+DY[kk])) p[np++]=P(q[i].x+k/2,q[i].y+((k==1||k==2)?1:0));
		}
	}
	//nh=np; REP(i,np) h[i]=p[i];
	sort(p,p+np);
	nh=0;
	REP(i,np) {
		while(nh>=2&&!ok(h[nh-2],h[nh-1],p[i])) --nh;
		h[nh++]=p[i];
	}
	int th=nh;
	for(int i=np-1;i>=0;--i) {
		while(nh-th>=1&&!ok(h[nh-2],h[nh-1],p[i])) --nh;
		h[nh++]=p[i];
	}
	--nh;
	printf("%d\n",nh);
	REP(i,nh) printf("%d %d\n",h[i].x,h[i].y);
}

void run() {
	while(scanf("%d%d",&n,&nq)==2) {
		if(n==0&&nq==0) break;
		REP(i,nq) scanf("%d%d",&q[i].x,&q[i].y),--q[i].x,--q[i].y;
		solve();
	}
}

int main() {
	run();
	return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define uint unsigned
#define pii pair<int,int>
#define pll pair<ll,ll>
#define IT iterator
#define PB push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define CLR(a,v) memset(a,v,sizeof(a));
#define CPY(a,b) memcpy(a,b,sizeof(a));
#define debug puts("wzpakking")
#define y1 ysghysgsygsh
using namespace std;
const int d1[4][2]={{0,1},{-1,0},{0,-1},{1,0}};
const int d2[4][2]={{1,1},{-1,1},{-1,-1},{1,-1}};
const int d3[4][2]={{0,0},{-1,0},{-1,-1},{0,-1}};
const int N=200005;
int n,m,top,ok[4];
map<int,int> mn,mx;
struct P{
	int x,y;
	P(){}
	P(int _x,int _y){
		x=_x; y=_y;
	}
	P operator +(const P &a)const{
		return P(x+a.x,y+a.y);
	}
	P operator -(const P &a)const{
		return P(x-a.x,y-a.y);
	}
	ll operator *(const P &a)const{
		return 1ll*x*a.y-1ll*y*a.x;
	}
	bool operator <(const P &a)const{
		return x==a.x?y<a.y:x<a.x;
	}
	bool operator ==(const P &a)const{
		return x==a.x&&y==a.y;
	}
	ll dis(){
		return 1ll*x*x+1ll*y*y;
	}
}a[N],q[N*4];
bool cmp(P x,P y){
	if (x*y) return x*y>0;
	return x.dis()<y.dis();
}
void Convex_hull(){
	sort(q+1,q+top+1);
	top=unique(q+1,q+top+1)-q-1;
	P bas=a[1];
	//For(i,1,top) cout<<q[i].x<<' '<<q[i].y<<endl;
	For(i,1,top) q[i]=q[i]-bas;
	sort(q+2,q+top+1,cmp);
	//For(i,1,top) cout<<q[i].x<<' '<<q[i].y<<endl;
	n=top; top=1;
	For(i,2,n){
		for (;top>=2&&(q[top]-q[top-1])*(q[i]-q[top])<=0;top--);
		q[++top]=q[i];
	}
	For(i,1,top)
		q[i]=q[i]+bas;
}
bool chk(int x,int y){
	if (mn.find(x)==mn.end()) return 0;
	return mn[x]<=y&&mx[x]>=y;
}
void solve(){
	top=0;
	scanf("%d%d",&n,&m);
	if (!(n+m)) exit(0);
	mn.clear(); mx.clear();
	For(i,1,m) scanf("%d%d",&a[i].x,&a[i].y);
	For(i,1,m) mn[a[i].x]=n+1,mx[a[i].x]=0;
	For(i,1,m){
		mn[a[i].x]=min(mn[a[i].x],a[i].y);
		mx[a[i].x]=max(mx[a[i].x],a[i].y);
	}
	For(i,1,m){
		ok[0]=ok[1]=ok[2]=ok[3]=1;
		For(j,0,3)
			if (!chk(a[i].x+d1[j][0],a[i].y+d1[j][1]))
				ok[j]=ok[(j+1)%4]=0;
		For(j,0,3)
			if (!chk(a[i].x+d2[j][0],a[i].y+d2[j][1]))
				ok[j]=0;
		For(j,0,3) if (ok[j])
			q[++top]=P(a[i].x+d3[j][0],a[i].y+d3[j][1]);
	}
	//cout<<top<<endl;
	Convex_hull();
	reverse(q+2,q+top+1);
	printf("%d\n",top);
	For(i,1,top) printf("%d %d\n",q[i].x,q[i].y);
}
int main(){
	for (;;) solve();
}

#include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>
#include <cstdio>
#include <set>

const int dx[] = {1, 0, -1, 0};
const int dy[] = {0, 1, 0, -1};

using namespace std;

#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)
#define TRACE(x) cout << #x << " = " << x << endl
#define _ << " _ " <<

typedef long long llint;

const int MAX = 100005;

typedef long long llint;
typedef pair<int, int> Pt;
#define x first
#define y second

int convexHull(Pt *a, int n) {
  rotate(a, min_element(a, a + n), a + n);

  auto ccw = [](const Pt &a, const Pt &b, const Pt &c) {
    llint ccw = a.x*llint(b.y-c.y) + b.x*llint(c.y-a.y) + c.x*llint(a.y-b.y);
    return ccw < 0 ? -1 : ccw > 0;
  };

  auto dist = [](const Pt &a, const Pt &b) {
    return llint(a.x-b.x)*(a.x-b.x) + llint(a.y-b.y)*(a.y-b.y);
  };

  sort(a + 1, a + n, [&a, &ccw, &dist](const Pt &x, const Pt &y) {
      int c = ccw(a[0], x, y);
      if (c) return c > 0;
      return dist(a[0], x) < dist(a[0], y);
    }
  );

  int m = 0;
  REP(i, n) {
    while (m >= 2 && ccw(a[m-2], a[m-1], a[i]) <= 0) m--;
    a[m++] = a[i];
  }

  return m;
}

int touch[MAX], cookie;
int row_lo[MAX];
int row_hi[MAX];
set< pair< int, int > > M, F;

bool is_four(int x, int y) {
  if (x < 0 || x > MAX) return false;
  if (touch[x] != cookie) return false;
  if (M.find({x, y}) != M.end()) return false;
  return y >= row_lo[x] && y <= row_hi[x];
}

int main(void) {
  int n, m;
  while (scanf("%d%d", &n, &m) == 2) {
    if (n == 0) break;
    ++cookie;

    M.clear();
    F.clear();

    REP(i, m) {
      int x, y;
      scanf("%d%d", &x, &y);
      M.insert({x, y});

      if (touch[x] != cookie) {
	touch[x] = cookie;
	row_lo[x] = y;
	row_hi[x] = y;
      }

      row_lo[x] = min(row_lo[x], y);
      row_hi[x] = max(row_hi[x], y);
    }

    for (auto c : M) {
      REP(d, 4) {
	int x = c.first + dx[d];
	int y = c.second + dy[d];

	if (is_four(x, y))
	  F.insert({x, y});
      }
    }

    for (auto f : F) M.insert(f);

    vector<Pt> v;
    for (auto c : M)
      if (M.find({c.first + 1, c.second}) != M.end() &&
	  M.find({c.first, c.second + 1}) != M.end() &&
	  M.find({c.first + 1, c.second + 1}) != M.end())
	v.push_back({c.first, c.second});

    int m = convexHull(&v[0], v.size());
    printf("%d\n", m);
    reverse(v.begin() + 1, v.begin() + m);
    REP(i, m) {
      printf("%d %d\n", v[i].x, v[i].y);
    }
  }

  return 0;
}

//be naame khodaa

#include <iostream>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <cstdio>
#include <algorithm>
#include <set>
#include <cassert>
#include <iomanip>
#include <cstring>
#define fi first
#define se second
#define rep(i, x, n) for (int i = x; i < n; i++)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(), (x).end()
#define SZ(x) ((int)(x).size())
#define For(i, a, b) for (int i = a; i < b; i++)
#define PB pop_back()
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> VI;

const int maxn = 200005;
inline pii operator - (const pii &p, const pii &q){return pii(p.fi - q.fi, p.se - q.se);}
int pmy[4*maxn], pMy[4*maxn], smy[4*maxn], sMy[4*maxn];
pii p[maxn];
int sz;
vector<pii> lo, up;
vector <pii> qx;
inline ll cross(const pii &p, const pii &q){
	return 1LL * p.fi * q.se - 1LL * p.se * q.fi;
}
inline int hull(vector<pii> &h){
	if(sz <= 1)	return sz;
	h.clear();
	h.pb(p[0]);
	For(i,1,sz){
		while(h.size() > 1 && cross(h.back() - h[(int)h.size()-2], p[i] - h.back()) <= 0)
			h.PB;
		h.pb(p[i]);
	}
	return h.size();
}
inline bool fnd(const pii &p, const vector<pii> &v){
	int i = lower_bound(all(v), p) - v.begin();
	return i < int(v.size()) && v[i] == p;
}
inline int convex_hull(){
	lo.clear();
	up.clear();
	if(sz <= 1)	return sz;
	sort(p, p + sz);
	sz = unique(p, p + sz) - p;
	int L = hull(lo);
	reverse(p, p + sz);
	int H = hull(up);
	sz = 0;
	For(i,0,int(lo.size()))
		p[sz ++] = lo[i];
	For(i,1,int(up.size())-1)
		p[sz ++] = up[i];
	return L + H - 2;
}

bool in(pii q){
	int it = lower_bound(qx.begin(), qx.end(), mp(q.first, 0)) - qx.begin();
	if (it == qx.size() || (pMy[it] <= q.se || pmy[it] >= q.se)) return false;
	it = lower_bound(qx.begin(), qx.end(), mp(q.first+1, 0)) - qx.begin() - 1;
	if (it < 0 || (sMy[it] <= q.se || smy[it] >= q.se)) return false;
	return true;
}

int main()
{
	ios::sync_with_stdio(false);
	int n, m;
	while (cin >> n >> m && n){

		map <pii, int> cnt;
		int y, x;
		qx.clear();
		for (int i = 0; i < m; i++){
			cin >> x >> y;
			x--, y--;
			cnt[mp(x, y)]++;
			cnt[mp(x+1, y)]++;
			cnt[mp(x, y+1)]++;
			cnt[mp(x+1, y+1)]++;
			qx.pb(mp(x, y));
			qx.pb(mp(x+1, y));
			qx.pb(mp(x, y+1));
			qx.pb(mp(x+1, y+1));
		}
		sort(qx.begin(), qx.end());
		qx.resize(unique(qx.begin(), qx.end()) - qx.begin());
		pmy[0] = n, pMy[0] = 0;
		for (int i = 1; i <= qx.size(); i++){
			pmy[i] = min(pmy[i-1], qx[i-1].se);
			pMy[i] = max(pMy[i-1], qx[i-1].se);
		}
		smy[qx.size()-1] = n, sMy[qx.size()-1] = 0;
		for (int i = int(qx.size())-2; i >= 0; i--){
			smy[i] = min(smy[i+1], qx[i+1].se);
			sMy[i] = max(sMy[i+1], qx[i+1].se);
		}

		sz = 0;
		for (auto q : cnt){
//			cout << q.fi.fi << ' ' << q.fi.se << ' ' << q.se << endl;
			if (q.second == 4 || (q.second == 3 && in(q.first))){
				p[sz++] = q.first;
	//			cout << q.fi.fi << ' ' << q.fi.se << endl;
			}
		}

		convex_hull();
		cout << sz << endl;
		int st = 0;
		for (int i = 0; i < sz; i++)
			if (p[i] < p[st])
				st = i;
		int j = st;
		do
		{
			cout << p[j].fi << ' ' << p[j].se << '\n';
			j--;
			if (j < 0) j = sz-1;
		} while (j != st);

	}
	return 0;
}

#include <bits/stdc++.h>
using namespace std;
#define N 810000
int n,T,cnt,top,m;
struct poi
{
	int x,y;
	poi(){}
	poi(int x,int y):x(x),y(y){}
	friend bool operator == (const poi &r1,const poi &r2)
	{return r1.x==r2.x&&r1.y==r2.y;}
	friend bool operator < (const poi &r1,const poi &r2)
	{
		if(r1.x==r2.x)return r1.y<r2.y;
		return r1.x<r2.x;
	}
	friend int operator ^ (const poi &r1,const poi &r2)
	{return r1.x*r2.y-r2.x*r1.y;};
	friend poi operator - (const poi &r1,const poi &r2)
	{return poi(r1.x-r2.x,r1.y-r2.y);};
}a[N],st[N],b[N];
int xl[N],xr[N],yl[N],yr[N];
int onleft(poi p1,poi p2,poi p3)
{
	return ((p1-p2)^(p3-p2))>=0;
}
int check(int x,int y)
{
	for(int i=0;i<=1;i++)
		for(int j=0;j<=1;j++)
			if(xl[y+j]>x+i||xr[y+j]<x+i||yl[x+i]>y+j||yr[x+i]<y+j)
				return 0;
	return 1;
}
int main()
{
	//freopen("tt.in","r",stdin);
	memset(xl,0x3f,sizeof(xl));
	memset(yl,0x3f,sizeof(yl));
	while(scanf("%d%d",&n,&m)!=EOF&&n)
	{
		top=0;cnt=0;
		for(int i=1,x,y;i<=m;i++)
		{
			scanf("%d%d",&x,&y);b[i]=poi(x,y);
			xl[y]=min(xl[y],x);xr[y]=max(xr[y],x);
			yl[x]=min(yl[x],y);yr[x]=max(yr[x],y);
		}
		for(int i=1;i<=m;i++)
			for(int j=0;j<=1;j++)
				for(int k=0;k<=1;k++)
					if(check(b[i].x-j,b[i].y-k))
						a[++cnt]=poi(b[i].x-j,b[i].y-k);

		sort(a+1,a+1+cnt);
		cnt=unique(a+1,a+1+cnt)-a-1;
		for(int i=1;i<=cnt;i++)
		{
			while(top>=2&&onleft(st[top],st[top-1],a[i]))
				top--;
			st[++top]=a[i];
		}
		int t=top;
		for(int i=cnt-1;i>=1;i--)
		{
			while(top>t&&onleft(st[top],st[top-1],a[i]))
				top--;
			st[++top]=a[i];
		}
		printf("%d\n",top-1);
		for(int i=1;i<top;i++)
			printf("%d %d\n",st[i].x,st[i].y);
		for(int i=1,x,y;i<=m;i++)
		{
			x=b[i].x;y=b[i].y;
			xl[y]=1<<30;xr[y]=0;
			yl[x]=1<<30;yr[x]=0;
		}
	}
	return 0;
}
//hellobig_tq

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

ll cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x+0LL)*(p2.y-p0.y)-(p1.y-p0.y+0LL)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    ll tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;
vector<int> xs[100010];

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
	memset(xs,0,sizeof(xs));
}

int main(){
	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
			xs[y[i]].push_back(x[i]);
		}

		for(int i=0;i<=n+1;i++){
			sort(xs[i].begin(),xs[i].end());
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				bool f = (xs[y[i]][0] == x[i] || xs[y[i]][xs[y[i]].size()-1] == x[i]);
				if( f && mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);
					list[sz++] = point(newx,newy);

				}
			}
		}
		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }
	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

ll cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x+0LL)*(p2.y-p0.y)-(p1.y-p0.y+0LL)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    ll tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;
vector<int> ys[100010];
vector<int> xs[100010];

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
	memset(xs,0,sizeof(xs));
	memset(ys,0,sizeof(ys));
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
			xs[y[i]].push_back(x[i]);
			ys[x[i]].push_back(y[i]);
		}

		for(int i=0;i<=n+1;i++){
			sort(xs[i].begin(),xs[i].end());
			sort(ys[i].begin(),ys[i].end());
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				bool f1 = (ys[x[i]][0] == y[i] || ys[x[i]][ys[x[i]].size()-1] == y[i]);
				bool f2 = (xs[y[i]][0] == x[i] || xs[y[i]][xs[y[i]].size()-1] == x[i]);
				if( (f1 || f2) && mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					/*if(n==50000){
						if(newx == 12 && newy== 49894){
							cout<<"YES"<<endl;
						}
					}*/

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					/*if(dist2(cx,cy,newx+0.5,newy+0.5) < dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}*/

					list[sz++] = point(newx,newy);

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include <bits/stdc++.h>
using namespace std;

#ifdef LOCAL
    #define eprintf(...) fprintf(stderr, __VA_ARGS__)
#else
    #define eprintf(...) 0
#endif

typedef long long ll;

struct Point
{
    ll x, y;
    Point () : x(), y() {}
    Point (int _x, int _y) : x(_x), y(_y) {}
    void read()
    {
        scanf("%lld%lld", &x, &y);
    }
    Point operator- (const Point& p) const
    {
        return Point(x - p.x, y - p.y);
    }
    Point operator+ (const Point& p) const
    {
        return Point(x + p.x, y + p.y);
    }
    ll operator* (const Point& p) const
    {
        return x * p.y - y * p.x;
    }
    void print()
    {
        printf("%lld %lld\n", x, y);
    }
    ll len2() const
    {
        return x * x + y * y;
    }
};

const int N = 1e5 + 10;
const int M = 2e5 + 10;
const ll INF = 1e9 + 10;
int n, m;
int min_x[N], max_x[N];
Point cells[M];
Point delta[] = { Point(0, 0), Point(0, 1), Point(1, 0), Point(1, 1) };
vector<Point> pts, hull;

bool in_seg(int l, int r, int x)
{
    return l <= x && x <= r;
}

void add_vertex(Point p)
{
    if (in_seg(min_x[p.y - 1], max_x[p.y - 1], p.x - 1) &&
            in_seg(min_x[p.y], max_x[p.y], p.x - 1) &&
            in_seg(min_x[p.y - 1], max_x[p.y - 1], p.x) &&
            in_seg(min_x[p.y], max_x[p.y], p.x))
        pts.push_back(p);
}

bool solve()
{
    scanf("%d%d", &n, &m);
    if (n == 0)
        return false;

    for(int i = 0; i < m; ++i)
    {
        cells[i].read();
        cells[i] = cells[i] - Point(1, 1);
        min_x[cells[i].y] = INF;
        max_x[cells[i].y] = -INF;
        min_x[cells[i].y - 1] = INF;
        max_x[cells[i].y - 1] = -INF;
        min_x[cells[i].y + 1] = INF;
        max_x[cells[i].y + 1] = -INF;
    }
    for(int i = 0; i < m; ++i)
    {
        int y = cells[i].y;
        min_x[y] = min(min_x[y], (int)cells[i].x);
        max_x[y] = max(max_x[y], (int)cells[i].x);
    }

    pts.clear();
    hull.clear();

    for(int i = 0; i < m; ++i)
        for(auto& d : delta)
            add_vertex(cells[i] + d);

    auto O = pts[0];
    for(auto& p : pts)
        p = p - O;
    sort(pts.begin() + 1, pts.end(), [] (const Point& f, const Point& s) { return f * s == 0 ? f.len2() < s.len2() : f * s > 0; });
    pts.emplace_back();
    for(auto p : pts)
    {
        for(; hull.size() > 1 && (hull.back() - hull[hull.size() - 2]) * (p - hull[hull.size() - 2]) <= 0; hull.pop_back());
        hull.push_back(p);
    }
    hull.pop_back();
    reverse(hull.begin() + 1, hull.end());
    printf("%d\n", (int)hull.size());
    for(auto p : hull)
        (O + p).print();

    return true;
}

int main()
{
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
#endif

    while(solve());

    eprintf("time = %.3lf\n", (double)clock() / CLOCKS_PER_SEC);
}

#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cstdio>
#include <queue>
#include <set>
#include <map>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#include <numeric>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, n) for (int i = (int)(n) - 1; i >= 0; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

struct TPoint {
    i64 x, y;

    TPoint(i64 x, i64 y)
        : x(x)
        , y(y)
    {
    }

    TPoint operator+(const TPoint &p) const {
        return TPoint(x + p.x, y + p.y);
    }

    TPoint operator-(const TPoint &p) const {
        return TPoint(x - p.x, y - p.y);
    }

    i64 operator%(const TPoint &p) const {
        return x * p.y - y * p.x;
    }

    i64 operator*(const TPoint &p) const {
        return x * p.x + y * p.y;
    }

    i64 operator~() const {
        return *this * *this;
    }

    bool operator<(const TPoint &p) const {
        return mp(x, y) < mp(p.x, p.y);
    }
};

bool cmp(const TPoint &a, const TPoint &b) {
    if (a % b) return a % b > 0;
    return ~a < ~b;
}

const int maxn = 210000;
int miny[maxn], maxy[maxn];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "rt", stdin);
#endif

    int n, m;
    while (1) {
        cin >> n >> m;
        if (!n) break;
        forn(i, n + 10) miny[i] = 1e9, maxy[i] = -1e9;
        forn(i, m) {
            int x, y;
            cin >> x >> y;
//            --x; --y;
            uin(miny[x], y);
            uax(maxy[x], y);
        }
        vector<TPoint> p;
        forn(i, n + 2) {
            if (i && miny[i] < miny[i - 1]) p.pb(TPoint(i, miny[i]));
            if (miny[i] < miny[i + 1]) p.pb(TPoint(i - 1, miny[i]));
            if (i && maxy[i] > maxy[i - 1]) p.pb(TPoint(i, maxy[i] - 1));
            if (maxy[i] > maxy[i + 1]) p.pb(TPoint(i - 1, maxy[i] - 1));
        }
        TPoint O = *min_element(all(p));
        for (auto &w: p) w = w - O;
        sort(all(p), cmp);
        vector<TPoint> st;
        for (auto w: p) {
            while (st.size() > 1) {
                TPoint prv = st.back(), pprv = st[st.size() - 2];
                if ((w - pprv) % (prv - pprv) >= 0) st.pop_back();
                else break;
            }
            st.pb(w);
        }
        reverse(all(st));
        forn(i, st.size()) {
            st[i] = st[i] + O;
//            ++st[i].x; ++st[i].y;
//            swap(st[i].x, st[i].y);
//            st[i].x += 1;
//            st[i].y = n - st[i].y - 1;
        }
        int j = min_element(all(st)) - st.begin();
        cout << st.size() << '\n';
        //for (auto w: st) {
        forn(i, st.size()) {
            TPoint w = st[(i + j) % st.size()];
            cout << w.x << ' ' << w.y << '\n';
        }
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#include <cstdio>
#include <stdlib.h>
#include <stack>
#include <numeric>
#include <bitset>
#include <cctype>
#include <list>
#include <assert.h>
#include <random>
#include <unordered_map>
#include <ctime>
typedef  long long ll;
using namespace std;
#define INF 2147483647
#define infL (1LL<<60)
#define inf (1<<30)
#define inf9 (1000000000)
#define MOD 1000000007
#define EPS 1e-18
#define Gr 9.8
#define PI acos(-1)
#define REP(i,n) for(int (i)=0;(i)<(int)(n);(i)++)
#define REQ(i,n) for(int (i)=1;(i)<=(int)(n);(i)++)
#define lch (rt<<1)
#define rch (rt<<1|1)
#define readmp(n) for(int i=0,u,v;i<n;i++) {scanf("%d%d",&u,&v); mp[u].push_back(v); mp[v].push_back(u);}
typedef pair<int, int> pii;
typedef long double ld;
typedef unsigned int uint;
#define MAX 300105
bool debug = 0;
int n,m,k;
int dx[4] = {0,1,0,-1}, dy[4] = {1,0,-1,0};
string direc="RDLU";
ll ln, lk, lm;
void etp(bool f = 0) {
    puts(f ?"Yes" : "No");
    exit(0);
}
void addmod(int &x, int y, int mod = MOD) {
    x+=y; if (x>=mod) x-=mod;
}
void et() {
    puts("-1"); exit(0);
}
 ll fastPow(ll x, ll y, int mod=MOD) {
     ll ans = 1;
     while(y>0) {
         if(y&1) ans = (x * ans)%mod;
         x = x*x%mod;
         y>>=1;
     }
     return ans;
 }

typedef ll ValType;
struct Point {
    ValType x, y;
    Point() { }
    Point(ValType x, ValType y) : x(x), y(y) { }

    Point operator+(const Point& o) const { return Point(x + o.x, y + o.y); }
    Point operator-(const Point& o) const { return Point(x - o.x, y - o.y); }
    bool operator<(const Point& o) const { return x < o.x || (x == o.x  && y < o.y); }

    ValType cross(Point b) const {return x*b.y- b.x*y;}
    void readin() {
        scanf("%lld%lld", &x, &y);
    }
    void pp() {
        printf("%lld %lld\n",x,y);
    }
}p[MAX];

vector<Point> convex(vector<Point> &vp) {
    sort(vp.begin(), vp.end());
    int N = vp.size();
    vector<Point> ans1,ans2;
    REP(i,N) {
        while(ans1.size()>1) {
            Point o=ans1[ans1.size()-2], a= ans1.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans1.pop_back();
            } else break;
        }
        ans1.push_back(vp[i]);
    }
    for(int i=N-1;i>=0;i--) {
        while(ans2.size()>1) {
            Point o=ans2[ans2.size()-2], a= ans2.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans2.pop_back();
            } else break;
        }
        ans2.push_back(vp[i]);
    }
    for(int i=1;i<ans2.size()-1;i++) ans1.push_back(ans2[i]);
    return ans1;
}

ll xl[MAX],xr[MAX],yl[MAX],yr[MAX];
bool isIn(ll x, ll y) {
    for(int i=0;i<=1;i++)
        for(int j=0;j<=1;j++)
            if(xl[y+j]>x+i||xr[y+j]<x+i||yl[x+i]>y+j||yr[x+i]<y+j)
                return 0;
    return 1;
}
void fmain() {
    REP(i,MAX) {
        xl[i]=infL; yl[i]=infL;
    }
    while (~scanf("%d%d", &n,&m)) {
        if (n==0) break;
        REQ(i,m) p[i].readin();
        REQ(i,m) {
            xl[p[i].y]=min(xl[p[i].y], p[i].x);
            xr[p[i].y]=max(xr[p[i].y], p[i].x);
            yl[p[i].x] = min(yl[p[i].x], p[i].y);
            yr[p[i].x] = max(yr[p[i].x], p[i].y);
        }
        vector<Point> vp;
        REQ(i,m) {
            ll x=p[i].x,y=p[i].y;
            if (isIn(x, y)) vp.push_back(Point(x,y));
          //   if (isIn(x-1, y)) vp.push_back(Point(x-1,y));
          //   if (isIn(x, y-1)) vp.push_back(Point(x,y-1));
          //   if (isIn(x-1, y-1)) vp.push_back(Point(x-1,y-1));
//            int tio=0;
        }
        vector<Point> ans = convex(vp);
        printf("%d\n", ans.size());
        ans[0].pp();
        for(int i=ans.size()-1;i>=1;i--) ans[i].pp();

        REQ(i,m) {
            xl[p[i].y]=infL;
            xr[p[i].y]=0;
            yl[p[i].x] = infL;
            yr[p[i].x] = 0;
        }
    }
}
int main() {
    fmain();
    return 0;
}

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#include <cstdio>
#include <stdlib.h>
#include <stack>
#include <numeric>
#include <bitset>
#include <cctype>
#include <list>
#include <assert.h>
#include <random>
#include <unordered_map>
#include <ctime>
typedef  long long ll;
using namespace std;
#define INF 2147483647
#define infL (1LL<<60)
#define inf (1<<30)
#define inf9 (1000000000)
#define MOD 1000000007
#define EPS 1e-18
#define Gr 9.8
#define PI acos(-1)
#define REP(i,n) for(int (i)=0;(i)<(int)(n);(i)++)
#define REQ(i,n) for(int (i)=1;(i)<=(int)(n);(i)++)
#define lch (rt<<1)
#define rch (rt<<1|1)
#define readmp(n) for(int i=0,u,v;i<n;i++) {scanf("%d%d",&u,&v); mp[u].push_back(v); mp[v].push_back(u);}
typedef pair<int, int> pii;
typedef long double ld;
typedef unsigned int uint;
#define MAX 200105
bool debug = 0;
int n,m,k;
int dx[4] = {0,1,0,-1}, dy[4] = {1,0,-1,0};
string direc="RDLU";
ll ln, lk, lm;
void etp(bool f = 0) {
    puts(f ?"Yes" : "No");
    exit(0);
}
void addmod(int &x, int y, int mod = MOD) {
    x+=y; if (x>=mod) x-=mod;
}
void et() {
    puts("-1"); exit(0);
}
 ll fastPow(ll x, ll y, int mod=MOD) {
     ll ans = 1;
     while(y>0) {
         if(y&1) ans = (x * ans)%mod;
         x = x*x%mod;
         y>>=1;
     }
     return ans;
 }

typedef ll ValType;
struct Point {
    ValType x, y;
    Point() { }
    Point(ValType x, ValType y) : x(x), y(y) { }
    ld abs() const { return hypot(x, y); }
    ld arg() const { return atan2(y, x); }
    Point operator*(double o) const { return Point(x * o, y * o); }
    Point operator+(const Point& o) const { return Point(x + o.x, y + o.y); }
    Point operator-(const Point& o) const { return Point(x - o.x, y - o.y); }
    bool operator<(const Point& o) const { return x < o.x - EPS || (x < o.x + EPS && y < o.y - EPS); }
    Point scale(double o) const { return *this * (o / abs()); }
    Point rotY() const { return Point(-y, x); }
    Point rotX() const { return Point(y, -x); }
    ValType cross(Point b) const {return x*b.y- b.x*y;}
    ValType dot(Point b) const {return x*b.x + y*b.y;}
    ld disToSeg(Point &a, Point &b) {
        return fabs(((*this)-a).cross(b-a) / (b-a).abs());
    }
    void readin() {
        scanf("%lld%lld", &x, &y);
    }
    void pp() {
        printf("%lld %lld\n",x,y);
    }
}p[MAX];

vector<Point> convex(vector<Point> &vp) {
    sort(vp.begin(), vp.end());
    vector<Point> ans1,ans2;
    REP(i,vp.size()) {
        while(ans1.size()>1) {
            Point o=ans1[ans1.size()-2], a= ans1.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans1.pop_back();
            } else break;
        }
        ans1.push_back(vp[i]);
    }
    for(int i=vp.size()-1;i>=0;i--) {
        while(ans2.size()>1) {
            Point o=ans2[ans2.size()-2], a= ans2.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans2.pop_back();
            } else break;
        }
        ans2.push_back(vp[i]);
    }
    for(int i=1;i<ans2.size()-1;i++) ans1.push_back(ans2[i]);
    return ans1;
}

ll xl[MAX],xr[MAX],yl[MAX],yr[MAX];
bool isIn(ll x, ll y) {
    for(int i=0;i<=1;i++)
        for(int j=0;j<=1;j++)
            if(xl[y+j]>x+i||xr[y+j]<x+i||yl[x+i]>y+j||yr[x+i]<y+j)
                return 0;
    return 1;
}
void fmain() {
    REP(i,MAX) {
        xl[i]=infL; yl[i]=infL;
    }
    while (~scanf("%d%d", &n,&m)) {
        if (n==0) break;
        REQ(i,m) p[i].readin();
        REQ(i,m) {
            xl[p[i].y]=min(xl[p[i].y], p[i].x);
            xr[p[i].y]=max(xr[p[i].y], p[i].x);
            yl[p[i].x] = min(yl[p[i].x], p[i].y);
            yr[p[i].x] = max(yr[p[i].x], p[i].y);
        }
        vector<Point> vp;
        REQ(i,m) {
            ll x=p[i].x,y=p[i].y;
            if (isIn(x, y)) vp.push_back(Point(x,y));
            if (isIn(x-1, y)) vp.push_back(Point(x-1,y));
            if (isIn(x, y-1)) vp.push_back(Point(x,y-1));
            if (isIn(x-1, y-1)) vp.push_back(Point(x-1,y-1));
//            int tio=0;
        }
        vector<Point> ans = convex(vp);
        printf("%d\n", ans.size());
        ans[0].pp();
        for(int i=ans.size()-1;i>=1;i--) ans[i].pp();

        REQ(i,m) {
            xl[p[i].y]=infL;
            xr[p[i].y]=0;
            yl[p[i].x] = infL;
            yr[p[i].x] = 0;
        }
    }
}
int main() {
    fmain();
    return 0;
}

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <set>
#include <map>
#include <cstdio>
#include <stdlib.h>
#include <stack>
#include <numeric>
#include <bitset>
#include <cctype>
#include <list>
#include <assert.h>
#include <random>
#include <unordered_map>
#include <ctime>
typedef  long long ll;
using namespace std;
#define INF 2147483647
#define infL (1LL<<60)
#define inf (1<<30)
#define inf9 (1000000000)
#define MOD 1000000007
#define EPS 1e-18
#define Gr 9.8
#define PI acos(-1)
#define REP(i,n) for(int (i)=0;(i)<(int)(n);(i)++)
#define REQ(i,n) for(int (i)=1;(i)<=(int)(n);(i)++)
#define lch (rt<<1)
#define rch (rt<<1|1)
#define readmp(n) for(int i=0,u,v;i<n;i++) {scanf("%d%d",&u,&v); mp[u].push_back(v); mp[v].push_back(u);}
typedef pair<int, int> pii;
typedef long double ld;
typedef unsigned int uint;
#define MAX 200105
bool debug = 0;
int n,m,k;
int dx[4] = {0,1,0,-1}, dy[4] = {1,0,-1,0};
string direc="RDLU";
ll ln, lk, lm;
void etp(bool f = 0) {
    puts(f ?"Yes" : "No");
    exit(0);
}
void addmod(int &x, int y, int mod = MOD) {
    x+=y; if (x>=mod) x-=mod;
}
void et() {
    puts("-1"); exit(0);
}
 ll fastPow(ll x, ll y, int mod=MOD) {
     ll ans = 1;
     while(y>0) {
         if(y&1) ans = (x * ans)%mod;
         x = x*x%mod;
         y>>=1;
     }
     return ans;
 }

typedef ll ValType;
struct Point {
    ValType x, y;
    Point() { }
    Point(ValType x, ValType y) : x(x), y(y) { }
    ld abs() const { return hypot(x, y); }
    ld arg() const { return atan2(y, x); }
    Point operator*(double o) const { return Point(x * o, y * o); }
    Point operator+(const Point& o) const { return Point(x + o.x, y + o.y); }
    Point operator-(const Point& o) const { return Point(x - o.x, y - o.y); }
    bool operator<(const Point& o) const { return x < o.x - EPS || (x < o.x + EPS && y < o.y - EPS); }
    Point scale(double o) const { return *this * (o / abs()); }
    Point rotY() const { return Point(-y, x); }
    Point rotX() const { return Point(y, -x); }
    ValType cross(Point b) const {return x*b.y- b.x*y;}
    ValType dot(Point b) const {return x*b.x + y*b.y;}
    ld disToSeg(Point &a, Point &b) {
        return fabs(((*this)-a).cross(b-a) / (b-a).abs());
    }
    void readin() {
        scanf("%lld%lld", &x, &y);
    }
    void pp() {
        printf("%lld %lld\n",x,y);
    }
}p[MAX];

vector<Point> convex(vector<Point> &vp) {
    sort(vp.begin(), vp.end());
    vector<Point> ans1,ans2;
    REP(i,vp.size()) {
        while(ans1.size()>1) {
            Point o=ans1[ans1.size()-2], a= ans1.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans1.pop_back();
            } else break;
        }
        ans1.push_back(vp[i]);
    }
    for(int i=vp.size()-1;i>=0;i--) {
        while(ans2.size()>1) {
            Point o=ans2[ans2.size()-2], a= ans2.back();
            if ((a-o).cross(vp[i]-o) <= 0) {
                ans2.pop_back();
            } else break;
        }
        ans2.push_back(vp[i]);
    }
    for(int i=1;i<ans2.size()-1;i++) ans1.push_back(ans2[i]);
    return ans1;
}

ll xl[MAX],xr[MAX],yl[MAX],yr[MAX];
bool isIn(ll x, ll y) {
    for(int i=0;i<=1;i++)
        for(int j=0;j<=1;j++)
            if(xl[y+j]>x+i||xr[y+j]<x+i||yl[x+i]>y+j||yr[x+i]<y+j)
                return 0;
    return 1;
}
void fmain() {
    REP(i,MAX) {
        xl[i]=infL; yl[i]=infL;
    }
    while (~scanf("%d%d", &n,&m)) {
        if (n==0) break;
        REQ(i,m) p[i].readin();
        REQ(i,m) {
            xl[p[i].y]=min(xl[p[i].y], p[i].x);
            xr[p[i].y]=max(xr[p[i].y], p[i].x);
            yl[p[i].x] = min(yl[p[i].x], p[i].y);
            yr[p[i].x] = max(yr[p[i].x], p[i].y);
        }
        vector<Point> vp;
        REQ(i,m) {
            ll x=p[i].x,y=p[i].y;
            if (isIn(x, y)) vp.push_back(Point(x,y));
            if (isIn(x-1, y)) vp.push_back(Point(x-1,y));
            if (isIn(x, y-1)) vp.push_back(Point(x,y-1));
            if (isIn(x-1, y-1)) vp.push_back(Point(x-1,y-1));
//            int tio=0;
        }
        sort(vp.begin(), vp.end());
        vector<Point> ans = convex(vp);
        printf("%d\n", ans.size());
        ans[0].pp();
        for(int i=ans.size()-1;i>=1;i--) ans[i].pp();

        REQ(i,m) {
            xl[p[i].y]=infL;
            xr[p[i].y]=0;
            yl[p[i].x] = infL;
            yr[p[i].x] = 0;
        }
    }
}
int main() {
    fmain();
    return 0;
}

//#pragma comment(linker, "/STACK:20000000")
#include <vector>
#include <list>
#include <map>
#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 <cstring>
#include <cassert>
#include <cstdlib>
#include <ctime>

using namespace std;
typedef long long int64;
#ifdef HOME
	#define E(c) cerr<<#c
	#define Eo(x) cerr<<#x<<" = "<<(x)<<endl
	#define Ef(...) fprintf(stderr, __VA_ARGS__)
#else
	#define E(c) ((void)0)
	#define Eo(x) ((void)0)
	#define Ef(...) ((void)0)
#endif

struct Point {
	int x, y;

	Point() : x(0), y(0) {}
	Point(int x, int y) : x(x), y(y) {}

	Point operator- (Point b) const {
		return Point(x - b.x, y - b.y);
	}
	Point operator+ (Point b) const {
		return Point(x + b.x, y + b.y);
	}
	bool operator< (Point b) const {
		return make_pair(x, y) < make_pair(b.x, b.y);
	}
};

int cross (Point a, Point b) {
	return a.x * b.y - a.y * b.x;
}
int dot (Point a, Point b) {
	return a.x * b.x + a.y * b.y;
}

int n, m;
map<int, set<int>> cells;

char buff[1<<20];
int main() {
#ifdef HOME
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	while (1) {
		scanf("%d%d", &n, &m);
		if (n == 0) break;

		cells.clear();
		for (int i = 0; i < m; i++) {
			int x, y;
			scanf("%d%d", &x, &y);
			x--; y--;
			cells[x].insert(y);
		}

		set<Point> dots;
		for (auto it = cells.begin(); it != cells.end(); it++) {
			int x = it->first;
			const auto &ySet = it->second;
			int last = *ySet.begin();
			for (auto jt = ySet.begin(); jt != ySet.end(); jt++) {
				int curr = *jt;
				if (curr - last > 1) {
					dots.insert(Point(x, last+1));
					dots.insert(Point(x, curr));
					dots.insert(Point(x+1, last+1));
					dots.insert(Point(x+1, curr));
				}
				if (curr - last == 1) {
					if (cells.find(x+1) != cells.end()) {
						const auto &nSet = cells[x+1];
						if (nSet.find(last) != nSet.end() && nSet.find(curr) != nSet.end())
							dots.insert(Point(x+1, curr));
					}
				}
				last = curr;
			}
		}

		vector<Point> pts(dots.begin(), dots.end());
		Ef("%d\n", pts.size());
		for (int i = 0; i < pts.size(); i++)
			Ef("%d %d\n", pts[i].x, pts[i].y);

		Point ctr = pts[0];
		std::sort(pts.begin() + 1, pts.end(), [&](Point a, Point b) -> bool {
			int area = cross(a - ctr, b - ctr);
			if (area != 0)
				return area < 0;
			return dot(a - ctr, a - ctr) < dot(b - ctr, b - ctr);
		});

		vector<Point> hull;
		hull.push_back(pts[0]);
		hull.push_back(pts[1]);
        for (int i = 2; i < pts.size(); i++) {
			Point p = pts[i];
			while (hull.size() >= 2 && cross(hull.rbegin()[0] - hull.rbegin()[1], p - hull.rbegin()[0]) >= 0)
				hull.pop_back();
			hull.push_back(p);
        }

        printf("%d\n", hull.size());
        for (int i = 0; i < hull.size(); i++)
        	printf("%d %d\n", hull[i].x, hull[i].y);

	}
	return 0;
}

//#pragma comment(linker, "/STACK:20000000")
#include <vector>
#include <list>
#include <map>
#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 <cstring>
#include <cassert>
#include <cstdlib>
#include <ctime>

using namespace std;
typedef long long int64;
#ifdef HOME
	#define E(c) cerr<<#c
	#define Eo(x) cerr<<#x<<" = "<<(x)<<endl
	#define Ef(...) fprintf(stderr, __VA_ARGS__)
#else
	#define E(c) ((void)0)
	#define Eo(x) ((void)0)
	#define Ef(...) ((void)0)
#endif

struct Point {
	int x, y;

	Point() : x(0), y(0) {}
	Point(int x, int y) : x(x), y(y) {}

	Point operator- (Point b) const {
		return Point(x - b.x, y - b.y);
	}
	Point operator+ (Point b) const {
		return Point(x + b.x, y + b.y);
	}
	bool operator< (Point b) const {
		return make_pair(x, y) < make_pair(b.x, b.y);
	}
};

int64 cross (Point a, Point b) {
	return int64(a.x) * b.y - int64(a.y) * b.x;
}
int64 dot (Point a, Point b) {
	return int64(a.x) * b.x + int64(a.y) * b.y;
}

int n, m;
map<int, set<int>> cells;

char buff[1<<20];
int main() {
#ifdef HOME
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	while (1) {
		scanf("%d%d", &n, &m);
		if (n == 0) break;

		cells.clear();
		for (int i = 0; i < m; i++) {
			int x, y;
			scanf("%d%d", &x, &y);
			x--; y--;
			cells[x].insert(y);
		}

		set<Point> dots;
		for (auto it = cells.begin(); it != cells.end(); it++) {
			int x = it->first;
			const auto &ySet = it->second;
			int last = *ySet.begin();
			for (auto jt = ySet.begin(); jt != ySet.end(); jt++) {
				int curr = *jt;
				if (curr - last > 1) {
					dots.insert(Point(x, last+1));
					dots.insert(Point(x, curr));
					dots.insert(Point(x+1, last+1));
					dots.insert(Point(x+1, curr));
				}
				if (curr - last == 1) {
					if (cells.find(x+1) != cells.end()) {
						const auto &nSet = cells[x+1];
						if (nSet.find(last) != nSet.end() && nSet.find(curr) != nSet.end())
							dots.insert(Point(x+1, curr));
					}
				}
				last = curr;
			}
		}

		vector<Point> pts(dots.begin(), dots.end());
		Ef("%d\n", pts.size());
		for (int i = 0; i < pts.size(); i++)
			Ef("%d %d\n", pts[i].x, pts[i].y);

		Point ctr = pts[0];
		std::sort(pts.begin() + 1, pts.end(), [&](Point a, Point b) -> bool {
			int64 area = cross(a - ctr, b - ctr);
			if (area != 0)
				return area < 0;
			return dot(a - ctr, a - ctr) < dot(b - ctr, b - ctr);
		});

		vector<Point> hull;
		hull.push_back(pts[0]);
		hull.push_back(pts[1]);
        for (int i = 2; i < pts.size(); i++) {
			Point p = pts[i];
			while (hull.size() >= 2 && cross(hull.rbegin()[0] - hull.rbegin()[1], p - hull.rbegin()[0]) >= 0)
				hull.pop_back();
			hull.push_back(p);
        }

        printf("%d\n", hull.size());
        for (int i = 0; i < hull.size(); i++)
        	printf("%d %d\n", hull[i].x, hull[i].y);

	}
	return 0;
}

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

#define Pi 3.1415926535897932385
#define PRINTPOINT(_p_) cout<<"("<<_p_.x<<","<<_p_.y<<")"

struct Point{
	double x; double y;
	Point(){x=y=0;}
	Point(double _x, double _y){x=_x;y=_y;}
	friend Point operator +(const Point &a, const Point &b){return Point(b.x+a.x,b.y+a.y);}
	friend Point operator -(const Point &a, const Point &b){return Point(a.x-b.x,a.y-b.y);}
	friend Point operator *(const Point &a, double p){return Point(a.x*p, a.y*p);}
	friend Point operator /(const Point &a, double p){return Point(a.x/p, a.y/p);}
	friend double operator *(const Point &p, const Point &a){return (p.x*a.x+p.y*a.y);}
	friend double operator /(const Point &p, const Point &a){return (p.x*a.y-p.y*a.x);}
	friend bool operator <(const Point &a, const Point &b){
		if (a.x<b.x) return true;
		if (a.x>b.x) return false;
		if (a.y<b.y) return true;
		return false;
	}
	friend bool operator >(const Point &a, const Point &b){
		if (a.x>b.x) return true;
		if (a.x<b.x) return false;
		if (a.y>b.y) return true;
		return false;
	}
	friend bool operator ==(const Point &a, const Point &b){
		return (a.x==b.x && a.y==b.y);
	}
	friend bool operator !=(const Point &a, const Point &b){
		return (a.x!=b.x || a.y!=b.y);
	}
	double slope(){return y/x;}
	double measure(){return sqrt(x*x+y*y);}
	double angle(){
		double an=atan2(y,x);
		if (an<0) an+=2*Pi;
		return an;
	}
	Point shrink(){
		return Point(1,y/x);
	}
};

struct Hashdata{
	Point p;
	int t;
	Hashdata(){p=Point(); t=0;}
	Hashdata(Point _p, int _t){p=_p; t=_t;}
};

#define N 100010
#define M 200010
#define H 3000007
#define INF (double)1000000000000
#define _(_x_,_y_) Point(_x_,_y_)
#define eps ((double)1e-10)

int n,m,hc,cc;
int leftone[N], rightone[N];
Point peter[M], charles[4*M], harry[M];
bool repeat[4*M];
Point barycenter;
double anne[M];
int hull[M], q[M], nowtest;
Hashdata hash[H], corner[H];

int point_hash(Point a){
	int x=a.x, y=a.y;
	return (x*10007+y)%H;
}

void add_hash(Point x, bool empty){
	int h=point_hash(x);
	while (hash[h].t==nowtest || hash[h].t==nowtest+1) h=(h+1)%H;
	//cout<<"addhash"; PRINTPOINT(x)<<" "<<(nowtest+empty)<<endl;
	hash[h]=Hashdata(x,nowtest+empty);
}

int find_hash(Point x){
	int h=point_hash(x);
	while (hash[h].p!=x && (hash[h].t==nowtest || hash[h].t==nowtest+1)) h=(h+1)%H;
	if (hash[h].p==x) {
		if (hash[h].t==nowtest) return nowtest;
		if (hash[h].t==nowtest+1) return nowtest+1;
	}
	return 0;
}

bool reader(){
	scanf("%d%d",&n,&m);
	if (n==0) return false;
	for (int i=1;i<=n;i++) leftone[i]=n,rightone[i]=0;
	for (int i=1;i<=m;i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		peter[i]=Point(x,y);
		if (x<leftone[y]) leftone[y]=x;
		if (x>rightone[y]) rightone[y]=x;
		add_hash(peter[i],0);
	}
	//for (int i=1;i<=m;i++) charles[i]=peter[i]-Point(0.5,0.5);
	return true;
}

void qsort(int l, int r){
	int i=l,j=r; Point mid=charles[(l+r)/2];
	do {
		while (charles[i]<mid) i++;
		while (charles[j]>mid) j--;
		if (i<=j) {
			Point t=charles[i]; charles[i]=charles[j]; charles[j]=t;
			i++; j--;
		}
	} while (i<=j);
	if (i<r) qsort(i,r);
	if (l<j) qsort(l,j);
}

void asort(int l, int r){
	int i=l,j=r; double mid=anne[(l+r)/2];
	do {
		while (anne[i]<mid) i++; while (anne[j]>mid) j--;
		if (i<=j) {
			Point t=harry[i]; harry[i]=harry[j]; harry[j]=t;
			double q=anne[i]; anne[i]=anne[j]; anne[j]=q;
			i++; j--;
		}
	} while (i<=j);
	if (i<r) asort(i,r);
	if (l<j) asort(l,j);
}

void convex_hull(int vc){
	int qh=2; q[1]=vc; q[2]=vc-1;
	for (int i=vc-2;i>=1;i--) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	int qh1=qh;
	for (int i=1;i<=qh;i++) hull[i]=q[i];
	qh=2; q[1]=1; q[2]=2;
	for (int i=3;i<=vc;i++) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	for (int i=2;i<qh;i++) hull[qh1+i-1]=q[i];
	hc=qh1+qh-2;
	for (int i=0;i<hc;i++) harry[i]=charles[hull[i+1]];
}

/*
inline double triangle_area(const Point &a, const Point &b, const Point &c){
	Point ab=b-a, ac=c-a;
	return fabs(ab/ac/2);
}

inline Point triangle_barycenter(const Point &a, const Point &b, const Point &c){
	return (a+b+c)/3;
}

void center_of_mass(){
	Point sum=Point(0,0); double totalarea=0;
	for (int i=1;i<hc-1;i++) {
		double area=triangle_area(harry[0],harry[i],harry[i+1]);
		Point center=triangle_barycenter(harry[0],harry[i],harry[i+1]);
		//cout<<"area:"<<area<<",center=("<<center.x<<","<<center.y<<")"<<endl;
		sum=sum+center*area;
		totalarea+=area;
	}
	//PRINTPOINT(sum)<<" area="<<totalarea<<endl;
	barycenter=sum/totalarea;
}

void get_anne(){
	for (int i=0;i<hc;i++) anne[i]=(harry[i]-barycenter).angle();
}

int get_rotation(Point p){
	double ang=(p-barycenter).angle();
	//cout<<"angle="<<ang<<endl;
	if (ang<anne[0]) return 0;
	if (ang>anne[hc-1]) return hc;
	int max=hc-1, min=0;
	while (max-min-1) {
		int mid=(max+min)/2;
		if (anne[mid]>=ang) max=mid; else min=mid;
	}
	return max;
}

void convert_to_line(Point s, Point r, double* a, double *b, double *c){
	*a=(r.y-s.y); *b=s.x-r.x; *c=s.y*(r.x-s.x)-s.x*(r.y-s.y);
}

bool in_rectangle(Point obj, Point a, Point b){
	bool s = (obj.x<=a.x+eps && obj.x>=b.x-eps) || (obj.x<=b.x+eps && obj.x>=a.x-eps);
	bool t = (obj.y<=a.y+eps && obj.y>=b.y-eps) || (obj.y<=b.y+eps && obj.y>=a.y-eps);
	//printf("s=%d, t=%d\n",s,t);
	return s&&t;
}

bool intersect(Point ray, Point a, Point b){
	//printf("INTERSECTION?\n");
	//PRINTPOINT(ray)<<endl;
	//PRINTPOINT(a)<<endl;
	//PRINTPOINT(b)<<endl;
	double a1, a2, b1, b2, c1, c2;
	convert_to_line(barycenter, ray, &a1, &b1, &c1);
	convert_to_line(a, b, &a2, &b2, &c2);
	//cout<<"a="<<a1<<" b="<<b1<<" c="<<c1<<endl;
	//cout<<"a="<<a2<<" b="<<b2<<" c="<<c2<<endl;
	double deno=a1*b2-a2*b1;
	if (deno==0) return false;
	double x=(b1*c2-c1*b2)/deno, y=(a2*c1-a1*c2)/deno;
	Point isec=Point(x,y);
	//PRINTPOINT(isec)<<endl;
	bool alpha = in_rectangle(isec,a,b);
	bool beta = in_rectangle(isec,barycenter,ray);
	//printf("infirst %d\n",alpha);
	//printf("insecond %d\n",beta);
	if (alpha&&beta) return true;
	//printf("I am here!\n");
	return false;
}

bool in_hull(Point ray){
	int r=get_rotation(ray);
	//printf("getrotation=%d\n",r);
	int s=r-1; if (s<0) s+=hc;
	if (r==hc) r=0;
	if (intersect(ray,harry[r],harry[s])) return false;
	return true;
} */

bool in_hull(Point ray) {
	int x=ray.x, y=ray.y;
	if (x<leftone[y]) return false;
	if (x>rightone[y]) return false;
}

bool is_zero(int x, int y){
	int p=find_hash(Point(x,y));
	if (p==nowtest) return false;
	if (p==nowtest+1) return true;
	bool q=true;
	////////////////if (in_hull(Point(x,y)-Point(0.5,0.5))) q=false;
	if (in_hull(Point(x,y))) q=false;
	//printf("x=%d, y=%d, q=%d\n",x,y,q);
	add_hash(Point(x,y),q?1:0);
	return q;
}

bool check_zeroes(int x, int y){
	if (is_zero(x,y)) return false;
	if (is_zero(x+1,y)) return false;
	if (is_zero(x,y+1)) return false;
	if (is_zero(x+1,y+1)) return false;
	return true;
}

void add_corner(Point a){
	//printf("Check: "); PRINTPOINT(a)<<endl;
	int h=point_hash(a);
	while (corner[h].t==nowtest) {
		if (corner[h].p==a) return;
		h=(h+1)%H;
	}
	//if (corner[h].p==a) return;
	corner[h]=Hashdata(a,nowtest);
	charles[++cc]=a;
}

void generate(){
	cc=0;
	for (int i=1;i<=m;i++) {
		int x=peter[i].x, y=peter[i].y;
		//printf("genloop i=%d, x=%d, y=%d\n",i,x,y);
		if (check_zeroes(x,y)) add_corner(Point(x,y));
		if (check_zeroes(x-1,y)) add_corner(Point(x-1,y));
		if (check_zeroes(x,y-1)) add_corner(Point(x,y-1));
		if (check_zeroes(x-1,y-1)) add_corner(Point(x-1,y-1));
	}
	qsort(1,cc);
	memset(repeat,false,sizeof(repeat));
	for (int i=2;i<=cc;i++) if (charles[i]==charles[i-1]) repeat[i]=true;
	int nc=0;
	for (int i=1;i<=cc;i++) if (!repeat[i]) charles[++nc]=charles[i];
	cc=nc;
	//for (int i=1;i<=cc;i++) {
	//	PRINTPOINT(charles[i])<<endl;
	//}
}

void printer(){
	printf("%d\n",hc);
	Point starter=harry[0]; int si=0;
	for (int i=1;i<hc;i++) if (harry[i]<starter) starter=harry[i],si=i;
	for (int i=si;i<hc;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
	for (int i=0;i<si;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
}

int main(){
	nowtest=1;
	while (reader()) {
		qsort(1,m);											//O(m log m)
		convex_hull(m);										//O(m)
		//center_of_mass();									//O(m)
		//PRINTPOINT(barycenter)<<endl;
		//get_anne();										//O(m)
		asort(0,hc-1);										//O(m log m)
		generate();											//O(m)
		convex_hull(cc);									//O(m)
		printer();											//O(m)
		nowtest+=2;
	}
}

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

typedef long double triple;
#define Pi 3.1415926535897932385
#define PRINTPOINT(_p_) cout<<"("<<_p_.x<<","<<_p_.y<<")"

struct Point{
	triple x; triple y;
	Point(){x=y=0;}
	Point(triple _x, triple _y){x=_x;y=_y;}
	friend Point operator +(const Point &a, const Point &b){return Point(b.x+a.x,b.y+a.y);}
	friend Point operator -(const Point &a, const Point &b){return Point(a.x-b.x,a.y-b.y);}
	friend Point operator *(const Point &a, triple p){return Point(a.x*p, a.y*p);}
	friend Point operator /(const Point &a, triple p){return Point(a.x/p, a.y/p);}
	friend triple operator *(const Point &p, const Point &a){return (p.x*a.x+p.y*a.y);}
	friend triple operator /(const Point &p, const Point &a){return (p.x*a.y-p.y*a.x);}
	friend bool operator <(const Point &a, const Point &b){
		if (a.x<b.x) return true;
		if (a.x>b.x) return false;
		if (a.y<b.y) return true;
		return false;
	}
	friend bool operator >(const Point &a, const Point &b){
		if (a.x>b.x) return true;
		if (a.x<b.x) return false;
		if (a.y>b.y) return true;
		return false;
	}
	friend bool operator ==(const Point &a, const Point &b){
		return (a.x==b.x && a.y==b.y);
	}
	friend bool operator !=(const Point &a, const Point &b){
		return (a.x!=b.x || a.y!=b.y);
	}
	triple slope(){return y/x;}
	triple measure(){return sqrt(x*x+y*y);}
	triple angle(){
		triple an=atan2(y,x);
		if (an<0) an+=2*Pi;
		return an;
	}
	Point shrink(){
		return Point(1,y/x);
	}
};

struct Hashdata{
	Point p;
	int t;
	Hashdata(){p=Point(); t=0;}
	Hashdata(Point _p, int _t){p=_p; t=_t;}
};

#define N 100010
#define M 200010
#define H 1000007
#define INF (triple)1000000000000
#define _(_x_,_y_) Point(_x_,_y_)
#define eps ((triple)1e-10)

int n,m,hc,cc;
Point peter[M], charles[4*M], harry[M];
bool repeat[4*M];
Point barycenter;
double anne[M];
int hull[M], q[M], nowtest;
Hashdata hash[H];

int point_hash(Point a){
	int x=a.x, y=a.y;
	return (x*10007+y)%H;
}

void add_hash(Point x){
	int h=point_hash(x);
	while (hash[h].t==nowtest) h=(h+1)%H;
	hash[h]=Hashdata(x,nowtest);
}

int find_hash(Point x){
	int h=point_hash(x);
	while (hash[h].p!=x && hash[h].t==nowtest) h=(h+1)%H;
	if (hash[h].p==x && hash[h].t==nowtest) return nowtest;
	return 0;
}

bool reader(){
	scanf("%d%d",&n,&m);
	if (n==0) return false;
	for (int i=1;i<=m;i++) {int x,y; scanf("%d%d",&x,&y); peter[i]=Point(x,y); add_hash(peter[i]);}
	for (int i=1;i<=m;i++) charles[i]=peter[i]-Point(0.5,0.5);
	return true;
}

void qsort(int l, int r){
	int i=l,j=r; Point mid=charles[(l+r)/2];
	do {
		while (charles[i]<mid) i++;
		while (charles[j]>mid) j--;
		if (i<=j) {
			Point t=charles[i]; charles[i]=charles[j]; charles[j]=t;
			i++; j--;
		}
	} while (i<=j);
	if (i<r) qsort(i,r);
	if (l<j) qsort(l,j);
}

void asort(int l, int r){
	int i=l,j=r; triple mid=anne[(l+r)/2];
	do {
		while (anne[i]<mid) i++; while (anne[j]>mid) j--;
		if (i<=j) {
			Point t=harry[i]; harry[i]=harry[j]; harry[j]=t;
			triple q=anne[i]; anne[i]=anne[j]; anne[j]=q;
			i++; j--;
		}
	} while (i<=j);
	if (i<r) asort(i,r);
	if (l<j) asort(l,j);
}

void convex_hull(int vc){
	int qh=2; q[1]=vc; q[2]=vc-1;
	for (int i=vc-2;i>=1;i--) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	int qh1=qh;
	for (int i=1;i<=qh;i++) hull[i]=q[i];
	qh=2; q[1]=1; q[2]=2;
	for (int i=3;i<=vc;i++) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	for (int i=2;i<qh;i++) hull[qh1+i-1]=q[i];
	hc=qh1+qh-2;
	for (int i=0;i<hc;i++) harry[i]=charles[hull[i+1]];
}

inline triple triangle_area(const Point &a, const Point &b, const Point &c){
	Point ab=b-a, ac=c-a;
	return fabs(ab/ac/2);
}

inline Point triangle_barycenter(const Point &a, const Point &b, const Point &c){
	return (a+b+c)/3;
}

void center_of_mass(){
	Point sum=Point(0,0); triple totalarea=0;
	for (int i=1;i<hc-1;i++) {
		triple area=triangle_area(harry[0],harry[i],harry[i+1]);
		Point center=triangle_barycenter(harry[0],harry[i],harry[i+1]);
		//cout<<"area:"<<area<<",center=("<<center.x<<","<<center.y<<")"<<endl;
		sum=sum+center*area;
		totalarea+=area;
	}
	//PRINTPOINT(sum)<<" area="<<totalarea<<endl;
	barycenter=sum/totalarea;
}

void get_anne(){
	for (int i=0;i<hc;i++) anne[i]=(harry[i]-barycenter).angle();
}

int get_rotation(Point p){
	triple ang=(p-barycenter).angle();
	//cout<<"angle="<<ang<<endl;
	if (ang<anne[0]) return 0;
	if (ang>anne[hc-1]) return hc;
	int max=hc-1, min=0;
	while (max-min-1) {
		int mid=(max+min)/2;
		if (anne[mid]>=ang) max=mid; else min=mid;
	}
	return max;
}

void convert_to_line(Point s, Point r, triple* a, triple *b, triple *c){
	*a=(r.y-s.y); *b=s.x-r.x; *c=s.y*(r.x-s.x)-s.x*(r.y-s.y);
}

bool in_rectangle(Point obj, Point a, Point b){
	bool s = (obj.x<=a.x+eps && obj.x>=b.x-eps) || (obj.x<=b.x+eps && obj.x>=a.x-eps);
	bool t = (obj.y<=a.y+eps && obj.y>=b.y-eps) || (obj.y<=b.y+eps && obj.y>=a.y-eps);
	//printf("s=%d, t=%d\n",s,t);
	return s&&t;
}

bool intersect(Point ray, Point a, Point b){
	//printf("INTERSECTION?\n");
	//PRINTPOINT(ray)<<endl;
	//PRINTPOINT(a)<<endl;
	//PRINTPOINT(b)<<endl;
	triple a1, a2, b1, b2, c1, c2;
	convert_to_line(barycenter, ray, &a1, &b1, &c1);
	convert_to_line(a, b, &a2, &b2, &c2);
	//cout<<"a="<<a1<<" b="<<b1<<" c="<<c1<<endl;
	//cout<<"a="<<a2<<" b="<<b2<<" c="<<c2<<endl;
	triple deno=a1*b2-a2*b1;
	if (deno==0) return false;
	triple x=(b1*c2-c1*b2)/deno, y=(a2*c1-a1*c2)/deno;
	Point isec=Point(x,y);
	//PRINTPOINT(isec)<<endl;
	bool alpha = in_rectangle(isec,a,b);
	bool beta = in_rectangle(isec,barycenter,ray);
	//printf("infirst %d\n",alpha);
	//printf("insecond %d\n",beta);
	if (alpha&&beta) return true;
	//printf("I am here!\n");
	return false;
}

bool in_hull(Point ray){
	int r=get_rotation(ray);
	//printf("getrotation=%d\n",r);
	int s=r-1; if (s<0) s+=hc;
	if (r==hc) r=0;
	if (intersect(ray,harry[r],harry[s])) return false;
	return true;
}

bool is_zero(int x, int y){
	int p=find_hash(Point(x,y));
	if (p==nowtest) return false;
	if (in_hull(Point(x,y)-Point(0.5,0.5))) return false;
	return true;
}

bool check_zeroes(int x, int y){
	if (is_zero(x,y)) return false;
	if (is_zero(x+1,y)) return false;
	if (is_zero(x,y+1)) return false;
	if (is_zero(x+1,y+1)) return false;
	return true;
}

void generate(){
	cc=0;
	for (int i=1;i<=m;i++) {
		int x=peter[i].x, y=peter[i].y;
		//printf("genloop i=%d, x=%d, y=%d\n",i,x,y);
		if (check_zeroes(x,y)) charles[++cc]=Point(x,y);
		if (check_zeroes(x-1,y)) charles[++cc]=Point(x-1,y);
		if (check_zeroes(x,y-1)) charles[++cc]=Point(x,y-1);
		if (check_zeroes(x-1,y-1)) charles[++cc]=Point(x-1,y-1);
	}
	qsort(1,cc);
	memset(repeat,false,sizeof(repeat));
	for (int i=2;i<=cc;i++) if (charles[i]==charles[i-1]) repeat[i]=true;
	int nc=0;
	for (int i=1;i<=cc;i++) if (!repeat[i]) charles[++nc]=charles[i];
	cc=nc;
	//for (int i=1;i<=cc;i++) {
	//	PRINTPOINT(charles[i])<<endl;
	//}
}

void printer(){
	printf("%d\n",hc);
	Point starter=harry[0]; int si=0;
	for (int i=1;i<hc;i++) if (harry[i]<starter) starter=harry[i],si=i;
	for (int i=si;i<hc;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
	for (int i=0;i<si;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
}

int main(){
	nowtest=1;
	while (reader()) {
		qsort(1,m);
		convex_hull(m);
		center_of_mass();
		PRINTPOINT(barycenter)<<endl;
		get_anne();
		asort(0,hc-1);
		generate();
		convex_hull(cc);
		printer();
		nowtest++;
	}
}

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

#define Pi 3.1415926535897932385
#define PRINTPOINT(_p_) cout<<"("<<_p_.x<<","<<_p_.y<<")"

struct Point{
	double x; double y;
	Point(){x=y=0;}
	Point(double _x, double _y){x=_x;y=_y;}
	friend Point operator +(const Point &a, const Point &b){return Point(b.x+a.x,b.y+a.y);}
	friend Point operator -(const Point &a, const Point &b){return Point(a.x-b.x,a.y-b.y);}
	friend Point operator *(const Point &a, double p){return Point(a.x*p, a.y*p);}
	friend Point operator /(const Point &a, double p){return Point(a.x/p, a.y/p);}
	friend double operator *(const Point &p, const Point &a){return (p.x*a.x+p.y*a.y);}
	friend double operator /(const Point &p, const Point &a){return (p.x*a.y-p.y*a.x);}
	friend bool operator <(const Point &a, const Point &b){
		if (a.x<b.x) return true;
		if (a.x>b.x) return false;
		if (a.y<b.y) return true;
		return false;
	}
	friend bool operator >(const Point &a, const Point &b){
		if (a.x>b.x) return true;
		if (a.x<b.x) return false;
		if (a.y>b.y) return true;
		return false;
	}
	friend bool operator ==(const Point &a, const Point &b){
		return (a.x==b.x && a.y==b.y);
	}
	friend bool operator !=(const Point &a, const Point &b){
		return (a.x!=b.x || a.y!=b.y);
	}
	double slope(){return y/x;}
	double measure(){return sqrt(x*x+y*y);}
	double angle(){
		double an=atan2(y,x);
		if (an<0) an+=2*Pi;
		return an;
	}
	Point shrink(){
		return Point(1,y/x);
	}
};

struct Hashdata{
	Point p;
	int t;
	Hashdata(){p=Point(); t=0;}
	Hashdata(Point _p, int _t){p=_p; t=_t;}
};

#define N 100010
#define M 200010
#define H 3000007
#define INF (double)1000000000000
#define _(_x_,_y_) Point(_x_,_y_)
#define eps ((double)1e-10)

int n,m,hc,cc;
int leftone[N], rightone[N];
Point peter[M], charles[4*M], harry[M];
int hull[M], q[M], nowtest;
Hashdata hash[H], corner[H];

int point_hash(Point a){
	int x=a.x, y=a.y;
	return (x*10007+y)%H;
}

void add_hash(Point x, bool empty){
	int h=point_hash(x);
	while (hash[h].t==nowtest || hash[h].t==nowtest+1) h=(h+1)%H;
	//cout<<"addhash"; PRINTPOINT(x)<<" "<<(nowtest+empty)<<endl;
	hash[h]=Hashdata(x,nowtest+empty);
}

int find_hash(Point x){
	int h=point_hash(x);
	while (hash[h].p!=x && (hash[h].t==nowtest || hash[h].t==nowtest+1)) h=(h+1)%H;
	if (hash[h].p==x) {
		if (hash[h].t==nowtest) return nowtest;
		if (hash[h].t==nowtest+1) return nowtest+1;
	}
	return 0;
}

bool reader(){
	scanf("%d%d",&n,&m);
	if (n==0) return false;
	for (int i=1;i<=n;i++) leftone[i]=n,rightone[i]=0;
	for (int i=1;i<=m;i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		peter[i]=Point(x,y);
		if (x<leftone[y]) leftone[y]=x;
		if (x>rightone[y]) rightone[y]=x;
		add_hash(peter[i],0);
	}
	//for (int i=1;i<=m;i++) charles[i]=peter[i]-Point(0.5,0.5);
	return true;
}

void qsort(int l, int r){
	int i=l,j=r; Point mid=charles[(l+r)/2];
	do {
		while (charles[i]<mid) i++;
		while (charles[j]>mid) j--;
		if (i<=j) {
			Point t=charles[i]; charles[i]=charles[j]; charles[j]=t;
			i++; j--;
		}
	} while (i<=j);
	if (i<r) qsort(i,r);
	if (l<j) qsort(l,j);
}

void convex_hull(int vc){
	int qh=2; q[1]=vc; q[2]=vc-1;
	for (int i=vc-2;i>=1;i--) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	int qh1=qh;
	for (int i=1;i<=qh;i++) hull[i]=q[i];
	qh=2; q[1]=1; q[2]=2;
	for (int i=3;i<=vc;i++) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	for (int i=2;i<qh;i++) hull[qh1+i-1]=q[i];
	hc=qh1+qh-2;
	for (int i=0;i<hc;i++) harry[i]=charles[hull[i+1]];
}

bool in_hull(Point ray) {
	int x=ray.x, y=ray.y;
	if (x<leftone[y]) return false;
	if (x>rightone[y]) return false;
}

bool is_zero(int x, int y){
	int p=find_hash(Point(x,y));
	if (p==nowtest) return false;
	if (p==nowtest+1) return true;
	bool q=true;
	////////////////if (in_hull(Point(x,y)-Point(0.5,0.5))) q=false;
	if (in_hull(Point(x,y))) q=false;
	//printf("x=%d, y=%d, q=%d\n",x,y,q);
	add_hash(Point(x,y),q?1:0);
	return q;
}

bool check_zeroes(int x, int y){
	if (is_zero(x,y)) return false;
	if (is_zero(x+1,y)) return false;
	if (is_zero(x,y+1)) return false;
	if (is_zero(x+1,y+1)) return false;
	return true;
}

void add_corner(Point a){
	//printf("Check: "); PRINTPOINT(a)<<endl;
	int h=point_hash(a);
	while (corner[h].t==nowtest) {
		if (corner[h].p==a) return;
		h=(h+1)%H;
	}
	//if (corner[h].p==a) return;
	corner[h]=Hashdata(a,nowtest);
	charles[++cc]=a;
}

void generate(){
	cc=0;
	for (int i=1;i<=m;i++) {
		int x=peter[i].x, y=peter[i].y;
		//printf("genloop i=%d, x=%d, y=%d\n",i,x,y);
		if (check_zeroes(x,y)) add_corner(Point(x,y));
		if (check_zeroes(x-1,y)) add_corner(Point(x-1,y));
		if (check_zeroes(x,y-1)) add_corner(Point(x,y-1));
		if (check_zeroes(x-1,y-1)) add_corner(Point(x-1,y-1));
	}
	qsort(1,cc);
	//memset(repeat,false,sizeof(repeat));
	//for (int i=2;i<=cc;i++) if (charles[i]==charles[i-1]) repeat[i]=true;
	//int nc=0;
	//for (int i=1;i<=cc;i++) if (!repeat[i]) charles[++nc]=charles[i];
	//cc=nc;
	//for (int i=1;i<=cc;i++) {
	//	PRINTPOINT(charles[i])<<endl;
	//}
}

void printer(){
	printf("%d\n",hc);
	Point starter=harry[0]; int si=0;
	for (int i=1;i<hc;i++) if (harry[i]<starter) starter=harry[i],si=i;
	for (int i=si;i<hc;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
	for (int i=0;i<si;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
}

int main(){
	nowtest=1;
	while (reader()) {
		generate();											//O(m)
		convex_hull(cc);									//O(m)
		printer();											//O(m)
		nowtest+=2;
	}
}

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;

#define Pi 3.1415926535897932385
#define PRINTPOINT(_p_) cout<<"("<<_p_.x<<","<<_p_.y<<")"

struct Point{
	double x; double y;
	Point(){x=y=0;}
	Point(double _x, double _y){x=_x;y=_y;}
	friend Point operator +(const Point &a, const Point &b){return Point(b.x+a.x,b.y+a.y);}
	friend Point operator -(const Point &a, const Point &b){return Point(a.x-b.x,a.y-b.y);}
	friend Point operator *(const Point &a, double p){return Point(a.x*p, a.y*p);}
	friend Point operator /(const Point &a, double p){return Point(a.x/p, a.y/p);}
	friend double operator *(const Point &p, const Point &a){return (p.x*a.x+p.y*a.y);}
	friend double operator /(const Point &p, const Point &a){return (p.x*a.y-p.y*a.x);}
	friend bool operator <(const Point &a, const Point &b){
		if (a.x<b.x) return true;
		if (a.x>b.x) return false;
		if (a.y<b.y) return true;
		return false;
	}
	friend bool operator >(const Point &a, const Point &b){
		if (a.x>b.x) return true;
		if (a.x<b.x) return false;
		if (a.y>b.y) return true;
		return false;
	}
	friend bool operator ==(const Point &a, const Point &b){
		return (a.x==b.x && a.y==b.y);
	}
	friend bool operator !=(const Point &a, const Point &b){
		return (a.x!=b.x || a.y!=b.y);
	}
	double slope(){return y/x;}
	double measure(){return sqrt(x*x+y*y);}
	double angle(){
		double an=atan2(y,x);
		if (an<0) an+=2*Pi;
		return an;
	}
	Point shrink(){
		return Point(1,y/x);
	}
};

struct Hashdata{
	Point p;
	int t;
	Hashdata(){p=Point(); t=0;}
	Hashdata(Point _p, int _t){p=_p; t=_t;}
};

#define N 100010
#define M 200010
#define H 3000007
#define INF (double)1000000000000
#define _(_x_,_y_) Point(_x_,_y_)
#define eps ((double)1e-10)

int n,m,hc,cc;
int leftone[N], rightone[N];
Point peter[M], charles[4*M], harry[M];
bool repeat[4*M];
Point barycenter;
double anne[M];
int hull[M], q[M], nowtest;
Hashdata hash[H], corner[H];

int point_hash(Point a){
	int x=a.x, y=a.y;
	return (x*10007+y)%H;
}

void add_hash(Point x, bool empty){
	int h=point_hash(x);
	while (hash[h].t==nowtest || hash[h].t==nowtest+1) h=(h+1)%H;
	//cout<<"addhash"; PRINTPOINT(x)<<" "<<(nowtest+empty)<<endl;
	hash[h]=Hashdata(x,nowtest+empty);
}

int find_hash(Point x){
	int h=point_hash(x);
	while (hash[h].p!=x && (hash[h].t==nowtest || hash[h].t==nowtest+1)) h=(h+1)%H;
	if (hash[h].p==x) {
		if (hash[h].t==nowtest) return nowtest;
		if (hash[h].t==nowtest+1) return nowtest+1;
	}
	return 0;
}

bool reader(){
	scanf("%d%d",&n,&m);
	if (n==0) return false;
	for (int i=1;i<=n;i++) leftone[i]=n,rightone[i]=0;
	for (int i=1;i<=m;i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		peter[i]=Point(x,y);
		if (x<leftone[y]) leftone[y]=x;
		if (x>rightone[y]) rightone[y]=x;
		add_hash(peter[i],0);
	}
	//for (int i=1;i<=m;i++) charles[i]=peter[i]-Point(0.5,0.5);
	return true;
}

void qsort(int l, int r){
	int i=l,j=r; Point mid=charles[(l+r)/2];
	do {
		while (charles[i]<mid) i++;
		while (charles[j]>mid) j--;
		if (i<=j) {
			Point t=charles[i]; charles[i]=charles[j]; charles[j]=t;
			i++; j--;
		}
	} while (i<=j);
	if (i<r) qsort(i,r);
	if (l<j) qsort(l,j);
}

void asort(int l, int r){
	int i=l,j=r; double mid=anne[(l+r)/2];
	do {
		while (anne[i]<mid) i++; while (anne[j]>mid) j--;
		if (i<=j) {
			Point t=harry[i]; harry[i]=harry[j]; harry[j]=t;
			double q=anne[i]; anne[i]=anne[j]; anne[j]=q;
			i++; j--;
		}
	} while (i<=j);
	if (i<r) asort(i,r);
	if (l<j) asort(l,j);
}

void convex_hull(int vc){
	int qh=2; q[1]=vc; q[2]=vc-1;
	for (int i=vc-2;i>=1;i--) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	int qh1=qh;
	for (int i=1;i<=qh;i++) hull[i]=q[i];
	qh=2; q[1]=1; q[2]=2;
	for (int i=3;i<=vc;i++) {
		while ( (qh>=2) && ((charles[i]-charles[q[qh-1]])/(charles[q[qh]]-charles[q[qh-1]])<=0) ) qh--;
		qh++; q[qh]=i;
	}
	for (int i=2;i<qh;i++) hull[qh1+i-1]=q[i];
	hc=qh1+qh-2;
	for (int i=0;i<hc;i++) harry[i]=charles[hull[i+1]];
}

/*
inline double triangle_area(const Point &a, const Point &b, const Point &c){
	Point ab=b-a, ac=c-a;
	return fabs(ab/ac/2);
}

inline Point triangle_barycenter(const Point &a, const Point &b, const Point &c){
	return (a+b+c)/3;
}

void center_of_mass(){
	Point sum=Point(0,0); double totalarea=0;
	for (int i=1;i<hc-1;i++) {
		double area=triangle_area(harry[0],harry[i],harry[i+1]);
		Point center=triangle_barycenter(harry[0],harry[i],harry[i+1]);
		//cout<<"area:"<<area<<",center=("<<center.x<<","<<center.y<<")"<<endl;
		sum=sum+center*area;
		totalarea+=area;
	}
	//PRINTPOINT(sum)<<" area="<<totalarea<<endl;
	barycenter=sum/totalarea;
}

void get_anne(){
	for (int i=0;i<hc;i++) anne[i]=(harry[i]-barycenter).angle();
}

int get_rotation(Point p){
	double ang=(p-barycenter).angle();
	//cout<<"angle="<<ang<<endl;
	if (ang<anne[0]) return 0;
	if (ang>anne[hc-1]) return hc;
	int max=hc-1, min=0;
	while (max-min-1) {
		int mid=(max+min)/2;
		if (anne[mid]>=ang) max=mid; else min=mid;
	}
	return max;
}

void convert_to_line(Point s, Point r, double* a, double *b, double *c){
	*a=(r.y-s.y); *b=s.x-r.x; *c=s.y*(r.x-s.x)-s.x*(r.y-s.y);
}

bool in_rectangle(Point obj, Point a, Point b){
	bool s = (obj.x<=a.x+eps && obj.x>=b.x-eps) || (obj.x<=b.x+eps && obj.x>=a.x-eps);
	bool t = (obj.y<=a.y+eps && obj.y>=b.y-eps) || (obj.y<=b.y+eps && obj.y>=a.y-eps);
	//printf("s=%d, t=%d\n",s,t);
	return s&&t;
}

bool intersect(Point ray, Point a, Point b){
	//printf("INTERSECTION?\n");
	//PRINTPOINT(ray)<<endl;
	//PRINTPOINT(a)<<endl;
	//PRINTPOINT(b)<<endl;
	double a1, a2, b1, b2, c1, c2;
	convert_to_line(barycenter, ray, &a1, &b1, &c1);
	convert_to_line(a, b, &a2, &b2, &c2);
	//cout<<"a="<<a1<<" b="<<b1<<" c="<<c1<<endl;
	//cout<<"a="<<a2<<" b="<<b2<<" c="<<c2<<endl;
	double deno=a1*b2-a2*b1;
	if (deno==0) return false;
	double x=(b1*c2-c1*b2)/deno, y=(a2*c1-a1*c2)/deno;
	Point isec=Point(x,y);
	//PRINTPOINT(isec)<<endl;
	bool alpha = in_rectangle(isec,a,b);
	bool beta = in_rectangle(isec,barycenter,ray);
	//printf("infirst %d\n",alpha);
	//printf("insecond %d\n",beta);
	if (alpha&&beta) return true;
	//printf("I am here!\n");
	return false;
}

bool in_hull(Point ray){
	int r=get_rotation(ray);
	//printf("getrotation=%d\n",r);
	int s=r-1; if (s<0) s+=hc;
	if (r==hc) r=0;
	if (intersect(ray,harry[r],harry[s])) return false;
	return true;
} */

bool in_hull(Point ray) {
	int x=ray.x, y=ray.y;
	if (x<leftone[y]) return false;
	if (x>rightone[y]) return false;
}

bool is_zero(int x, int y){
	int p=find_hash(Point(x,y));
	if (p==nowtest) return false;
	if (p==nowtest+1) return true;
	bool q=true;
	////////////////if (in_hull(Point(x,y)-Point(0.5,0.5))) q=false;
	if (in_hull(Point(x,y))) q=false;
	//printf("x=%d, y=%d, q=%d\n",x,y,q);
	add_hash(Point(x,y),q?1:0);
	return q;
}

bool check_zeroes(int x, int y){
	if (is_zero(x,y)) return false;
	if (is_zero(x+1,y)) return false;
	if (is_zero(x,y+1)) return false;
	if (is_zero(x+1,y+1)) return false;
	return true;
}

void add_corner(Point a){
	//printf("Check: "); PRINTPOINT(a)<<endl;
	int h=point_hash(a);
	while (corner[h].t==nowtest) {
		if (corner[h].p==a) return;
		h=(h+1)%H;
	}
	//if (corner[h].p==a) return;
	corner[h]=Hashdata(a,nowtest);
	charles[++cc]=a;
}

void generate(){
	cc=0;
	for (int i=1;i<=m;i++) {
		int x=peter[i].x, y=peter[i].y;
		//printf("genloop i=%d, x=%d, y=%d\n",i,x,y);
		if (check_zeroes(x,y)) add_corner(Point(x,y));
		if (check_zeroes(x-1,y)) add_corner(Point(x-1,y));
		if (check_zeroes(x,y-1)) add_corner(Point(x,y-1));
		if (check_zeroes(x-1,y-1)) add_corner(Point(x-1,y-1));
	}
	qsort(1,cc);
	memset(repeat,false,sizeof(repeat));
	for (int i=2;i<=cc;i++) if (charles[i]==charles[i-1]) repeat[i]=true;
	int nc=0;
	for (int i=1;i<=cc;i++) if (!repeat[i]) charles[++nc]=charles[i];
	cc=nc;
	//for (int i=1;i<=cc;i++) {
	//	PRINTPOINT(charles[i])<<endl;
	//}
}

void printer(){
	printf("%d\n",hc);
	Point starter=harry[0]; int si=0;
	for (int i=1;i<hc;i++) if (harry[i]<starter) starter=harry[i],si=i;
	for (int i=si;i<hc;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
	for (int i=0;i<si;i++) {
		int x=harry[i].x, y=harry[i].y;
		printf("%d %d\n",x,y);
	}
}

int main(){
	nowtest=1;
	while (reader()) {
		generate();											//O(m)
		convex_hull(cc);									//O(m)
		printer();											//O(m)
		nowtest+=2;
	}
}

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define M 1010
#define ep 1e-9

typedef pair <LL, LL> PII;

int n, m, id[M * M];

int dx[] = {-1, -1, 0, 0};
int dy[] = {-1, 0, -1, 0};

double ang[M * M];

vector <PII> v, in;

PII con[M * M];

PII operator - (PII a, PII b) {
  return PII(a.first - b.first, a.second - b.second);
}

int operator ^ (PII a, PII b) {
  return a.first * b.second - a.second * b.first;
}

int dist(PII a) {
  return a.first * a.first + a.second * a.second;
}

bool cmp(int i, int j) {
  if (fabs(ang[i] - ang[j]) > ep) {
    return ang[i] > ang[j];
  }
  return dist(v[i] - v[0]) < dist(v[j] - v[0]);
}

map <PII, bool> mp;

int main() {
  //freopen("in.txt", "r", stdin);
  int x, y;
  while (scanf("%d %d", &n, &m) && n) {
    in.clear(); v.clear(); mp.clear();
    int minx = n + 1, maxx = -1, miny, maxy;
    for (int i = 0; i < m; i++) {
      scanf("%d %d", &x, &y); in.push_back(PII(x, y));
      mp[PII(x, y)] = 1;
      if (minx > x || (minx == x && miny < y)) {
        minx = x; miny = y;
      }
      if (maxx < x || (maxx == x && maxy > y)) {
        maxx = x; maxy = y;
      }
    }

    PII lft = PII(minx, miny - 1);
    PII rgt = PII(maxx - 1, maxy);

    //printf("%d %d\n", lft.first, lft.second); printf("%d %d\n", rgt.first, rgt.second); puts("----");

    v.push_back(lft); v.push_back(rgt);

    for (int i = 0; i < m; i++) {
      for (int k = 0; k < 4; k++) {
        x = in[i].first + dx[k], y = in[i].second + dy[k];
        PII cur = PII(x, y);
        if (((cur - lft) ^ (rgt - lft)) > 0) {
          if (mp.count(cur) && mp.count(PII(cur.first + 1, cur.second))) {
            v.push_back(cur);
          }
        }
        else {
          if (mp.count(PII(cur.first, cur.second + 1)) && mp.count(PII(cur.first + 1, cur.second + 1))) {
            v.push_back(cur);
          }
        }
      }
    }

    sort(v.begin(), v.end());
    v.resize(unique(v.begin(), v.end()) - v.begin());
    int sz = v.size();
    id[0] = 0;
    for (int i = 1; i < sz; i++)
      id[i] = i, ang[i] = atan2(v[i].second - v[0].second, v[i].first - v[0].first);
    sort(id + 1, id + sz, cmp);
    int k = 0;
    for (int i = 0; i < sz; i++) {
      while (k > 1 && ((con[k - 1] - con[k - 2]) ^ (v[id[i]] - con[k - 2])) >= 0) k--;
      con[k++] = v[id[i]];
    }
    printf("%d\n", k);
    for (int i = 0; i < k; i++) {
      printf("%I64d %I64d\n", con[i].first, con[i].second);
    }
  }
}

#include <bits/stdc++.h>
using namespace std;
#define M 1010
#define ep 1e-9

typedef pair <int, int> PII;

char s[M][M];

int n, m, a[M][M], id[M * M];

int dx[] = {-1, -1, 0, 0};
int dy[] = {-1, 0, -1, 0};

double ang[M * M];

vector <PII> v, in;

PII con[M * M];

PII operator - (PII a, PII b) {
  return PII(a.first - b.first, a.second - b.second);
}

int operator ^ (PII a, PII b) {
  return a.first * b.second - a.second * b.first;
}

int dist(PII a) {
  return a.first * a.first + a.second * a.second;
}

bool cmp(int i, int j) {
  if (fabs(ang[i] - ang[j]) > ep) {
    return ang[i] > ang[j];
  }
  return dist(v[i] - v[0]) < dist(v[j] - v[0]);
}

map <PII, bool> mp;

int main() {
  //freopen("in.txt", "r", stdin);
  int x, y;
  while (scanf("%d %d", &n, &m) && n) {
    in.clear(); v.clear(); mp.clear();
    int minx = n + 1, maxx = -1, miny, maxy;
    for (int i = 0; i < m; i++) {
      scanf("%d %d", &x, &y); in.push_back(PII(x, y));
      mp[PII(x, y)] = 1;
      if (minx > x || (minx == x && miny < y)) {
        minx = x; miny = y;
      }
      if (maxx < x || (maxx == x && maxy > y)) {
        maxx = x; maxy = y;
      }
    }

    PII lft = PII(minx, miny - 1);
    PII rgt = PII(maxx - 1, maxy);

    //printf("%d %d\n", lft.first, lft.second); printf("%d %d\n", rgt.first, rgt.second); puts("----");

    v.push_back(lft); v.push_back(rgt);

    for (int i = 0; i < m; i++) {
      for (int k = 0; k < 4; k++) {
        x = in[i].first + dx[k], y = in[i].second + dy[k];
        PII cur = PII(x, y);
        if (((cur - lft) ^ (rgt - lft)) > 0) {
          if (mp.count(cur) && mp.count(PII(cur.first + 1, cur.second))) {
            v.push_back(cur);
          }
        }
        else {
          if (mp.count(PII(cur.first, cur.second + 1)) && mp.count(PII(cur.first + 1, cur.second + 1))) {
            v.push_back(cur);
          }
        }
      }
    }

    sort(v.begin(), v.end());
    v.resize(unique(v.begin(), v.end()) - v.begin());
    int sz = v.size();
    id[0] = 0;
    for (int i = 1; i < sz; i++)
      id[i] = i, ang[i] = atan2(v[i].second - v[0].second, v[i].first - v[0].first);
    sort(id + 1, id + sz, cmp);
    int k = 0;
    for (int i = 0; i < sz; i++) {
      while (k > 1 && ((con[k - 1] - con[k - 2]) ^ (v[id[i]] - con[k - 2])) >= 0) k--;
      con[k++] = v[id[i]];
    }
    printf("%d\n", k);
    for (int i = 0; i < k; i++) {
      printf("%d %d\n", con[i].first, con[i].second);
    }
  }
}

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<cmath>
#include<algorithm>

const double eps = 1e-9;
const int N = 100005;
const int dx[] = {+0,+1,+0,-1};
const int dy[] = {+1,+0,-1,+0};

using namespace std;

struct Point {
	double x,y;
	Point (double a=0,double b=0) {x=a,y=b;}

}p[N],q[N],stack[N];

inline Point operator + (const Point& a, const Point& b) {return Point(a.x+b.x,a.y+b.y);}
inline Point operator - (const Point& a, const Point& b) {return Point(a.x-b.x,a.y-b.y);}
inline double operator * (const Point& a, const Point& b) {return a.x*b.x+a.y*b.y;}
inline double operator / (const Point& a, const Point& b) {return a.x*b.y-a.y*b.x;}

bool cmp(const Point& a, const Point& b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}

int n,m,top,tot;
int mx[N],mn[N];

bool is_Zero(int x, int y) {if (y<0||y>=n||mn[y]>mx[y]) return true; return (x<mn[y]||x>mx[y]);}

void convex_hull() {
	sort(p+1,p+tot+1,cmp);
	int bs=0;
	for (int i=1;i<=tot;i++) {while ((top>1)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	bs=top;
	for (int i=tot-1;i>=1;i--) {while ((top>bs)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	printf("%d\n",top-1);
	for (int i=top;i>1;i--) cout<<stack[i].x<<' '<<stack[i].y<<endl;
}

int main() {

	while (true) {
		scanf("%d%d",&n,&m); if (n==0) break; top=0; tot=0;
		for (int i=1;i<=m;i++) scanf("%lf%lf",&q[i].x,&q[i].y),q[i].x--,q[i].y--;
		for (int i=1;i<=m;i++) mx[i]=INT_MIN,mn[i]=INT_MAX;
		for (int i=1;i<=m;i++) {
			int tmp=q[i].y;	if (q[i].x<mn[tmp]) mn[tmp]=q[i].x; if (q[i].x>mx[tmp]) mx[tmp]=q[i].x;
		}
		for (int i=1;i<=m;i++) {
			for (int k=0;k<4;k++) {
				int kk=(k+1)%4;
				if ((is_Zero(q[i].x+dx[k],q[i].y+dy[k]))&&(is_Zero(q[i].x+dx[kk],q[i].y+dy[kk])))
				 {
				 	//cout<<"IN"<<tot<<endl;
				 	if (k==0) {p[++tot] = q[i];}
				 	if (k==1) {p[++tot] = Point(q[i].x,q[i].y+1);}
				 	if (k==2) {p[++tot] = Point(q[i].x+1,q[i].y+1);}
				 	if (k==3) {p[++tot] = Point(q[i].x+1,q[i].y);}
				 	//cout<<"OUT"<<tot<<endl;
				 	//cout<<p[i].x<<' '<<p[i].y<<endl;
				 	//cout<<p[tot].x<<' '<<p[tot].y<<endl;
				 }

			}
		}

		//for (int i=1;i<=tot;i++) cout<<p[i].x<<' '<<p[i].y<<endl;

		convex_hull();

	}
	return 0;
}

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<cmath>
#include<algorithm>

const double eps = 1e-9;
const int N = 500005;
const int dx[] = {+0,+1,+0,-1};
const int dy[] = {+1,+0,-1,+0};

using namespace std;

struct Point {
	int x,y;
	Point (int a=0,int b=0) {x=a,y=b;}
}p[N],q[N],stack[N];

inline Point operator + (const Point& a, const Point& b) {return Point(a.x+b.x,a.y+b.y);}
inline Point operator - (const Point& a, const Point& b) {return Point(a.x-b.x,a.y-b.y);}
inline int operator * (const Point& a, const Point& b) {return a.x*b.x+a.y*b.y;}
inline int operator / (const Point& a, const Point& b) {return a.x*b.y-a.y*b.x;}

bool cmp(const Point& a, const Point& b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}

int n,m,top,tot;
int mx[N],mn[N];

bool is_Zero(int x, int y) {if (y<0||y>=n||mn[y]>mx[y]) return true; return (x<mn[y]||x>mx[y]);}

void convex_hull() {
	sort(p+1,p+tot+1,cmp);
	int bs=0;
	for (int i=1;i<=tot;i++) {while ((top>1)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	bs=top;
	for (int i=tot-1;i>=1;i--) {while ((top>bs)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	printf("%d\n",top-1);
	for (int i=top;i>1;i--) cout<<stack[i].x<<' '<<stack[i].y<<endl;
}

int main() {

	while (true) {
		scanf("%d%d",&n,&m); if (n==0) break; top=0; tot=0;
		for (int i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].x--,q[i].y--;
		for (int i=1;i<=n;i++) mx[i]=INT_MIN,mn[i]=INT_MAX;
		for (int i=1;i<=m;i++) {
			int tmp=q[i].y;	if (q[i].x<mn[tmp]) mn[tmp]=q[i].x; if (q[i].x>mx[tmp]) mx[tmp]=q[i].x;
		}
		for (int i=1;i<=m;i++) {
			for (int k=0;k<4;k++) {
				int kk=(k+1)%4;
				if ((is_Zero(q[i].x+dx[k],q[i].y+dy[k]))&&(is_Zero(q[i].x+dx[kk],q[i].y+dy[kk])))
				 {
				 	//cout<<"IN"<<tot<<endl;
				 	if (k==0) {p[++tot] = q[i];}
				 	if (k==1) {p[++tot] = Point(q[i].x,q[i].y+1);}
				 	if (k==2) {p[++tot] = Point(q[i].x+1,q[i].y+1);}
				 	if (k==3) {p[++tot] = Point(q[i].x+1,q[i].y);}
				 	//cout<<"OUT"<<tot<<endl;
				 	//cout<<p[i].x<<' '<<p[i].y<<endl;
				 	//cout<<p[tot].x<<' '<<p[tot].y<<endl;
				 }

			}
		}

		//for (int i=1;i<=tot;i++) cout<<p[i].x<<' '<<p[i].y<<endl;

		convex_hull();

	}
	return 0;
}

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<cmath>
#include<algorithm>

const double eps = 1e-9;
const int N = 500005;
const int dx[] = {+0,+1,+0,-1};
const int dy[] = {+1,+0,-1,+0};

using namespace std;

struct Point {
	int x,y;
	Point (int a=0,int b=0) {x=a,y=b;}
}p[N],q[N],stack[N];

inline Point operator + (const Point& a, const Point& b) {return Point(a.x+b.x,a.y+b.y);}
inline Point operator - (const Point& a, const Point& b) {return Point(a.x-b.x,a.y-b.y);}
inline int operator * (const Point& a, const Point& b) {return a.x*b.x+a.y*b.y;}
inline int operator / (const Point& a, const Point& b) {return a.x*b.y-a.y*b.x;}

bool cmp(const Point& a, const Point& b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}

int n,m,top,tot;
int mx[N],mn[N];

bool is_Zero(int x, int y) {if (y<0||y>=n||mn[y]>mx[y]) return true; return (x<mn[y]||x>mx[y]);}

void convex_hull() {
	sort(p+1,p+tot+1,cmp);
	int bs=0;
	for (int i=1;i<=tot;i++) {while ((top>1)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	bs=top;
	for (int i=tot-1;i>=1;i--) {while ((top>bs)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	printf("%d\n",top-1);
	for (int i=top;i>1;i--) cout<<stack[i].x<<' '<<stack[i].y<<endl;
}

int main() {

	while (true) {
		scanf("%d%d",&n,&m); if (n==0) break; top=0; tot=0;
		for (int i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].x--,q[i].y--;
		for (int i=1;i<=m;i++) mx[i]=INT_MIN,mn[i]=INT_MAX;
		for (int i=1;i<=m;i++) {
			int tmp=q[i].y;	if (q[i].x<mn[tmp]) mn[tmp]=q[i].x; if (q[i].x>mx[tmp]) mx[tmp]=q[i].x;
		}
		for (int i=1;i<=m;i++) {
			for (int k=0;k<4;k++) {
				int kk=(k+1)%4;
				if ((is_Zero(q[i].x+dx[k],q[i].y+dy[k]))&&(is_Zero(q[i].x+dx[kk],q[i].y+dy[kk])))
				 {
				 	//cout<<"IN"<<tot<<endl;
				 	if (k==0) {p[++tot] = q[i];}
				 	if (k==1) {p[++tot] = Point(q[i].x,q[i].y+1);}
				 	if (k==2) {p[++tot] = Point(q[i].x+1,q[i].y+1);}
				 	if (k==3) {p[++tot] = Point(q[i].x+1,q[i].y);}
				 	//cout<<"OUT"<<tot<<endl;
				 	//cout<<p[i].x<<' '<<p[i].y<<endl;
				 	//cout<<p[tot].x<<' '<<p[tot].y<<endl;
				 }

			}
		}

		//for (int i=1;i<=tot;i++) cout<<p[i].x<<' '<<p[i].y<<endl;

		convex_hull();

	}
	return 0;
}

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<cmath>
#include<algorithm>

const double eps = 1e-9;
const int N = 500005;
const int dx[] = {+0,+1,+0,-1};
const int dy[] = {+1,+0,-1,+0};

using namespace std;

struct Point {
	int x,y;
	Point (int a=0,int b=0) {x=a,y=b;}
}p[N],q[N],stack[N];

inline Point operator + (const Point& a, const Point& b) {return Point(a.x+b.x,a.y+b.y);}
inline Point operator - (const Point& a, const Point& b) {return Point(a.x-b.x,a.y-b.y);}
inline int operator * (const Point& a, const Point& b) {return a.x*b.x+a.y*b.y;}
inline int operator / (const Point& a, const Point& b) {return a.x*b.y-a.y*b.x;}

bool cmp(const Point& a, const Point& b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}

int n,m,top,tot;
int mx[N],mn[N];

bool is_Zero(int x, int y) {if (y<0||y>=n||mn[y]>mx[y]) return true; return (x<mn[y]||x>mx[y]);}

void convex_hull() {
	sort(p+1,p+tot+1,cmp);
	int bs=0;
	for (int i=1;i<=tot;i++) {while ((top>1)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	bs=top;
	for (int i=tot-1;i>=1;i--) {while ((top>bs)&&((p[i]-stack[top-1])/(stack[top]-stack[top-1])>=0)) top--; stack[++top]=p[i];}
	printf("%d\n",top-1);
	for (int i=top;i>1;i--) cout<<stack[i].x<<' '<<stack[i].y<<endl;
}

int main() {

	while (true) {
		scanf("%d%d",&n,&m); if (n==0) break; top=0; tot=0;
		for (int i=1;i<=m;i++) scanf("%lf%lf",&q[i].x,&q[i].y),q[i].x--,q[i].y--;
		for (int i=1;i<=m;i++) mx[i]=INT_MIN,mn[i]=INT_MAX;
		for (int i=1;i<=m;i++) {
			int tmp=q[i].y;	if (q[i].x<mn[tmp]) mn[tmp]=q[i].x; if (q[i].x>mx[tmp]) mx[tmp]=q[i].x;
		}
		for (int i=1;i<=m;i++) {
			for (int k=0;k<4;k++) {
				int kk=(k+1)%4;
				if ((is_Zero(q[i].x+dx[k],q[i].y+dy[k]))&&(is_Zero(q[i].x+dx[kk],q[i].y+dy[kk])))
				 {
				 	//cout<<"IN"<<tot<<endl;
				 	if (k==0) {p[++tot] = q[i];}
				 	if (k==1) {p[++tot] = Point(q[i].x,q[i].y+1);}
				 	if (k==2) {p[++tot] = Point(q[i].x+1,q[i].y+1);}
				 	if (k==3) {p[++tot] = Point(q[i].x+1,q[i].y);}
				 	//cout<<"OUT"<<tot<<endl;
				 	//cout<<p[i].x<<' '<<p[i].y<<endl;
				 	//cout<<p[tot].x<<' '<<p[tot].y<<endl;
				 }

			}
		}

		//for (int i=1;i<=tot;i++) cout<<p[i].x<<' '<<p[i].y<<endl;

		convex_hull();

	}
	return 0;
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		for (i=1;i<=nm;i++) if (A[i].x==53 && A[i].y==1783) puts("QAQ");
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		for (i=1;i<=m;i++) if (A[i].x==53 && A[i].y==1783) puts("QAQ");
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(A[1],a)<dis(A[1],b);
	return (ll) x1*y2<(ll) x2*y1;
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(A[1],b)<dis(A[1],c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool cmp3(const cc &a,const cc &b) {
	return dis(A[1],a)<dis(A[1],b);
}
bool cmp4(const cc &a,const cc &b) {
	return dis(A[1],a)>dis(A[1],b);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool check3(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2==(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		i=2;
		while (i<n && check3(A[1],A[2],A[i+1])) i++;
		sort(A+2,A+i+1,cmp3);
		i=n;
		while (i>2 && check3(A[1],A[n],A[i-1])) i--;
		sort(A+i+1,A+n+1,cmp4);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) {
				if (A[m].x==53 && A[m].y==1783) {
					printf("%d %d %d %d %d %d\n",m,i,A[m-1].x,A[m-1].y,A[i].x,A[i].y);
					puts("=====================");
				}
				m--;
			}
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(A[1],b)<dis(A[1],c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) {
			if (A[m].x==53 && A[m].y==1783) {
				printf("%d %d %d %d %d\n",m,A[m-1].x,A[m-1].y,A[1].x,A[1].y);
				puts("=====================");
			}
			m--;
		}
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	if (a.x==40 && a.y==2827 && b.x==14 && b.y==4915 && c.x==53 && c.y==1783) {
		int x1,y1,x2,y2;
		x1=b.x-a.x;y1=b.y-a.y;
		x2=c.x-b.x;y2=c.y-b.y;
		printf("%I64d %I64d\n",(ll) x1*y2,(ll) x2*y1);
	}
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else {
				if (A[i].x==53 && A[i].y==1783) {
					printf("%d %d %d %d %d\n",m,A[m-1].x,A[m-1].y,A[m].x,A[m].y);
					puts("=====================");
				}
				if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
			}
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		for (i=1;i<=m;i++) if (A[i].x==53 && A[j].y==1783) puts("QAQ");
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(A[1],b)>dis(A[1],c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		for (i=1;i<=m;i++) if (A[i].x==53 && A[i].y==1783) puts("QAQ");
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
#define max(x,y) ((x)<(y)?(y):(x))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
typedef long long ll;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return (ll) x1*y2<(ll) x2*y1;
}
ll dis(const cc &a,const cc &b) {
	return (ll) (a.x-b.x)*(a.x-b.x)+(ll) (a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if ((ll) x1*y2==(ll) x2*y1) return dis(a,b)<dis(a,c);
	return (ll) x1*y2>(ll) x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return (ll) x1*y2<(ll) x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				l[P[i].x]=min(l[P[i].x],P[i].y);
				r[P[i].x]=max(r[P[i].x],P[i].y);
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else {
				if (A[i].x==53 && A[i].y==1783) {
					printf("%d %d %d %d %d\n",m,A[m-1].x,A[m-1].y,A[m].x,A[m].y);
					puts("=====================");
				}
				if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
			}
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100100,M=200200;
int i,j,k,n,q,m,nm,ch,ii;
int l[N],r[N],fg[N];
struct cc { int x,y;} t,A[M],P[M];
void R(int &x) {
	x=0;ch=getchar();
	while (ch<'0' || '9'<ch) ch=getchar();
	while ('0'<=ch && ch<='9') x=x*10+ch-'0',ch=getchar();
}
void W(int x) {
	if (x>=10) W(x/10);
	putchar(x%10+'0');
}
bool cmp1(const cc &a,const cc &b) {
	if (a.x==b.x) return a.y<b.y;
	return a.x<b.x;
}
bool cmp2(const cc &a,const cc &b) {
	int x1,y1,x2,y2;
	x1=a.x-A[1].x;y1=a.y-A[1].y;
	x2=b.x-a.x;y2=b.y-a.y;
	return x1*y2<x2*y1;
}
int dis(const cc &a,const cc &b) {
	return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
}
bool check(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	if (x1*y2==x2*y1) return dis(a,b)<dis(a,c);
	return x1*y2>x2*y1;
}
bool check2(const cc &a,const cc &b,const cc &c) {
	int x1,y1,x2,y2;
	x1=b.x-a.x;y1=b.y-a.y;
	x2=c.x-b.x;y2=c.y-b.y;
	return x1*y2<x2*y1;
}
bool find(int x,int y) {
	if (fg[x]!=ii) return 0;
	if (y<l[x] || r[x]<y) return 0;
	return 1;
}
int main() {
	R(n);R(q);
	while (n && q) {
		ii++;
		m=0;
		for (i=1;i<=q;i++) {
			R(P[i].x);R(P[i].y);
			if (fg[P[i].x]!=ii) {
				fg[P[i].x]=ii;
				l[P[i].x]=r[P[i].x]=P[i].y;
			}
			else {
				if (P[i].y<l[P[i].x]) l[P[i].x]=P[i].y;
				if (P[i].y>r[P[i].x]) r[P[i].x]=P[i].y;
			}
		}
		for (k=1;k<=q;k++) {
			i=P[k].x;j=P[k].y;
			if (!find(i+1,j-1) && !find(i+1,j) && !find(i,j-1)) A[++m].x=i-1,A[m].y=j;
			if (!find(i+1,j+1) && !find(i+1,j) && !find(i,j+1)) A[++m].x=i-1,A[m].y=j-1;
			if (!find(i-1,j+1) && !find(i-1,j) && !find(i,j+1)) A[++m].x=i,A[m].y=j-1;
			if (!find(i-1,j-1) && !find(i-1,j) && !find(i,j-1)) A[++m].x=i,A[m].y=j;
		}
		sort(A+1,A+m+1,cmp1);
		A[m+1].x=-1;nm=0;
		for (i=1;i<=m;i++) if (A[i].x!=A[i+1].x || A[i].y!=A[i+1].y) A[++nm]=A[i];
		sort(A+2,A+nm+1,cmp2);
		m=2;
		for (i=3;i<=nm;i++) {
			while (m>=2 && check(A[m-1],A[m],A[i])) m--;
			if (m<2) A[++m]=A[i];
			else if (check2(A[m-1],A[m],A[i])) A[++m]=A[i];
		}
		while (m>=2 && check(A[m-1],A[m],A[1])) m--;
		W(m);puts("");
		for (i=1;i<=m;i++) W(A[i].x),putchar(' '),W(A[i].y),puts("");
		R(n);R(q);
	}
}

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long double ld;
typedef long long ll;
const ld EPS = 1e-5;
char a1[200000], a2[200000];
int s1[200000], s2[200000], d1[200000], d2[200000];
ld s[200000];
ld sqr(ld w) {
  return w * w;
}
int cmp(ld c1, int c2, int c3, ld v1, int v2, int v3) {
  if (c1 + EPS < v1) {
    return -1;
  }
  if (c1 - EPS > v1) {
    return 1;
  }
  if (c2 > v2) {
    return -1;
  }
  if (c2 < v2) {
    return 1;
  }
  if (c3 < v3) {
    return -1;
  }
  if (c3 > v3) {
    return 1;
  }
  return 0;
}
void qs(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  ld t1 = s[y];
  int t2 = s1[y], t3 = s2[y];
  do {
    while (cmp(s[e], s1[e], s2[e], t1, t2, t3) < 0) e++;
    while (cmp(s[r], s1[r], s2[r], t1, t2, t3) > 0) r--;
    if (e <= r) {
      swap(s[e], s[r]);
      swap(s1[e], s1[r]);
      swap(s2[e], s2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs(q, r);
  if (e < w) qs(e, w);
}
int cmp2(int c1, int c2, int v1, int v2) {
  if (c1 < v1) {
    return -1;
  }
  if (c1 > v1) {
    return 1;
  }
  if (c2 < v2) {
    return -1;
  }
  if (c2 > v2) {
    return 1;
  }
  return 0;
}
void qs2(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  int t1 = a1[y], t2 = a2[y];
  do {
    while (cmp2(a1[e], a2[e], t1, t2) < 0) e++;
    while (cmp2(a1[r], a2[r], t1, t2) > 0) r--;
    if (e <= r) {
      swap(a1[e], a1[r]);
      swap(a2[e], a2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs2(q, r);
  if (e < w) qs2(e, w);
}
ld rot(ld q, ld w, ld e, ld r, ld t, ld y) {
  return (e - q) * (y - w) - (t - q) * (r - w);
}
int q, lAns1, lAns2, numV;

int sch(int e, int r) {
  int c1 = 0, c, v;
  for (v = 1<<17; v; v >>= 1) {
    c = c1 + v;
    if (c < numV) {
      if ((a1[c] < e) || ((a1[c] == e) && (a2[c] <= r))) {
        c1 = c;
      }
    }
  }
  if ((a1[c1] != e) || (a2[c1] != r)) {
    return 0;
  }
  return 1;
}
void check(int e, int r, int de, int dr) {
  if (sch(e + de, r) + sch(e, r + dr) == 2) {
    lAns1 = (1 + de) / 2;
    lAns2 = (1 + dr) / 2;
  }
}
int main() {
  #ifdef Vlad_kv
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
  #endif // Vlad_kv
  int w, e, r, t;
  for (scanf("%d", &q); q; scanf("%d", &q)) {
    scanf("%d", &numV);
    for (w = 0; w < numV; w++) {
      scanf("%d%d", &s1[w], &s2[w]);
      s1[w]--;
      s2[w]--;
      a1[w] = s1[w];
      a2[w] = s2[w];
    }
    qs2(0, numV - 1);
    for (w = 1; w < numV; w++) {
      if ((s2[w] < s2[0]) || ((s2[w] == s2[0]) && (s1[w] < s1[0]))) {
        swap(s1[w], s1[0]);
        swap(s2[w], s2[0]);
      }
    }
    for (w = 1; w < numV; w++) {
      ld AB = sqrt(sqr(s1[w] - s1[0]) + sqr(s2[w] - s2[0]));
      s[w] = (sqr(AB) + 1 - (sqr(s1[w] - s1[0] - 1) + sqr(s2[w] - s2[0]))) /
             AB;
    }
    qs(1, numV - 1);

    t = 0;
    for (w = 1; w < numV; w++) {
      while (!((t == 0) || (rot(s1[t - 1], s2[t - 1], s1[t], s2[t], s1[w], s2[w]) < -0.1))) {
        t--;
      }
      t++;
      s1[t] = s1[w];
      s2[t] = s2[w];
    }
    t++;

    for (w = 0; w < t; w++) {
      check(s1[w], s2[w], 1, 1);
      check(s1[w], s2[w], 1, -1);
      check(s1[w], s2[w], -1, 1);
      check(s1[w], s2[w], -1, -1);

      d1[w] = s1[w] + lAns1;
      d2[w] = s2[w] + lAns2;
    }

    r = 0;

    for (w = 1; w < t; w++) {
      if ((d1[w] != d1[r]) || (d2[w] != d2[r])) {
        r++;
        d1[r] = d1[w];
        d2[r] = d2[w];
      }
    }
    while ((d1[r] == d1[0]) && (d2[r] == d2[0])) {
      r--;
    }

    t = r + 1;

    r = 0;
    for (e = 1; e < t; e++) {
      if ((d1[e] < d1[r]) || ((d1[e] == d1[r]) && (d2[e] < d2[r]))) {
        r = e;
      }
    }

    cout << t << "\n";
    e = r;
    do {
      printf("%d %d\n", d1[e], d2[e]);
      e++;
      if (e == t) {
        e = 0;
      }
    } while (e != r);

  }
  return 0;
}

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long double ld;
typedef long long ll;
const ld EPS = 1e-10;
char a1[200000], a2[200000];
int s1[200000], s2[200000], d1[200000], d2[200000];
ld s[200000];
ld sqr(ld w) {
  return w * w;
}
int cmp(ld c1, int c2, int c3, ld v1, int v2, int v3) {
  if (c1 + EPS < v1) {
    return -1;
  }
  if (c1 - EPS > v1) {
    return 1;
  }
  if (c2 > v2) {
    return -1;
  }
  if (c2 < v2) {
    return 1;
  }
  if (c3 < v3) {
    return -1;
  }
  if (c3 > v3) {
    return 1;
  }
  return 0;
}
void qs(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  ld t1 = s[y];
  int t2 = s1[y], t3 = s2[y];
  do {
    while (cmp(s[e], s1[e], s2[e], t1, t2, t3) < 0) e++;
    while (cmp(s[r], s1[r], s2[r], t1, t2, t3) > 0) r--;
    if (e <= r) {
      swap(s[e], s[r]);
      swap(s1[e], s1[r]);
      swap(s2[e], s2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs(q, r);
  if (e < w) qs(e, w);
}
int cmp2(int c1, int c2, int v1, int v2) {
  if (c1 < v1) {
    return -1;
  }
  if (c1 > v1) {
    return 1;
  }
  if (c2 < v2) {
    return -1;
  }
  if (c2 > v2) {
    return 1;
  }
  return 0;
}
void qs2(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  int t1 = a1[y], t2 = a2[y];
  do {
    while (cmp2(a1[e], a2[e], t1, t2) < 0) e++;
    while (cmp2(a1[r], a2[r], t1, t2) > 0) r--;
    if (e <= r) {
      swap(a1[e], a1[r]);
      swap(a2[e], a2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs2(q, r);
  if (e < w) qs2(e, w);
}
ld rot(ld q, ld w, ld e, ld r, ld t, ld y) {
  return (e - q) * (y - w) - (t - q) * (r - w);
}
int q, lAns1, lAns2, numV;

int sch(int e, int r) {
  if (((e < 0) || (e >= q)) || ((r < 0) || (r >= q))) {
    return 0;
  }
  int c1 = 0, c, v;
  for (v = 1<<17; v; v >>= 1) {
    c = c1 + v;
    if (c < numV) {
      if ((a1[c] < e) || ((a1[c] == e) && (a2[c] <= r))) {
        c1 = c;
      }
    }
  }
  if ((a1[c1] != e) || (a2[c1] != r)) {
    return 0;
  }
  return 1;
}
void check(int e, int r, int de, int dr) {
  if (sch(e + de, r) + sch(e, r + dr) == 2) {
    lAns1 = (1 + de) / 2;
    lAns2 = (1 + dr) / 2;
  }
}
int main() {
  #ifdef Vlad_kv
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
  #endif // Vlad_kv
  int w, e, r, t;
  for (scanf("%d", &q); q; scanf("%d", &q)) {
    scanf("%d", &numV);
    for (w = 0; w < numV; w++) {
      scanf("%d%d", &s1[w], &s2[w]);
      s1[w]--;
      s2[w]--;
      a1[w] = s1[w];
      a2[w] = s2[w];
    }
    qs2(0, numV - 1);
    for (w = 1; w < numV; w++) {
      if ((s2[w] < s2[0]) || ((s2[w] == s2[0]) && (s1[w] < s1[0]))) {
        swap(s1[w], s1[0]);
        swap(s2[w], s2[0]);
      }
    }
    for (w = 1; w < numV; w++) {
      ld AB = sqrt(sqr(s1[w] - s1[0]) + sqr(s2[w] - s2[0]));
      s[w] = (sqr(AB) + 1 - (sqr(s1[w] - s1[0] - 1) + sqr(s2[w] - s2[0]))) /
             AB;
    }
    qs(1, numV - 1);

    t = 0;
    for (w = 1; w < numV; w++) {
      while (!((t == 0) || (rot(s1[t - 1], s2[t - 1], s1[t], s2[t], s1[w], s2[w]) < -0.1))) {
        t--;
      }
      t++;
      s1[t] = s1[w];
      s2[t] = s2[w];
    }
    t++;

    for (w = 0; w < t; w++) {
      check(s1[w], s2[w], 1, 1);
      check(s1[w], s2[w], 1, -1);
      check(s1[w], s2[w], -1, 1);
      check(s1[w], s2[w], -1, -1);

      d1[w] = s1[w] + lAns1;
      d2[w] = s2[w] + lAns2;
    }

    r = 0;

    for (w = 1; w < t; w++) {
      if ((d1[w] != d1[r]) || (d2[w] != d2[r])) {
        r++;
        d1[r] = d1[w];
        d2[r] = d2[w];
      }
    }
    while ((d1[r] == d1[0]) && (d2[r] == d2[0])) {
      r--;
    }

    t = r + 1;

    r = 0;
    for (e = 1; e < t; e++) {
      if ((d1[e] < d1[r]) || ((d1[e] == d1[r]) && (d2[e] < d2[r]))) {
        r = e;
      }
    }

    cout << t << "\n";
    e = r;
    do {
      printf("%d %d\n", d1[e], d2[e]);
      e++;
      if (e == t) {
        e = 0;
      }
    } while (e != r);

  }
  return 0;
}

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long ll;
char a1[200000], a2[200000];
int s1[200000], s2[200000], d1[200000], d2[200000];

ll rot(ll q, ll w, ll e, ll r, ll t, ll y) {
  return (e - q) * (y - w) - (t - q) * (r - w);
}

int cmp(ll c1, ll c2, ll v1, ll v2) {
  ll S = rot(s1[0], s2[0], c1, c2, v1, v2);
  if (S < 0) {
    return -1;
  }
  if (S > 0) {
    return 1;
  }
  ll len1 = (c1 - s1[0]) * (c1 - s1[0]) + (c2 - s2[0]) * (c2 - s2[0]);
  ll len2 = (v1 - s1[0]) * (v1 - s1[0]) + (v2 - s2[0]) * (v2 - s2[0]);
  if (len1 < len2) {
    return -1;
  }
  if (len1 > len2) {
    return 1;
  }
  return 0;
}
void qs(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  int t1 = s1[y], t2 = s2[y];
  do {
    while (cmp(s1[e], s2[e], t1, t2) < 0) e++;
    while (cmp(s1[r], s2[r], t1, t2) > 0) r--;
    if (e <= r) {
      swap(s1[e], s1[r]);
      swap(s2[e], s2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs(q, r);
  if (e < w) qs(e, w);
}
int cmp2(int c1, int c2, int v1, int v2) {
  if (c1 < v1) {
    return -1;
  }
  if (c1 > v1) {
    return 1;
  }
  if (c2 < v2) {
    return -1;
  }
  if (c2 > v2) {
    return 1;
  }
  return 0;
}
void qs2(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  int t1 = a1[y], t2 = a2[y];
  do {
    while (cmp2(a1[e], a2[e], t1, t2) < 0) e++;
    while (cmp2(a1[r], a2[r], t1, t2) > 0) r--;
    if (e <= r) {
      swap(a1[e], a1[r]);
      swap(a2[e], a2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs2(q, r);
  if (e < w) qs2(e, w);
}

int q, lAns1, lAns2, numV;

int sch(int e, int r) {
  int c1 = 0, c, v;
  for (v = 1<<17; v; v >>= 1) {
    c = c1 + v;
    if ((c < numV) && (cmp2(a1[c], a2[c], e, r) <= 0)) {
      c1 = c;
    }
  }
  if ((a1[c1] != e) || (a2[c1] != r)) {
    return 0;
  }
  return 1;
}
void check(int e, int r, int de, int dr) {
  if (sch(e + de, r) + sch(e, r + dr) == 2) {
    lAns1 = (1 + de) / 2;
    lAns2 = (1 + dr) / 2;
  }
}
int main() {
  #ifdef Vlad_kv
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
  #endif // Vlad_kv
  int w, e, r, t;
  for (scanf("%d", &q); q; scanf("%d", &q)) {
    scanf("%d", &numV);
    for (w = 0; w < numV; w++) {
      scanf("%d%d", &s1[w], &s2[w]);
      s1[w]--;
      s2[w]--;
      a1[w] = s1[w];
      a2[w] = s2[w];
    }
    qs2(0, numV - 1);
    for (w = 1; w < numV; w++) {
      if ((s2[w] < s2[0]) || ((s2[w] == s2[0]) && (s1[w] < s1[0]))) {
        swap(s1[w], s1[0]);
        swap(s2[w], s2[0]);
      }
    }

    qs(1, numV - 1);

    t = 0;
    for (w = 1; w < numV; w++) {
      while (!((t == 0) || (rot(s1[t - 1], s2[t - 1], s1[t], s2[t], s1[w], s2[w]) < 0))) {
        t--;
      }
      t++;
      s1[t] = s1[w];
      s2[t] = s2[w];
    }
    t++;

    for (w = 0; w < t; w++) {
      check(s1[w], s2[w], 1, 1);
      check(s1[w], s2[w], 1, -1);
      check(s1[w], s2[w], -1, 1);
      check(s1[w], s2[w], -1, -1);

      d1[w] = s1[w] + lAns1;
      d2[w] = s2[w] + lAns2;
    }

    r = 0;

    for (w = 1; w < t; w++) {
      if ((d1[w] != d1[r]) || (d2[w] != d2[r])) {
        r++;
        d1[r] = d1[w];
        d2[r] = d2[w];
      }
    }
    while ((d1[r] == d1[0]) && (d2[r] == d2[0])) {
      r--;
    }

    t = r + 1;

    r = 0;
    for (e = 1; e < t; e++) {
      if ((d1[e] < d1[r]) || ((d1[e] == d1[r]) && (d2[e] < d2[r]))) {
        r = e;
      }
    }

    cout << t << "\n";
    e = r;
    do {
      printf("%d %d\n", d1[e], d2[e]);
      e++;
      if (e == t) {
        e = 0;
      }
    } while (e != r);

  }
  return 0;
}

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long double ld;
typedef long long ll;
const ld EPS = 1e-7;
char a1[200000], a2[200000];
int s1[200000], s2[200000], d1[200000], d2[200000];
ld s[200000];
ld sqr(ld w) {
  return w * w;
}
int cmp(ld c1, int c2, int c3, ld v1, int v2, int v3) {
  if (c1 + EPS < v1) {
    return -1;
  }
  if (c1 - EPS > v1) {
    return 1;
  }
  if (c2 > v2) {
    return -1;
  }
  if (c2 < v2) {
    return 1;
  }
  if (c3 < v3) {
    return -1;
  }
  if (c3 > v3) {
    return 1;
  }
  return 0;
}
void qs(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  ld t1 = s[y];
  int t2 = s1[y], t3 = s2[y];
  do {
    while (cmp(s[e], s1[e], s2[e], t1, t2, t3) < 0) e++;
    while (cmp(s[r], s1[r], s2[r], t1, t2, t3) > 0) r--;
    if (e <= r) {
      swap(s[e], s[r]);
      swap(s1[e], s1[r]);
      swap(s2[e], s2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs(q, r);
  if (e < w) qs(e, w);
}
int cmp2(int c1, int c2, int v1, int v2) {
  if (c1 < v1) {
    return -1;
  }
  if (c1 > v1) {
    return 1;
  }
  if (c2 < v2) {
    return -1;
  }
  if (c2 > v2) {
    return 1;
  }
  return 0;
}
void qs2(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  int t1 = a1[y], t2 = a2[y];
  do {
    while (cmp2(a1[e], a2[e], t1, t2) < 0) e++;
    while (cmp2(a1[r], a2[r], t1, t2) > 0) r--;
    if (e <= r) {
      swap(a1[e], a1[r]);
      swap(a2[e], a2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs2(q, r);
  if (e < w) qs2(e, w);
}
ld rot(ld q, ld w, ld e, ld r, ld t, ld y) {
  return (e - q) * (y - w) - (t - q) * (r - w);
}
int q, lAns1, lAns2, numV;

int sch(int e, int r) {
  int c1 = 0, c, v;
  for (v = 1<<17; v; v >>= 1) {
    c = c1 + v;
    if (c < numV) {
      if ((a1[c] < e) || ((a1[c] == e) && (a2[c] <= r))) {
        c1 = c;
      }
    }
  }
  if ((a1[c1] != e) || (a2[c1] != r)) {
    return 0;
  }
  return 1;
}
void check(int e, int r, int de, int dr) {
  if (sch(e + de, r) + sch(e, r + dr) == 2) {
    lAns1 = (1 + de) / 2;
    lAns2 = (1 + dr) / 2;
  }
}
int main() {
  #ifdef Vlad_kv
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
  #endif // Vlad_kv
  int w, e, r, t;
  for (scanf("%d", &q); q; scanf("%d", &q)) {
    scanf("%d", &numV);
    for (w = 0; w < numV; w++) {
      scanf("%d%d", &s1[w], &s2[w]);
      s1[w]--;
      s2[w]--;
      a1[w] = s1[w];
      a2[w] = s2[w];
    }
    qs2(0, numV - 1);
    for (w = 1; w < numV; w++) {
      if ((s2[w] < s2[0]) || ((s2[w] == s2[0]) && (s1[w] < s1[0]))) {
        swap(s1[w], s1[0]);
        swap(s2[w], s2[0]);
      }
    }
    for (w = 1; w < numV; w++) {
      ld AB = sqrt(sqr(s1[w] - s1[0]) + sqr(s2[w] - s2[0]));
      s[w] = (sqr(AB) + 1 - (sqr(s1[w] - s1[0] - 1) + sqr(s2[w] - s2[0]))) /
             AB;
    }
    qs(1, numV - 1);

    t = 0;
    for (w = 1; w < numV; w++) {
      while (!((t == 0) || (rot(s1[t - 1], s2[t - 1], s1[t], s2[t], s1[w], s2[w]) < -0.1))) {
        t--;
      }
      t++;
      s1[t] = s1[w];
      s2[t] = s2[w];
    }
    t++;

    for (w = 0; w < t; w++) {
      check(s1[w], s2[w], 1, 1);
      check(s1[w], s2[w], 1, -1);
      check(s1[w], s2[w], -1, 1);
      check(s1[w], s2[w], -1, -1);

      d1[w] = s1[w] + lAns1;
      d2[w] = s2[w] + lAns2;
    }

    r = 0;

    for (w = 1; w < t; w++) {
      if ((d1[w] != d1[r]) || (d2[w] != d2[r])) {
        r++;
        d1[r] = d1[w];
        d2[r] = d2[w];
      }
    }
    while ((d1[r] == d1[0]) && (d2[r] == d2[0])) {
      r--;
    }

    t = r + 1;

    r = 0;
    for (e = 1; e < t; e++) {
      if ((d1[e] < d1[r]) || ((d1[e] == d1[r]) && (d2[e] < d2[r]))) {
        r = e;
      }
    }

    cout << t << "\n";
    e = r;
    do {
      printf("%d %d\n", d1[e], d2[e]);
      e++;
      if (e == t) {
        e = 0;
      }
    } while (e != r);

  }
  return 0;
}

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long double ld;
typedef long long ll;
char a1[200000], a2[200000];
int s1[200000], s2[200000], d1[200000], d2[200000];
ld s[200000];

ll rot(ll q, ll w, ll e, ll r, ll t, ll y) {
  return (e - q) * (y - w) - (t - q) * (r - w);
}
ld sqr(ld w) {
  return w * w;
}
int cmp(ll c1, ll c2, ll v1, ll v2) {
  ll S = rot(s1[0], s2[0], c1, c2, v1, v2);
  if (S < 0) {
    return -1;
  }
  if (S > 0) {
    return 1;
  }
  if (c1 > v1) {
    return -1;
  }
  if (c1 < v1) {
    return 1;
  }
  if (c2 > v2) {
    return 1;
  }
  if (c2 < v2) {
    return -1;
  }
  return 0;
}
void qs(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  int t1 = s1[y], t2 = s2[y];
  do {
    while (cmp(s1[e], s2[e], t1, t2) < 0) e++;
    while (cmp(s1[r], s2[r], t1, t2) > 0) r--;
    if (e <= r) {
      swap(s1[e], s1[r]);
      swap(s2[e], s2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs(q, r);
  if (e < w) qs(e, w);
}
int cmp2(int c1, int c2, int v1, int v2) {
  if (c1 < v1) {
    return -1;
  }
  if (c1 > v1) {
    return 1;
  }
  if (c2 < v2) {
    return -1;
  }
  if (c2 > v2) {
    return 1;
  }
  return 0;
}
void qs2(int q, int w) {
  int e = q, r = w, y = q + (rand() % (w - q + 1));
  int t1 = a1[y], t2 = a2[y];
  do {
    while (cmp2(a1[e], a2[e], t1, t2) < 0) e++;
    while (cmp2(a1[r], a2[r], t1, t2) > 0) r--;
    if (e <= r) {
      swap(a1[e], a1[r]);
      swap(a2[e], a2[r]);
      e++; r--;
    }
  } while (e <= r);
  if (q < r) qs2(q, r);
  if (e < w) qs2(e, w);
}

int q, lAns1, lAns2, numV;

int sch(int e, int r) {
  int c1 = 0, c, v;
  for (v = 1<<17; v; v >>= 1) {
    c = c1 + v;
    if (c < numV) {
      if ((a1[c] < e) || ((a1[c] == e) && (a2[c] <= r))) {
        c1 = c;
      }
    }
  }
  if ((a1[c1] != e) || (a2[c1] != r)) {
    return 0;
  }
  return 1;
}
void check(int e, int r, int de, int dr) {
  if (sch(e + de, r) + sch(e, r + dr) == 2) {
    lAns1 = (1 + de) / 2;
    lAns2 = (1 + dr) / 2;
  }
}
int main() {
  #ifdef Vlad_kv
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
  #endif // Vlad_kv
  int w, e, r, t;
  for (scanf("%d", &q); q; scanf("%d", &q)) {
    scanf("%d", &numV);
    for (w = 0; w < numV; w++) {
      scanf("%d%d", &s1[w], &s2[w]);
      s1[w]--;
      s2[w]--;
      a1[w] = s1[w];
      a2[w] = s2[w];
    }
    qs2(0, numV - 1);
    for (w = 1; w < numV; w++) {
      if ((s2[w] < s2[0]) || ((s2[w] == s2[0]) && (s1[w] < s1[0]))) {
        swap(s1[w], s1[0]);
        swap(s2[w], s2[0]);
      }
    }

    qs(1, numV - 1);

    t = 0;
    for (w = 1; w < numV; w++) {
      while (!((t == 0) || (rot(s1[t - 1], s2[t - 1], s1[t], s2[t], s1[w], s2[w]) < 0))) {
        t--;
      }
      t++;
      s1[t] = s1[w];
      s2[t] = s2[w];
    }
    t++;

    for (w = 0; w < t; w++) {
      check(s1[w], s2[w], 1, 1);
      check(s1[w], s2[w], 1, -1);
      check(s1[w], s2[w], -1, 1);
      check(s1[w], s2[w], -1, -1);

      d1[w] = s1[w] + lAns1;
      d2[w] = s2[w] + lAns2;
    }

    r = 0;

    for (w = 1; w < t; w++) {
      if ((d1[w] != d1[r]) || (d2[w] != d2[r])) {
        r++;
        d1[r] = d1[w];
        d2[r] = d2[w];
      }
    }
    while ((d1[r] == d1[0]) && (d2[r] == d2[0])) {
      r--;
    }

    t = r + 1;

    r = 0;
    for (e = 1; e < t; e++) {
      if ((d1[e] < d1[r]) || ((d1[e] == d1[r]) && (d2[e] < d2[r]))) {
        r = e;
      }
    }

    cout << t << "\n";
    e = r;
    do {
      printf("%d %d\n", d1[e], d2[e]);
      e++;
      if (e == t) {
        e = 0;
      }
    } while (e != r);

  }
  return 0;
}

#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;

struct vec {
	int x, y;
	vec(int a = 0, int b = 0) {
		x = a;
		y = b;
	}
	int operator * (vec A) {
		return x * A.x + y * A.y;
	}
	int operator % (vec A) {
		return x * A.y - y * A.x;
	}
	vec (vec A, vec B) {
		x = B.x - A.x;
		y = B.y - A.y;
	}
	int leng() {
		return x * x + y * y;
	}
};

// #define x first
// #define y second

vec cmp_vec;

bool cmp(vec A, vec B) {
	if ((vec(cmp_vec, A) % vec(cmp_vec, B)) == 0) {
		return vec(cmp_vec, A).leng() < vec(cmp_vec, B).leng();
	}
	return ((vec(cmp_vec, A) % vec(cmp_vec, B)) < 0);
}

bool cmp1(vec A, vec B) {
	return A.x < B.x || (A.x == B.x && A.y < B.y);
}

void hull(vector <vec> arr) {
	int n = arr.size();
	sort(arr.begin(), arr.end(), cmp1);
	cmp_vec = arr[0];
	sort(arr.begin(), arr.end(), cmp);
	vector <vec> hul({cmp_vec});
	for (auto x : arr) {
		if (x.x == cmp_vec.x && x.y == cmp_vec.y) continue;
		while (hul.size() > 1 and vec(hul[hul.size() - 2], hul.back()) % vec(hul.back(), x) >= 0) {
			hul.pop_back();
		}
		hul.push_back(x);
	}
	cout << hul.size() << endl;
	for (auto x : hul) {
		cout << x.x << " " << x.y << endl;
	}
}
vector <int> max_hor, min_hor;

bool inside(int x, int y) {
	return x <= max_hor[y] && x >= min_hor[y];
}

void sol (int n, int m) {
	set <pair <int, int> > arr;
	max_hor.clear();
	min_hor.clear();
	max_hor.resize(n, -1e9);
	min_hor.resize(n, 1e9);
	for (int i = 0; i < m; i++) {
		int x, y;
		cin >> x >> y;
		x--;
		y--;
		max_hor[y] = max(max_hor[y], x);
		min_hor[y] = min(min_hor[y], x);
		arr.insert(make_pair(x, y));
	}

	// int t[n][n];
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		t[i][j] = 0;
	// 	}
	// }
	// for (auto x : arr) {
	// 	t[x.first][x.second] = 1;
	// }
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		cout << t[i][j];
	// 	}
	// 	cout << endl;
	// }

	set <pair <int, int> > imp;

	for (auto A : arr) {
		int i = A.first;
		int j = A.second;
		// cout << i << " " << j << endl;
		// cout << inside(i + 1, j + 1) << endl;
		if (not inside(i + 1, j + 1) && not inside(i + 1, j) && not inside(i, j + 1) && arr.count({i + 1, j + 1}) + arr.count({i + 1, j}) + arr.count({i, j + 1}) == 0) {
			imp.insert({i, j});
			// cout << "A\n";
		}
		if (not inside(i - 1, j - 1) && not inside(i - 1, j) && not inside(i, j - 1) && arr.count({i - 1, j - 1}) + arr.count({i - 1, j}) + arr.count({i, j - 1}) == 0) {
			imp.insert({i + 1, j + 1});
			// cout << "B\n";
		}
		if (not inside(i, j - 1) && not inside(i + 1, j - 1) && not inside(i + 1, j) && arr.count({i, j - 1}) + arr.count({i + 1, j - 1}) + arr.count({i + 1, j}) == 0) {
			imp.insert({i, j + 1});
			// cout << "C\n";
		}
		if (not inside(i, j + 1) && not inside(i - 1, j) && not inside(i - 1, j + 1) && arr.count({i, j + 1}) + arr.count({i - 1, j}) + arr.count({i - 1, j + 1}) == 0) {
			imp.insert({i + 1, j});
			// cout << "\t" << i + 1 << " " << j << endl;
			// cout << "D\n";
		}
	}
	// cout << endl;
	vector <vec> tohull;
	for (auto x : imp) {
		// cout << x.first << " " << x.second << endl;
		tohull.push_back(vec(x.first, x.second));
	}
	hull(tohull);
}

signed main() {
	int n, m;
	while (cin >> n) {
		cin >> m;
		if (n == 0) break;
		sol(n, m);
	}
}

#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;

struct vec {
	int x, y;
	vec(int a = 0, int b = 0) {
		x = a;
		y = b;
	}
	int operator * (vec A) {
		return x * A.x + y * A.y;
	}
	int operator % (vec A) {
		return x * A.y - y * A.x;
	}
	vec (vec A, vec B) {
		x = B.x - A.x;
		y = B.y - A.y;
	}
	int leng() {
		return x * x + y * y;
	}
};

// #define x first
// #define y second

vec cmp_vec;

bool cmp(vec A, vec B) {
	if ((vec(cmp_vec, A) % vec(cmp_vec, B)) == 0) {
		return vec(cmp_vec, A).leng() < vec(cmp_vec, B).leng();
	}
	return ((vec(cmp_vec, A) % vec(cmp_vec, B)) < 0);
}

bool cmp1(vec A, vec B) {
	return A.x < B.x || (A.x == B.x && A.y < B.y);
}

void hull(vector <vec> arr) {
	int n = arr.size();
	sort(arr.begin(), arr.end(), cmp1);
	cmp_vec = arr[0];
	sort(arr.begin() + 1, arr.end(), cmp);
	vector <vec> hul({cmp_vec});
	for (auto x : arr) {
		if (x.x == cmp_vec.x && x.y == cmp_vec.y) continue;
		while (hul.size() > 1 and vec(hul[hul.size() - 2], hul.back()) % vec(hul.back(), x) >= 0) {
			hul.pop_back();
		}
		hul.push_back(x);
	}
	cout << hul.size() << endl;
	for (auto x : hul) {
		cout << x.x << " " << x.y << endl;
	}
}
vector <int> max_hor, min_hor;

bool inside(int x, int y) {
	return x <= max_hor[y] && x >= min_hor[y];
}

void sol (int n, int m) {
	set <pair <int, int> > arr;
	max_hor.clear();
	min_hor.clear();
	max_hor.resize(n, -1e9);
	min_hor.resize(n, 1e9);
	for (int i = 0; i < m; i++) {
		int x, y;
		cin >> x >> y;
		x--;
		y--;
		max_hor[y] = max(max_hor[y], x);
		min_hor[y] = min(min_hor[y], x);
		arr.insert(make_pair(x, y));
	}

	// int t[n][n];
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		t[i][j] = 0;
	// 	}
	// }
	// for (auto x : arr) {
	// 	t[x.first][x.second] = 1;
	// }
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		cout << t[i][j];
	// 	}
	// 	cout << endl;
	// }

	set <pair <int, int> > imp;

	for (auto A : arr) {
		int i = A.first;
		int j = A.second;
		// cout << i << " " << j << endl;
		// cout << inside(i + 1, j + 1) << endl;
		if (not inside(i + 1, j + 1) && not inside(i + 1, j) && not inside(i, j + 1) && arr.count({i + 1, j + 1}) + arr.count({i + 1, j}) + arr.count({i, j + 1}) == 0) {
			imp.insert({i, j});
			// cout << "A\n";
		}
		if (not inside(i - 1, j - 1) && not inside(i - 1, j) && not inside(i, j - 1) && arr.count({i - 1, j - 1}) + arr.count({i - 1, j}) + arr.count({i, j - 1}) == 0) {
			imp.insert({i + 1, j + 1});
			// cout << "B\n";
		}
		if (not inside(i, j - 1) && not inside(i + 1, j - 1) && not inside(i + 1, j) && arr.count({i, j - 1}) + arr.count({i + 1, j - 1}) + arr.count({i + 1, j}) == 0) {
			imp.insert({i, j + 1});
			// cout << "C\n";
		}
		if (not inside(i, j + 1) && not inside(i - 1, j) && not inside(i - 1, j + 1) && arr.count({i, j + 1}) + arr.count({i - 1, j}) + arr.count({i - 1, j + 1}) == 0) {
			imp.insert({i + 1, j});
			// cout << "\t" << i + 1 << " " << j << endl;
			// cout << "D\n";
		}
	}
	// cout << endl;
	vector <vec> tohull;
	for (auto x : imp) {
		// cout << x.first << " " << x.second << endl;
		tohull.push_back(vec(x.first, x.second));
	}
	hull(tohull);
}

signed main() {
	int n, m;
	while (cin >> n) {
		cin >> m;
		if (n == 0) break;
		sol(n, m);
	}
}

#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;

struct vec {
	int x, y;
	vec(int a = 0, int b = 0) {
		x = a;
		y = b;
	}
	int operator * (vec A) {
		return x * A.x + y * A.y;
	}
	int operator % (vec A) {
		return x * A.y - y * A.x;
	}
	vec (vec A, vec B) {
		x = B.x - A.x;
		y = B.y - A.y;
	}
	int leng() {
		return x * x + y * y;
	}
};

// #define x first
// #define y second

vec cmp_vec;

bool cmp(vec A, vec B) {
	if ((vec(cmp_vec, A) % vec(cmp_vec, B)) == 0) {
		return vec(cmp_vec, A).leng() < vec(cmp_vec, B).leng();
	}
	return ((vec(cmp_vec, A) % vec(cmp_vec, B)) > 0);
}

bool cmp1(vec A, vec B) {
	return A.x < B.x || (A.x == B.x && A.y < B.y);
}

void hull(vector <vec> arr) {
	int n = arr.size();
	sort(arr.begin(), arr.end(), cmp1);
	cmp_vec = arr[0];
	sort(arr.begin() + 1, arr.end(), cmp);
	vector <vec> hul({cmp_vec});
	for (auto x : arr) {
		if (x.x == cmp_vec.x && x.y == cmp_vec.y) continue;
		while (hul.size() > 1 and vec(hul[hul.size() - 2], hul.back()) % vec(hul.back(), x) <= 0) {
			hul.pop_back();
		}
		hul.push_back(x);
	}
	reverse(hul.begin() + 1, hul.end());
	cout << hul.size() << endl;
	for (auto x : hul) {
		cout << x.x << " " << x.y << endl;
	}
}
vector <int> max_hor, min_hor;

bool inside(int x, int y) {
	return x <= max_hor[y] && x >= min_hor[y];
}

void sol (int n, int m) {
	set <pair <int, int> > arr;
	max_hor.clear();
	min_hor.clear();
	max_hor.resize(n, -1e9);
	min_hor.resize(n, 1e9);
	for (int i = 0; i < m; i++) {
		int x, y;
		cin >> x >> y;
		x--;
		y--;
		max_hor[y] = max(max_hor[y], x);
		min_hor[y] = min(min_hor[y], x);
		arr.insert(make_pair(x, y));
	}

	// int t[n][n];
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		t[i][j] = 0;
	// 	}
	// }
	// for (auto x : arr) {
	// 	t[x.first][x.second] = 1;
	// }
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		cout << t[i][j];
	// 	}
	// 	cout << endl;
	// }

	set <pair <int, int> > imp;

	for (auto A : arr) {
		int i = A.first;
		int j = A.second;
		// cout << i << " " << j << endl;
		// cout << inside(i + 1, j + 1) << endl;
		if (not inside(i + 1, j + 1) && not inside(i + 1, j) && not inside(i, j + 1) && arr.count({i + 1, j + 1}) + arr.count({i + 1, j}) + arr.count({i, j + 1}) == 0) {
			imp.insert({i, j});
			// cout << "A\n";
		}
		if (not inside(i - 1, j - 1) && not inside(i - 1, j) && not inside(i, j - 1) && arr.count({i - 1, j - 1}) + arr.count({i - 1, j}) + arr.count({i, j - 1}) == 0) {
			imp.insert({i + 1, j + 1});
			// cout << "B\n";
		}
		if (not inside(i, j - 1) && not inside(i + 1, j - 1) && not inside(i + 1, j) && arr.count({i, j - 1}) + arr.count({i + 1, j - 1}) + arr.count({i + 1, j}) == 0) {
			imp.insert({i, j + 1});
			// cout << "C\n";
		}
		if (not inside(i, j + 1) && not inside(i - 1, j) && not inside(i - 1, j + 1) && arr.count({i, j + 1}) + arr.count({i - 1, j}) + arr.count({i - 1, j + 1}) == 0) {
			imp.insert({i + 1, j});
			// cout << "\t" << i + 1 << " " << j << endl;
			// cout << "D\n";
		}
	}
	// cout << endl;
	vector <vec> tohull;
	for (auto x : imp) {
		// cout << x.first << " " << x.second << endl;
		tohull.push_back(vec(x.first, x.second));
	}
	hull(tohull);
}

signed main() {
	int n, m;
	while (cin >> n) {
		cin >> m;
		if (n == 0) break;
		sol(n, m);
	}
}

#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;

struct vec {
	int x, y;
	vec(int a = 0, int b = 0) {
		x = a;
		y = b;
	}
	int operator * (vec A) {
		return x * A.x + y * A.y;
	}
	int operator % (vec A) {
		return x * A.y - y * A.x;
	}
	vec (vec A, vec B) {
		x = B.x - A.x;
		y = B.y - A.y;
	}
	int leng() {
		return x * x + y * y;
	}
};

// #define x first
// #define y second

vec cmp_vec;

bool cmp(vec A, vec B) {
	if ((vec(cmp_vec, A) % vec(cmp_vec, B)) == 0) {
		return vec(cmp_vec, A).leng() < vec(cmp_vec, B).leng();
	}
	return ((vec(cmp_vec, A) % vec(cmp_vec, B)) < 0);
}

void hull(vector <vec> arr) {
	int n = arr.size();
	cmp_vec = arr[0];
	sort(arr.begin(), arr.end(), cmp);
	vector <vec> hul({cmp_vec});
	for (auto x : arr) {
		if (x.x == cmp_vec.x && x.y == cmp_vec.y) continue;
		while (hul.size() > 1 and vec(hul[hul.size() - 2], hul.back()) % vec(hul.back(), x) >= 0) {
			hul.pop_back();
		}
		hul.push_back(x);
	}
	cout << hul.size() << endl;
	for (auto x : hul) {
		cout << x.x << " " << x.y << endl;
	}
}
vector <int> max_hor, min_hor;

bool inside(int x, int y) {
	return x <= max_hor[y] && x >= min_hor[y];
}

void sol (int n, int m) {
	set <pair <int, int> > arr;
	max_hor.clear();
	min_hor.clear();
	max_hor.resize(n, -1e9);
	min_hor.resize(n, 1e9);
	for (int i = 0; i < m; i++) {
		int x, y;
		cin >> x >> y;
		x--;
		y--;
		max_hor[y] = max(max_hor[y], x);
		min_hor[y] = min(min_hor[y], x);
		arr.insert(make_pair(x, y));
	}

	// int t[n][n];
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		t[i][j] = 0;
	// 	}
	// }
	// for (auto x : arr) {
	// 	t[x.first][x.second] = 1;
	// }
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		cout << t[i][j];
	// 	}
	// 	cout << endl;
	// }

	set <pair <int, int> > imp;

	for (auto A : arr) {
		int i = A.first;
		int j = A.second;
		// cout << i << " " << j << endl;
		// cout << inside(i + 1, j + 1) << endl;
		if (not inside(i + 1, j + 1) && not inside(i + 1, j) && not inside(i, j + 1) && arr.count({i + 1, j + 1}) + arr.count({i + 1, j}) + arr.count({i, j + 1}) == 0) {
			imp.insert({i, j});
			// cout << "A\n";
		}
		if (not inside(i - 1, j - 1) && not inside(i - 1, j) && not inside(i, j - 1) && arr.count({i - 1, j - 1}) + arr.count({i - 1, j}) + arr.count({i, j - 1}) == 0) {
			imp.insert({i + 1, j + 1});
			// cout << "B\n";
		}
		if (not inside(i, j - 1) && not inside(i + 1, j - 1) && not inside(i + 1, j) && arr.count({i, j - 1}) + arr.count({i + 1, j - 1}) + arr.count({i + 1, j}) == 0) {
			imp.insert({i, j + 1});
			// cout << "C\n";
		}
		if (not inside(i, j + 1) && not inside(i - 1, j) && not inside(i - 1, j + 1) && arr.count({i, j + 1}) + arr.count({i - 1, j}) + arr.count({i - 1, j + 1}) == 0) {
			imp.insert({i + 1, j});
			// cout << "\t" << i + 1 << " " << j << endl;
			// cout << "D\n";
		}
	}
	// cout << endl;
	vector <vec> tohull;
	for (auto x : imp) {
		// cout << x.first << " " << x.second << endl;
		tohull.push_back(vec(x.first, x.second));
	}
	hull(tohull);
}

signed main() {
	int n, m;
	while (cin >> n) {
		cin >> m;
		if (n == 0) break;
		sol(n, m);
	}
}

#include <algorithm>
#include <iostream>
#include <vector>
#include <queue>
#include <set>
using namespace std;

struct vec {
	int x, y;
	vec(int a = 0, int b = 0) {
		x = a;
		y = b;
	}
	int operator * (vec A) {
		return x * A.x + y * A.y;
	}
	int operator % (vec A) {
		return x * A.y - y * A.x;
	}
	vec (vec A, vec B) {
		x = B.x - A.x;
		y = B.y - A.y;
	}
	int leng() {
		return x * x + y * y;
	}
};

// #define x first
// #define y second

vec cmp_vec;

bool cmp(vec A, vec B) {
	if ((vec(cmp_vec, A) % vec(cmp_vec, B)) == 0) {
		return vec(cmp_vec, A).leng() < vec(cmp_vec, B).leng();
	}
	return ((vec(cmp_vec, A) % vec(cmp_vec, B)) < 0);
}

void hull(vector <vec> & arr) {
	int n = arr.size();
	cmp_vec = arr[0];
	sort(arr.begin(), arr.end(), cmp);
	vector <vec> hul({cmp_vec});
	for (auto x : arr) {
		if (x.x == cmp_vec.x && x.y == cmp_vec.y) continue;
		while (hul.size() > 1 and vec(hul[hul.size() - 2], hul.back()) % vec(hul.back(), x) >= 0) {
			hul.pop_back();
		}
		hul.push_back(x);
	}
	cout << hul.size() << endl;
	for (auto x : hul) {
		cout << x.x << " " << x.y << endl;
	}
}
vector <int> max_hor, min_hor;

bool inside(int x, int y) {
	return x <= max_hor[y] && x >= min_hor[y];
}

void sol (int n, int m) {
	set <pair <int, int> > arr;
	max_hor.clear();
	min_hor.clear();
	max_hor.resize(n, -1e9);
	min_hor.resize(n, 1e9);
	for (int i = 0; i < m; i++) {
		int x, y;
		cin >> x >> y;
		x--;
		y--;
		max_hor[y] = max(max_hor[y], x);
		min_hor[y] = min(min_hor[y], x);
		arr.insert(make_pair(x, y));
	}

	// int t[n][n];
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		t[i][j] = 0;
	// 	}
	// }
	// for (auto x : arr) {
	// 	t[x.first][x.second] = 1;
	// }
	// for (int i = 0; i < n; i++) {
	// 	for (int j = 0; j < n; j++) {
	// 		cout << t[i][j];
	// 	}
	// 	cout << endl;
	// }

	set <pair <int, int> > imp;

	for (auto A : arr) {
		int i = A.first;
		int j = A.second;
		// cout << i << " " << j << endl;
		// cout << inside(i + 1, j + 1) << endl;
		if (not inside(i + 1, j + 1) && not inside(i + 1, j) && not inside(i, j + 1) && arr.count({i + 1, j + 1}) + arr.count({i + 1, j}) + arr.count({i, j + 1}) == 0) {
			imp.insert({i, j});
			// cout << "A\n";
		}
		if (not inside(i - 1, j - 1) && not inside(i - 1, j) && not inside(i, j - 1) && arr.count({i - 1, j - 1}) + arr.count({i - 1, j}) + arr.count({i, j - 1}) == 0) {
			imp.insert({i + 1, j + 1});
			// cout << "B\n";
		}
		if (not inside(i, j - 1) && not inside(i + 1, j - 1) && not inside(i + 1, j) && arr.count({i, j - 1}) + arr.count({i + 1, j - 1}) + arr.count({i + 1, j}) == 0) {
			imp.insert({i, j + 1});
			// cout << "C\n";
		}
		if (not inside(i, j + 1) && not inside(i - 1, j) && not inside(i - 1, j + 1) && arr.count({i, j + 1}) + arr.count({i - 1, j}) + arr.count({i - 1, j + 1}) == 0) {
			imp.insert({i + 1, j});
			// cout << "\t" << i + 1 << " " << j << endl;
			// cout << "D\n";
		}
	}
	// cout << endl;
	vector <vec> tohull;
	for (auto x : imp) {
		// cout << x.first << " " << x.second << endl;
		tohull.push_back(vec(x.first, x.second));
	}
	hull(tohull);
}

signed main() {
	int n, m;
	while (cin >> n) {
		cin >> m;
		if (n == 0) break;
		sol(n, m);
	}
}

#include <bits/stdc++.h>
using namespace std;
#define repl(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,n) repl(i,0,n)
#define mp(a,b) make_pair((a),(b))
#define pb(a) push_back((a))
#define all(x) (x).begin(),(x).end()
#define uniq(x) sort(all(x)),(x).erase(unique(all(x)),end(x))
#define fi first
#define se second
#define dbg(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
void _dbg(string){cout<<endl;}
template<class H,class... T> void _dbg(string s,H h,T... t){int l=s.find(',');cout<<s.substr(0,l)<<" = "<<h<<", ";_dbg(s.substr(l+1),t...);}
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

#define INF 1120000000
#define EPS 1e-8
#define long long long // for codeforces

using Point = complex<double>;
#define X real()
#define Y imag()
namespace std {
  bool operator<(const Point &a, const Point &b){
    return a.X != b.X ? a.X < b.X : a.Y < b.Y;
  }
}

double cross(Point a, Point b){ return a.X*b.Y - a.Y*b.X; }

vector<Point> GrahamScan(vector<Point> points){
  uniq(points);
  int n = points.size();
  int k=0;
  vector<Point> qs(2*n);
  for(int i=0; i<n; qs[k++] = points[i++]){
    while(k>1 && cross(qs[k-1] - qs[k-2], points[i] - qs[k-1]) <= 0) k--;
  }
  for(int i=n-2,t=k; i>=0; qs[k++] = points[i--]){
    while(k>t && cross(qs[k-1] -qs[k-2], points[i] - qs[k-1]) <= 0) k--;
  }
  qs.resize(k-1);
  return qs;
}

// 凸多角形の内部判定 O(logn)
// 領域内部なら1、境界上なら2、外部なら0
int inConvex(Point p, const vector<Point>& conv){
  int n = conv.size();
  Point g = (conv[0] + conv[n/3] + conv[n*2/3])/3.0;
  if (g == p) return 1;
  Point gp = p - g;

  int l = 0, r = n;
  while(r-l>1){
    int mid = (l+r)/2;
    Point gl = conv[l] - g;
    Point gm = conv[mid] - g;
    if(cross(gl, gm) > 0){
      if(cross(gl, gp) >= 0 && cross(gm, gp) <= 0) r = mid;
      else l = mid;
    }
    else {
      if(cross(gl, gp) <= 0 && cross(gm, gp) >= 0) l = mid;
      else r = mid;
    }
  }
  r %= n;
  double cr = cross(conv[l] - p, conv[r] - p);
  return abs(cr)<EPS ? 2 : cr < 0 ? 0 : 1;
}

void solve(int n, int m){
  vector<Point> p(m);
  rep(i,m){
    int x,y;
    scanf("%d %d", &x, &y);
    x--;y--;
    p[i] = {x,y};
  }

  auto hull = GrahamScan(p);

  auto iszero = [&](int i, int j){
    if(i<0 || i>=n || j<0 || j>=n) return false;
    if(inConvex(Point{i,j}, hull)>0) return false;
    return true;
  };

  vector<Point> cand;

  for(auto po : p) rep(i,2) rep(j,2){
    int x = po.X-i, y = po.Y-j;
    if([&](){
      rep(dx,2)rep(dy,2)if(iszero(x-dx,y-dy)) return false;
      return true;
    }()){
      cand.pb(Point(x,y));
    }
  }

  vector<Point> res = GrahamScan(cand);

  int sz =  res.size();
  printf("%d\n", sz);
  rep(i,sz) printf("%.0f %.0f\n", res[(sz-i)%sz].X, res[(sz-i)%sz].Y);
}

int main(){
  int n,m;
  while(cin>>n>>m, n|m){
    solve(n,m);
  }

  return 0;
}

#include <bits/stdc++.h>
using namespace std;

const int MAX = (int)1E5 + 10;
const int dx[] = {0, 0, -1, -1};
const int dy[] = {-1, 0, -1, 0};

int n, m, cookie;
set<pair<int, int> > A;
int touch[MAX], minr[MAX], maxr[MAX];
vector<pair<int, int> > cv;

bool is_four(int x, int y){
    if(x < 1 || x > n) return false;
    if(touch[x] != cookie) return false;
    if(A.find(make_pair(x, y)) != A.end()) return false;
    return minr[x] <= y && y <= maxr[x];
}

long long sqr(int a){
    return a*a;
}

long long dist(const pair<int, int>& a, const pair<int, int>& b){
    return sqr(a.first - b.first) + sqr(a.second - b.second);
}

long long ccw(const pair<int, int>& o, const pair<int, int>& a, const pair<int, int>& b){
    return (a.first - o.first)*(b.second - o.second) - (a.second - o.second)*(b.first - o.first);
}

bool cmp(const pair<int, int>& l, const pair<int, int>& r){
    int c = ccw(cv[0], l, r);
    return c < 0 || (c == 0 && dist(cv[0], l) < dist(cv[0], r));
}

void graham_scan(){
    for(int i = 1; i < (int)cv.size(); i++)
    if(cv[i].first < cv[0].first || (cv[i].first == cv[0].first && cv[i].second < cv[0].second)) swap(cv[i], cv[0]);

    sort(cv.begin() + 1, cv.end(), cmp);
    cv.push_back(cv[0]);
    int top = 1;
    for(int i = 2; i < (int)cv.size(); i++){
        while(top > 0 && ccw(cv[top - 1], cv[top], cv[i]) >= 0) top--;
        cv[++top] = cv[i];
    }
    cv.resize(top);
}

int main(){
    while(true){
        A.clear();
        cv.resize(0);

        scanf("%d%d", &n, &m);
        if(n == 0 && m == 0) break;

        cookie++;

        for(int i = 0; i < m; i++){
            int x, y; scanf("%d%d", &x, &y);
            A.insert(make_pair(x, y));

            if(touch[x] != cookie){
                touch[x] = cookie;
                minr[x] = y;
                maxr[x] = y;
            }

            minr[x] = min(minr[x], y);
            maxr[x] = max(maxr[x], y);
        }

        for(auto a : A){
            for(int i = 0; i < 4; i++){
                int x = a.first + dx[i];
                int y = a.second + dy[i];
                if(is_four(x, y)) A.insert(make_pair(x, y));
            }
        }

        for(auto a : A)
        if(A.find(make_pair(a.first + 1, a.second)) != A.end()
        && A.find(make_pair(a.first, a.second + 1)) != A.end()
        && A.find(make_pair(a.first + 1, a.second + 1)) != A.end()) cv.push_back(a);

        graham_scan();

        printf("%d\n", (int)cv.size());
        for(auto v : cv) printf("%d %d\n", v.first, v.second);
    }
}

#include <bits/stdc++.h>
using namespace std;

const int MAX = (int)1E5 + 10;
const int dx[] = {0, 0, -1, -1};
const int dy[] = {-1, 0, -1, 0};

int n, m, cookie;
set<pair<int, int> > A;
int touch[MAX], minr[MAX], maxr[MAX];
vector<pair<int, int> > cv;

bool is_four(int x, int y){
    if(x < 1 || x > n) return false;
    if(touch[x] != cookie) return false;
    if(A.find(make_pair(x, y)) != A.end()) return false;
    return minr[x] <= y && y <= maxr[x];
}

long long sqr(int a){
    return a*a;
}

long long dist(const pair<int, int>& a, const pair<int, int>& b){
    return sqr(a.first - b.first) + sqr(a.second - b.second);
}

long long ccw(const pair<int, int>& o, const pair<int, int>& a, const pair<int, int>& b){
    return (a.first - o.first)*(b.second - o.second) - (a.second - o.second)*(b.first - o.first);
}

bool cmp(const pair<int, int>& l, const pair<int, int>& r){
    int c = ccw(cv[0], l, r);
    return c < 0 || (c == 0 && dist(cv[0], l) < dist(cv[0], r));
}

void graham_scan(){
    for(int i = 1; i < n; i++)
    if(cv[i].first < cv[0].first || (cv[i].first == cv[0].first && cv[i].second < cv[0].second)) swap(cv[i], cv[0]);

    sort(cv.begin() + 1, cv.end(), cmp);
    cv.push_back(cv[0]);
    int top = 1;
    for(int i = 2; i < (int)cv.size(); i++){
        while(top > 0 && ccw(cv[top - 1], cv[top], cv[i]) >= 0) top--;
        cv[++top] = cv[i];
    }
    cv.resize(top);
}

int main(){
    while(true){
        A.clear();
        cv.resize(0);

        scanf("%d%d", &n, &m);
        if(n == 0 && m == 0) break;

        cookie++;

        for(int i = 0; i < m; i++){
            int x, y; scanf("%d%d", &x, &y);
            A.insert(make_pair(x, y));

            if(touch[x] != cookie){
                touch[x] = cookie;
                minr[x] = y;
                maxr[x] = y;
            }

            minr[x] = min(minr[x], y);
            maxr[x] = max(maxr[x], y);
        }

        for(auto a : A){
            for(int i = 0; i < 4; i++){
                int x = a.first + dx[i];
                int y = a.second + dy[i];
                if(is_four(x, y)) A.insert(make_pair(x, y));
            }
        }

        for(auto a : A)
        if(A.find(make_pair(a.first + 1, a.second)) != A.end()
        && A.find(make_pair(a.first, a.second + 1)) != A.end()
        && A.find(make_pair(a.first + 1, a.second + 1)) != A.end()) cv.push_back(a);

        graham_scan();

        printf("%d\n", (int)cv.size());
        for(auto v : cv) printf("%d %d\n", v.first, v.second);
    }
}

#include <bits/stdc++.h>
using namespace std;

const int MAX = (int)1E5 + 10;
const int dx[] = {0, -1, 0, 1};
const int dy[] = {-1, 0, 1, 0};

int n, m, cookie;
set<pair<int, int> > A, B;
int touch[MAX], minr[MAX], maxr[MAX];
vector<pair<int, int> > cv;

bool is_four(int x, int y){
    if(x < 1 || x > n) return false;
    if(touch[x] != cookie) return false;
    if(A.find(make_pair(x, y)) != A.end()) return false;
    return minr[x] <= y && y <= maxr[x];
}

long long sqr(int a){
    return a*a;
}

long long dist(const pair<int, int>& a, const pair<int, int>& b){
    return sqr(a.first - b.first) + sqr(a.second - b.second);
}

long long ccw(const pair<int, int>& o, const pair<int, int>& a, const pair<int, int>& b){
    return (a.first - o.first)*(b.second - o.second) - (a.second - o.second)*(b.first - o.first);
}

bool cmp(const pair<int, int>& l, const pair<int, int>& r){
    int c = ccw(cv[0], l, r);
    return c < 0 || (c == 0 && dist(cv[0], l) < dist(cv[0], r));
}

void graham_scan(){
    for(int i = 1; i < (int)cv.size(); i++)
    if(cv[i].first < cv[0].first || (cv[i].first == cv[0].first && cv[i].second < cv[0].second)) swap(cv[i], cv[0]);

    sort(cv.begin() + 1, cv.end(), cmp);
    cv.push_back(cv[0]);
    int top = 1;
    for(int i = 2; i < (int)cv.size(); i++){
        while(top > 0 && ccw(cv[top - 1], cv[top], cv[i]) >= 0) top--;
        cv[++top] = cv[i];
    }
    cv.resize(top);
}

int main(){
    while(true){
        A.clear();
        B.clear();
        cv.resize(0);

        scanf("%d%d", &n, &m);
        if(n == 0 && m == 0) break;

        cookie++;

        for(int i = 0; i < m; i++){
            int x, y; scanf("%d%d", &x, &y);
            A.insert(make_pair(x, y));

            if(touch[x] != cookie){
                touch[x] = cookie;
                minr[x] = y;
                maxr[x] = y;
            }

            minr[x] = min(minr[x], y);
            maxr[x] = max(maxr[x], y);
        }

        for(auto a : A){
            for(int i = 0; i < 4; i++){
                int x = a.first + dx[i];
                int y = a.second + dy[i];
                if(is_four(x, y)) B.insert(make_pair(x, y));
            }
        }

        for(auto b : B) A.insert(b);

        for(auto a : A)
        if(A.find(make_pair(a.first + 1, a.second)) != A.end()
        && A.find(make_pair(a.first, a.second + 1)) != A.end()
        && A.find(make_pair(a.first + 1, a.second + 1)) != A.end()){
            cv.push_back(a);
        }

        graham_scan();

        printf("%d\n", (int)cv.size());
        for(auto v : cv) printf("%d %d\n", v.first, v.second);
    }
}

#include <bits/stdc++.h>
using namespace std;

const int MAX = (int)1E5 + 10;
const int dx[] = {0, -1, 0, 1};
const int dy[] = {-1, 0, 1, 0};

int n, m, cookie;
set<pair<int, int> > A, B;
int touch[MAX], minr[MAX], maxr[MAX];
vector<pair<int, int> > cv;

bool is_four(int x, int y){
    if(x < 1 || x > n) return false;
    if(touch[x] != cookie) return false;
    if(A.find(make_pair(x, y)) != A.end()) return false;
    return minr[x] <= y && y <= maxr[x];
}

long long sqr(int a){
    return a*a;
}

long long dist(const pair<int, int>& a, const pair<int, int>& b){
    return sqr(a.first - b.first) + sqr(a.second - b.second);
}

long long ccw(const pair<int, int>& o, const pair<int, int>& a, const pair<int, int>& b){
    return (long long)(a.first - o.first)*(b.second - o.second) - (long long)(a.second - o.second)*(b.first - o.first);
}

bool cmp(const pair<int, int>& l, const pair<int, int>& r){
    int c = ccw(cv[0], l, r);
    return c < 0 || (c == 0 && dist(cv[0], l) < dist(cv[0], r));
}

void graham_scan(){
    for(int i = 1; i < (int)cv.size(); i++)
    if(cv[i].first < cv[0].first || (cv[i].first == cv[0].first && cv[i].second < cv[0].second)) swap(cv[i], cv[0]);

    sort(cv.begin() + 1, cv.end(), cmp);
    cv.push_back(cv[0]);
    int top = 1;
    for(int i = 2; i < (int)cv.size(); i++){
        while(top > 0 && ccw(cv[top - 1], cv[top], cv[i]) >= 0) top--;
        cv[++top] = cv[i];
    }
    cv.resize(top);
}

int main(){
    while(true){
        A.clear();
        B.clear();
        cv.resize(0);

        scanf("%d%d", &n, &m);
        if(n == 0 && m == 0) break;

        cookie++;

        for(int i = 0; i < m; i++){
            int x, y; scanf("%d%d", &x, &y);
            A.insert(make_pair(x, y));

            if(touch[x] != cookie){
                touch[x] = cookie;
                minr[x] = y;
                maxr[x] = y;
            }

            minr[x] = min(minr[x], y);
            maxr[x] = max(maxr[x], y);
        }

        for(auto a : A){
            for(int i = 0; i < 4; i++){
                int x = a.first + dx[i];
                int y = a.second + dy[i];
                if(is_four(x, y)) B.insert(make_pair(x, y));
            }
        }

        for(auto b : B) A.insert(b);

        for(auto a : A)
        if(A.find(make_pair(a.first + 1, a.second)) != A.end()
        && A.find(make_pair(a.first, a.second + 1)) != A.end()
        && A.find(make_pair(a.first + 1, a.second + 1)) != A.end()){
            cv.push_back(a);
        }

        graham_scan();

        printf("%d\n", (int)cv.size());
        for(auto v : cv) printf("%d %d\n", v.first, v.second);
    }
}

#include <bits/stdc++.h>
using namespace std;

const int MAX = (int)1E5 + 10;
const int dx[] = {0, -1, 1, 1};
const int dy[] = {-1, 0, 0, 0};

int n, m, cookie;
set<pair<int, int> > A;
int touch[MAX], minr[MAX], maxr[MAX];
vector<pair<int, int> > cv;

bool is_four(int x, int y){
    if(x < 1 || x > n) return false;
    if(touch[x] != cookie) return false;
    return minr[x] <= y && y <= maxr[x];
}

long long sqr(int a){
    return a*a;
}

long long dist(const pair<int, int>& a, const pair<int, int>& b){
    return sqr(a.first - b.first) + sqr(a.second - b.second);
}

long long ccw(const pair<int, int>& o, const pair<int, int>& a, const pair<int, int>& b){
    return (a.first - o.first)*(b.second - o.second) - (a.second - o.second)*(b.first - o.first);
}

bool cmp(const pair<int, int>& l, const pair<int, int>& r){
    int c = ccw(cv[0], l, r);
    return c < 0 || (c == 0 && dist(cv[0], l) < dist(cv[0], r));
}

void graham_scan(){
    for(int i = 1; i < (int)cv.size(); i++)
    if(cv[i].first < cv[0].first || (cv[i].first == cv[0].first && cv[i].second < cv[0].second)) swap(cv[i], cv[0]);

    sort(cv.begin() + 1, cv.end(), cmp);
    cv.push_back(cv[0]);
    int top = 1;
    for(int i = 2; i < (int)cv.size(); i++){
        while(top > 0 && ccw(cv[top - 1], cv[top], cv[i]) >= 0) top--;
        cv[++top] = cv[i];
    }
    cv.resize(top);
}

int main(){
    while(true){
        A.clear();
        cv.resize(0);

        scanf("%d%d", &n, &m);
        if(n == 0 && m == 0) break;

        cookie++;

        for(int i = 0; i < m; i++){
            int x, y; scanf("%d%d", &x, &y);
            A.insert(make_pair(x, y));

            if(touch[x] != cookie){
                touch[x] = cookie;
                minr[x] = y;
                maxr[x] = y;
            }

            minr[x] = min(minr[x], y);
            maxr[x] = max(maxr[x], y);
        }

        for(auto a : A){
            for(int i = 0; i < 4; i++){
                int x = a.first + dx[i];
                int y = a.second + dy[i];
                if(is_four(x, y)) A.insert(make_pair(x, y));
            }
        }

        cout << is_four(4, 5) << (A.find(make_pair(4, 5)) != A.end()) << endl;

        for(auto a : A)
        if(A.find(make_pair(a.first + 1, a.second)) != A.end()
        && A.find(make_pair(a.first, a.second + 1)) != A.end()
        && A.find(make_pair(a.first + 1, a.second + 1)) != A.end()){
            cv.push_back(a);
            cout << a.first << " " << a.second << endl;
        }

        graham_scan();

        printf("%d\n", (int)cv.size());
        for(auto v : cv) printf("%d %d\n", v.first, v.second);
    }
}

#include <bits/stdc++.h>
using namespace std;

const int MAX = (int)1E5 + 10;
const int dx[] = {0, -1, 1, 1};
const int dy[] = {-1, 0, 0, 0};

int n, m, cookie;
set<pair<int, int> > A, B;
int touch[MAX], minr[MAX], maxr[MAX];
vector<pair<int, int> > cv;

bool is_four(int x, int y){
    if(x < 1 || x > n) return false;
    if(touch[x] != cookie) return false;
    if(A.find(make_pair(x, y)) != A.end()) return false;
    return minr[x] <= y && y <= maxr[x];
}

long long sqr(int a){
    return a*a;
}

long long dist(const pair<int, int>& a, const pair<int, int>& b){
    return sqr(a.first - b.first) + sqr(a.second - b.second);
}

long long ccw(const pair<int, int>& o, const pair<int, int>& a, const pair<int, int>& b){
    return (a.first - o.first)*(b.second - o.second) - (a.second - o.second)*(b.first - o.first);
}

bool cmp(const pair<int, int>& l, const pair<int, int>& r){
    int c = ccw(cv[0], l, r);
    return c < 0 || (c == 0 && dist(cv[0], l) < dist(cv[0], r));
}

void graham_scan(){
    for(int i = 1; i < (int)cv.size(); i++)
    if(cv[i].first < cv[0].first || (cv[i].first == cv[0].first && cv[i].second < cv[0].second)) swap(cv[i], cv[0]);

    sort(cv.begin() + 1, cv.end(), cmp);
    cv.push_back(cv[0]);
    int top = 1;
    for(int i = 2; i < (int)cv.size(); i++){
        while(top > 0 && ccw(cv[top - 1], cv[top], cv[i]) >= 0) top--;
        cv[++top] = cv[i];
    }
    cv.resize(top);
}

int main(){
    while(true){
        A.clear();
        B.clear();
        cv.resize(0);

        scanf("%d%d", &n, &m);
        if(n == 0 && m == 0) break;

        cookie++;

        for(int i = 0; i < m; i++){
            int x, y; scanf("%d%d", &x, &y);
            A.insert(make_pair(x, y));

            if(touch[x] != cookie){
                touch[x] = cookie;
                minr[x] = y;
                maxr[x] = y;
            }

            minr[x] = min(minr[x], y);
            maxr[x] = max(maxr[x], y);
        }

        for(auto a : A){
            for(int i = 0; i < 4; i++){
                int x = a.first + dx[i];
                int y = a.second + dy[i];
                if(is_four(x, y)) B.insert(make_pair(x, y));
            }
        }

        for(auto b : B) A.insert(b);

        for(auto a : A)
        if(A.find(make_pair(a.first + 1, a.second)) != A.end()
        && A.find(make_pair(a.first, a.second + 1)) != A.end()
        && A.find(make_pair(a.first + 1, a.second + 1)) != A.end()){
            cv.push_back(a);
        }

        graham_scan();

        printf("%d\n", (int)cv.size());
        for(auto v : cv) printf("%d %d\n", v.first, v.second);
    }
}

#include <bits/stdc++.h>
using namespace std;

const int MAX = (int)1E5 + 10;
const int dx[] = {0, -1, 0, 1};
const int dy[] = {-1, 0, 1, 0};

int n, m, cookie;
set<pair<int, int> > A, B;
int touch[MAX], minr[MAX], maxr[MAX];
vector<pair<int, int> > cv;

bool is_four(int x, int y){
    if(x < 1 || x > n) return false;
    if(touch[x] != cookie) return false;
    if(A.find(make_pair(x, y)) != A.end()) return false;
    return minr[x] <= y && y <= maxr[x];
}

long long sqr(int a){
    return a*a;
}

long long dist(const pair<int, int>& a, const pair<int, int>& b){
    return sqr(a.first - b.first) + sqr(a.second - b.second);
}

long long ccw(const pair<int, int>& o, const pair<int, int>& a, const pair<int, int>& b){
    return (long long)(a.first - o.first)*(b.second - o.second) - (long long)(a.second - o.second)*(b.first - o.first);
}

bool cmp(const pair<int, int>& l, const pair<int, int>& r){
    long long c = ccw(cv[0], l, r);
    return c < 0 || (c == 0 && dist(cv[0], l) < dist(cv[0], r));
}

void graham_scan(){
    for(int i = 1; i < (int)cv.size(); i++)
    if(cv[i].first < cv[0].first || (cv[i].first == cv[0].first && cv[i].second < cv[0].second)) swap(cv[i], cv[0]);

    sort(cv.begin() + 1, cv.end(), cmp);
    cv.push_back(cv[0]);
    int top = 1;
    for(int i = 2; i < (int)cv.size(); i++){
        while(top > 0 && ccw(cv[top - 1], cv[top], cv[i]) >= 0) top--;
        cv[++top] = cv[i];
    }
    cv.resize(top);
}

int main(){
    while(true){
        A.clear();
        B.clear();
        cv.resize(0);

        scanf("%d%d", &n, &m);
        if(n == 0 && m == 0) break;

        cookie++;

        for(int i = 0; i < m; i++){
            int x, y; scanf("%d%d", &x, &y);
            A.insert(make_pair(x, y));

            if(touch[x] != cookie){
                touch[x] = cookie;
                minr[x] = y;
                maxr[x] = y;
            }

            minr[x] = min(minr[x], y);
            maxr[x] = max(maxr[x], y);
        }

        for(auto a : A){
            for(int i = 0; i < 4; i++){
                int x = a.first + dx[i];
                int y = a.second + dy[i];
                if(is_four(x, y)) B.insert(make_pair(x, y));
            }
        }

        for(auto b : B) A.insert(b);

        for(auto a : A)
        if(A.find(make_pair(a.first + 1, a.second)) != A.end()
        && A.find(make_pair(a.first, a.second + 1)) != A.end()
        && A.find(make_pair(a.first + 1, a.second + 1)) != A.end()){
            cv.push_back(a);
        }

        graham_scan();

        printf("%d\n", (int)cv.size());
        for(auto v : cv) printf("%d %d\n", v.first, v.second);
    }
}

#include <string>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <iostream>
#include <sstream>
#include <cstring>
#include <numeric>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define F0(i,n) for (int i = 0; i < n; i++)
#define F1(i,n) for (int i = 1; i <= n; i++)
#define CL(a,x) memset(x, a, sizeof(x));
#define SZ(x) ((int)x.size())
const double eps = 1e-10;
const int inf = 1000000009;
int i, j, k, m, n, l;
int ans;
string s[505];

pii head;
int cc(pii A, pii B) {
	A.first -= head.first; A.second -= head.second;
	B.first -= head.first; B.second -= head.second;
	if (A.first * B.second != A.second * B.first) return A.first * B.second < A.second * B.first;
	return A.first * A.first + A.second * A.second < B.first * B.first + B.second * B.second;
}

int cmp(pii head, pii A, pii B) {
	A.first -= head.first; A.second -= head.second;
	B.first -= head.first; B.second -= head.second;
	return A.first * B.second - A.second * B.first;
}

int main() {
	//freopen("x.in", "r", stdin);

	while (1) {
		cin >> n; if (n == 0) break;

		vector<pii> a;

		/*
		F0(i, n) cin >> s[n - i - 1];
		F0(i, n) F0(j, n) if (s[i][j] != '0' && s[i][j] != '4') {
			a.push_back(pii(j, i));
		}*/
		cin >> m;
		while (m--) {
			scanf("%d%d", &i, &j);
			a.push_back(pii(i - 1, j - 1));
		}

		set<pii> S(a.begin(), a.end());

		sort(a.begin(), a.end());
		F0(i, SZ(a) - 1) if (a[i].first == a[i + 1].first) {
			if (a[i].second + 1 < a[i + 1].second) S.insert(pii(a[i].first, a[i].second + 1));
			if (a[i].second + 2 < a[i + 1].second) S.insert(pii(a[i].first, a[i + 1].second - 1));
		}
		F0(i, SZ(a)) swap(a[i].first, a[i].second);
		sort(a.begin(), a.end());
		F0(i, SZ(a) - 1) if (a[i].first == a[i + 1].first) {
			if (a[i].second + 1 < a[i + 1].second) S.insert(pii(a[i].second + 1, a[i].first));
			if (a[i].second + 2 < a[i + 1].second) S.insert(pii(a[i + 1].second - 1, a[i].first));
		}

		vector<pii> p;
		for (auto& x : S) {
			if (S.count(pii(x.first + 1, x.second)) &&
				S.count(pii(x.first + 1, x.second + 1)) &&
				S.count(pii(x.first, x.second + 1))) p.push_back(pii(x.first + 1, x.second + 1));
		}

		int k = 0;
		F0(i, SZ(p)) if (p[i] < p[k]) k = i;
		swap(p[k], p[0]);
		head = p[0];
		sort(p.begin() + 1, p.end(), cc);
		vector<pii> w;
		w.push_back(p[0]);
		for (int i = 1; i < SZ(p); i++) {
			while (w.size() >= 2 && cmp(w[SZ(w) - 2], w[SZ(w) - 1], p[i]) >= 0) w.pop_back();
			w.push_back(p[i]);
		}

		cout << SZ(w) << endl;
		F0(i, SZ(w)) cout << w[i].first << " " << w[i].second << endl;
	}

	return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define uint unsigned
#define pii pair<int,int>
#define pll pair<ll,ll>
#define IT iterator
#define PB push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define CLR(a,v) memset(a,v,sizeof(a));
#define CPY(a,b) memcpy(a,b,sizeof(a));
#define debug puts("wzpakking")
#define y1 ysghysgsygsh
using namespace std;
const int d1[4][2]={{0,1},{-1,0},{0,-1},{1,0}};
const int d2[4][2]={{1,1},{-1,1},{-1,-1},{1,-1}};
const int d3[4][2]={{0,0},{-1,0},{-1,-1},{0,-1}};
const int N=200005;
int n,m,top,ok[4];
map<int,int> mn,mx;
struct P{
	int x,y;
	P(){}
	P(int _x,int _y){
		x=_x; y=_y;
	}
	P operator +(const P &a)const{
		return P(x+a.x,y+a.y);
	}
	P operator -(const P &a)const{
		return P(x-a.x,y-a.y);
	}
	ll operator *(const P &a)const{
		return 1ll*x*a.y-1ll*y*a.x;
	}
	bool operator <(const P &a)const{
		return x==a.x?y<a.y:x<a.x;
	}
	bool operator ==(const P &a)const{
		return x==a.x&&y==a.y;
	}
	ll dis(){
		return 1ll*x*x+1ll*y*y;
	}
}a[N],q[N*4];
bool cmp(P x,P y){
	if (x*y) return x*y>0;
	return x.dis()>y.dis();
}
void Convex_hull(){
	sort(q+1,q+top+1);
	top=unique(q+1,q+top+1)-q-1;
	P bas=a[1];
	//For(i,1,top) cout<<q[i].x<<' '<<q[i].y<<endl;
	For(i,1,top) q[i]=q[i]-bas;
	sort(q+2,q+top+1,cmp);
	//For(i,1,top) cout<<q[i].x<<' '<<q[i].y<<endl;
	n=top; top=1;
	For(i,2,n){
		for (;top>=2&&(q[top]-q[top-1])*(q[i]-q[top])<=0;top--);
		q[++top]=q[i];
	}
	For(i,1,top)
		q[i]=q[i]+bas;
}
bool chk(int x,int y){
	if (mn.find(x)==mn.end()) return 0;
	return mn[x]<=y&&mx[x]>=y;
}
void solve(){
	top=0;
	scanf("%d%d",&n,&m);
	if (!(n+m)) exit(0);
	mn.clear(); mx.clear();
	For(i,1,m) scanf("%d%d",&a[i].x,&a[i].y);
	For(i,1,m) mn[a[i].x]=n+1,mx[a[i].x]=1;
	For(i,1,m){
		mn[a[i].x]=min(mn[a[i].x],a[i].y);
		mx[a[i].x]=max(mx[a[i].x],a[i].y);
	}
	For(i,1,m){
		ok[0]=ok[1]=ok[2]=ok[3]=1;
		For(j,0,3)
			if (!chk(a[i].x+d1[j][0],a[i].y+d1[j][1]))
				ok[j]=ok[(j+1)%4]=0;
		For(j,0,3)
			if (!chk(a[i].x+d2[j][0],a[i].y+d2[j][1]))
				ok[j]=0;
		For(j,0,3) if (ok[j])
			q[++top]=P(a[i].x+d3[j][0],a[i].y+d3[j][1]);
	}
	//cout<<top<<endl;
	Convex_hull();
	reverse(q+2,q+top+1);
	printf("%d\n",top);
	For(i,1,top) printf("%d %d\n",q[i].x,q[i].y);
}
int main(){
	for (;;) solve();
}

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define uint unsigned
#define pii pair<int,int>
#define pll pair<ll,ll>
#define IT iterator
#define PB push_back
#define fi first
#define se second
#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define CLR(a,v) memset(a,v,sizeof(a));
#define CPY(a,b) memcpy(a,b,sizeof(a));
#define debug puts("wzpakking")
#define y1 ysghysgsygsh
using namespace std;
const int d1[4][2]={{0,1},{0,-1},{-1,0},{0,1}};
const int d2[4][2]={{1,1},{-1,1},{-1,-1},{1,-1}};
const int d3[4][2]={{0,0},{-1,0},{-1,-1},{0,-1}};
const int N=200005;
int n,m,top,ok[4];
map<int,int> mn,mx;
struct P{
	int x,y;
	P(){}
	P(int _x,int _y){
		x=_x; y=_y;
	}
	P operator +(const P &a)const{
		return P(x+a.x,y+a.y);
	}
	P operator -(const P &a)const{
		return P(x-a.x,y-a.y);
	}
	ll operator *(const P &a)const{
		return 1ll*x*a.y-1ll*y*a.x;
	}
	bool operator <(const P &a)const{
		return x==a.x?y<a.y:x<a.x;
	}
	bool operator ==(const P &a)const{
		return x==a.x&&y==a.y;
	}
	ll dis(){
		return 1ll*x*x+1ll*y*y;
	}
}a[N],q[N*4];
bool cmp(P x,P y){
	if (x*y) return x*y>0;
	return x.dis()>y.dis();
}
void Convex_hull(){
	sort(q+1,q+top+1);
	top=unique(q+1,q+top+1)-q-1;
	P bas=a[1];
	//For(i,1,top) cout<<q[i].x<<' '<<q[i].y<<endl;
	For(i,1,top) q[i]=q[i]-bas;
	sort(q+2,q+top+1,cmp);
	//For(i,1,top) cout<<q[i].x<<' '<<q[i].y<<endl;
	n=top; top=1;
	For(i,2,n){
		for (;top>=2&&(q[top]-q[top-1])*(q[i]-q[top])<=0;top--);
		q[++top]=q[i];
	}
	For(i,1,top)
		q[i]=q[i]+bas;
}
bool chk(int x,int y){
	if (mn.find(x)==mn.end()) return 0;
	return mn[x]<=y&&mx[x]>=y;
}
void solve(){
	top=0;
	scanf("%d%d",&n,&m);
	if (!(n+m)) exit(0);
	mn.clear(); mx.clear();
	For(i,1,m) scanf("%d%d",&a[i].x,&a[i].y);
	For(i,1,m) mn[a[i].x]=n+1,mx[a[i].x]=1;
	For(i,1,m){
		mn[a[i].x]=min(mn[a[i].x],a[i].y);
		mx[a[i].x]=max(mx[a[i].x],a[i].y);
	}
	For(i,1,m){
		ok[0]=ok[1]=ok[2]=ok[3]=1;
		For(j,0,3)
			if (!chk(a[i].x+d1[j][0],a[i].y+d1[j][1]))
				ok[j]=ok[(j+1)%4]=0;
		For(j,0,3)
			if (!chk(a[i].x+d2[j][0],a[i].y+d2[j][1]))
				ok[j]=0;
		For(j,0,3) if (ok[j])
			q[++top]=P(a[i].x+d3[j][0],a[i].y+d3[j][1]);
	}
	cout<<top<<endl;
	Convex_hull();
	printf("%d\n",top);
	For(i,1,top) printf("%d %d\n",q[i].x,q[i].y);
}
int main(){
	for (;;) solve();
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;
vector<int> ys[100010];

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
	memset(ys,0,sizeof(ys));
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
			ys[x[i]].push_back(y[i]);
		}

		for(int i=0;i<=n+1;i++){
			sort(ys[i].begin(),ys[i].end());
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				if(mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					/*if(dist2(cx,cy,newx+0.5,newy+0.5) < dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}*/

					if(ys[x[i]][0] == y[i] || ys[x[i]][ys[x[i]].size()-1] == y[i]){
						list[sz++] = point(newx,newy);
					}

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

ll cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x+0LL)*(p2.y-p0.y)-(p1.y-p0.y+0LL)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;
vector<int> ys[100010];
vector<int> xs[100010];

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
	memset(xs,0,sizeof(xs));
	memset(ys,0,sizeof(ys));
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
			xs[y[i]].push_back(x[i]);
			ys[x[i]].push_back(y[i]);
		}

		for(int i=0;i<=n+1;i++){
			sort(xs[i].begin(),xs[i].end());
			sort(ys[i].begin(),ys[i].end());
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				bool f1 = (ys[x[i]][0] == y[i] || ys[x[i]][ys[x[i]].size()-1] == y[i]);
				bool f2 = (xs[y[i]][0] == x[i] || xs[y[i]][xs[y[i]].size()-1] == x[i]);
				if( (f1 || f2) && mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					/*if(n==50000){
						if(newx == 12 && newy== 49894){
							cout<<"YES"<<endl;
						}
					}*/

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					/*if(dist2(cx,cy,newx+0.5,newy+0.5) < dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}*/

					list[sz++] = point(newx,newy);

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				if(mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					if(dist2(cx,cy,newx,newy) < dist2(cx,cy,cmpx,cmpy)){
						//cout<<newx<<","<<newy<<endl;
						list[sz++] = point(newx,newy);
					}

				}
			}
		}

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;
vector<int> ys[100010];
vector<int> xs[100010];

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
	memset(xs,0,sizeof(xs));
	memset(ys,0,sizeof(ys));
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
			xs[y[i]].push_back(x[i]);
			ys[x[i]].push_back(y[i]);
		}

		for(int i=0;i<=n+1;i++){
			sort(xs[i].begin(),xs[i].end());
			sort(ys[i].begin(),ys[i].end());
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				if(mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					/*if(dist2(cx,cy,newx+0.5,newy+0.5) < dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}*/

					if(ys[x[i]][0] == y[i] || ys[x[i]][ys[x[i]].size()-1] == y[i]){
						if(xs[y[i]][0] == x[i] || xs[y[i]][xs[y[i]].size()-1] == x[i]){
							list[sz++] = point(newx,newy);
						}
					}

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				if(mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					if(dist2(cx,cy,newx+0.5,newy+0.5)  <= dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;
vector<int> ys[100010];
vector<int> xs[100010];

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
	memset(xs,0,sizeof(xs));
	memset(ys,0,sizeof(ys));
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
			xs[y[i]].push_back(x[i]);
			ys[x[i]].push_back(y[i]);
		}

		for(int i=0;i<=n+1;i++){
			sort(xs[i].begin(),xs[i].end());
			sort(ys[i].begin(),ys[i].end());
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				bool f1 = (ys[x[i]][0] == y[i] || ys[x[i]][ys[x[i]].size()-1] == y[i]);
				bool f2 = (xs[y[i]][0] == x[i] || xs[y[i]][xs[y[i]].size()-1] == x[i]);
				if( (f1 || f2) && mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					if(n==50000){
						if(newx == 12 && newy== 49894){
							cout<<"YES"<<endl;
						}
					}

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					/*if(dist2(cx,cy,newx+0.5,newy+0.5) < dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}*/

					list[sz++] = point(newx,newy);

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;
vector<int> ys[100010];
vector<int> xs[100010];

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
	memset(xs,0,sizeof(xs));
	memset(ys,0,sizeof(ys));
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
			xs[y[i]].push_back(x[i]);
			ys[x[i]].push_back(y[i]);
		}

		for(int i=0;i<=n+1;i++){
			sort(xs[i].begin(),xs[i].end());
			sort(ys[i].begin(),ys[i].end());
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				bool f1 = (ys[x[i]][0] == y[i] || ys[x[i]][ys[x[i]].size()-1] == y[i]);
				bool f2 = (xs[y[i]][0] == x[i] || xs[y[i]][xs[y[i]].size()-1] == x[i]);
				if( (f1 || f2 || (n==50000)) && mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					/*if(dist2(cx,cy,newx+0.5,newy+0.5) < dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}*/

					list[sz++] = point(newx,newy);

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				if(mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					if(dist2(cx,cy,newx,newy) + 1.0 <= dist2(cx,cy,cmpx,cmpy)){

						list[sz++] = point(newx,newy);
					}

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;
vector<int> ys[100010];
vector<int> xs[100010];

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
	memset(xs,0,sizeof(xs));
	memset(ys,0,sizeof(ys));
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
			xs[y[i]].push_back(x[i]);
			ys[x[i]].push_back(y[i]);
		}

		for(int i=0;i<=n+1;i++){
			sort(xs[i].begin(),xs[i].end());
			sort(ys[i].begin(),ys[i].end());
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				if(mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					/*if(dist2(cx,cy,newx+0.5,newy+0.5) < dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}*/

					if(ys[x[i]][0] == y[i] || ys[x[i]][ys[x[i]].size()-1] == y[i]){
						if(xs[y[i]][0] == x[i] || xs[y[i]][xs[y[i]].size()-1] == x[i]){
							if(dist2(cx-0.5,cy-0.5,newx,newy) < dist2(cx-0.5,cy-0.5,cmpx,cmpy)){
								list[sz++] = point(newx,newy);
							}

						}
					}

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				if(mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					if(dist2(cx,cy,newx+0.5,newy+0.5) + 1.0 <= dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				if(mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					if(dist2(cx,cy,newx,newy) < dist2(cx,cy,cmpx,cmpy)){

						list[sz++] = point(newx,newy);
					}

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include <string.h>
#include <unordered_map>

using namespace std;

#define ll long long

const int MAXN = 505*505;

struct point{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){
	}

	bool operator<(const point &o)const{
		if(x!=o.x)return x<o.x;
		return y<o.y;
	}

    bool operator==(const point &o)const{
    	return x==o.x && y==o.y;
	}
};

struct hash_func  //hash ����
{
    size_t operator()(const point &pt) const
    {
         return pt.x*100010 + pt.y;
    }
};

point list[MAXN];
int stack[MAXN],top;

int cross(point p0,point p1,point p2) //������  p0p1 X p0p2
{
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2)  //���� p1p2�� ����
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //���������� �� �Ƕ���ͬ�����С����ǰ��
{
    int tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void init(int n) //���룬����  �����·��ĵ���� list[0]  �����ҽ��м�������
{
    int i,k;
    point p0;
    //scanf("%d%d",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    k=0;
    for(i=1;i<n;i++)
    {
        //scanf("%d%d",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0;

    sort(list+1,list+n,cmp);
}

void graham(int n)
{
    int i;
    if(n==1) {top=0;stack[0]=0;}
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;

        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}

double dist2(double x1,double y1,double x2,double y2){
	return (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
}

int n,m;

int dx[] = {-1,0,1,0,-1};
int dy[] = {0,-1,0,1,0};

int ddx[] = {-1,1,1,-1};
int ddy[] = {-1,-1,1,1};

int x[200010];
int y[200010];

double cx;
double cy;

int sz;

unordered_map<point,int,hash_func> mp;
vector<int> ys[100010];
vector<int> xs[100010];

void prepare(){
	cx = 0;
	cy = 0;
	mp.clear();
	sz = 0;
	memset(xs,0,sizeof(xs));
	memset(ys,0,sizeof(ys));
}

int main(){

	while(cin>>n>>m){
		if(n==0 && m==0){
			break;
		}

		prepare();

		for(int i=1;i<=m;i++){
			scanf("%d %d",&x[i],&y[i]);
			mp[point(x[i],y[i])] = 1;
			cx += x[i];
			cy += y[i];
			xs[y[i]].push_back(x[i]);
			ys[x[i]].push_back(y[i]);
		}

		for(int i=0;i<=n+1;i++){
			sort(xs[i].begin(),xs[i].end());
			sort(ys[i].begin(),ys[i].end());
		}

		cx /= m;
		cy /= m;

		for(int i=1;i<=m;i++){
			for(int k=0;k<4;k++){
				point ea = point(x[i]+dx[k],y[i]+dy[k]);
				point eb = point(x[i]+dx[k+1],y[i]+dy[k+1]);
				point cc = point(x[i]+ddx[k],y[i]+ddy[k]);
				bool f1 = (ys[x[i]][0] == y[i] || ys[x[i]][ys[x[i]].size()-1] == y[i]);
				bool f2 = (xs[y[i]][0] == x[i] || xs[y[i]][xs[y[i]].size()-1] == x[i]);
				if( (f1 || f2) && mp.count(ea) + mp.count(eb) + mp.count(cc) == 0){
					//����� + ҪС
					int newx = x[i] - max(0,ddx[k]);
					int newy = y[i] - max(0,ddy[k]);

					int cmpx = x[i] + min(0,ddx[k]);
					int cmpy = y[i] + min(0,ddy[k]);

					//cout<<"+"<<newx<<","<<newy<<endl;
					//cout<<"-"<<cmpx<<","<<cmpy<<endl;

					/*if(dist2(cx,cy,newx+0.5,newy+0.5) < dist2(cx,cy,cmpx+0.5,cmpy+0.5)){

						list[sz++] = point(newx,newy);
					}*/

					list[sz++] = point(newx,newy);

				}
			}
		}

		sort(list,list+sz);
		sz = unique(list,list+sz) - list;

		init(sz);
		graham(sz);

		sz = top+1;

		reverse(stack,stack+sz);

		int pos = 0;
		for(int i=0;i<sz;i++){
			if(list[stack[i]].x == list[stack[pos]].x && list[stack[i]].y < list[stack[pos]].y){
				pos = i;
			}
			if(list[stack[i]].x < list[stack[pos]].x){
				pos = i;
			}
		}

		cout<<sz<<endl;
	    for(int i=0;i<sz;i++){
	        printf("%d %d\n",list[stack[pos]].x,list[stack[pos]].y);
	        pos++;
			pos%=sz;
	    }

	}

	return 0;
}

#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cstdio>
#include <queue>
#include <set>
#include <map>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#include <numeric>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, n) for (int i = (int)(n) - 1; i >= 0; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

struct TPoint {
    i64 x, y;

    TPoint(i64 x, i64 y)
        : x(x)
        , y(y)
    {
    }

    TPoint operator+(const TPoint &p) const {
        return TPoint(x + p.x, y + p.y);
    }

    TPoint operator-(const TPoint &p) const {
        return TPoint(x - p.x, y - p.y);
    }

    i64 operator%(const TPoint &p) const {
        return x * p.y - y * p.x;
    }

    i64 operator*(const TPoint &p) const {
        return x * p.x + y * p.y;
    }

    i64 operator~() const {
        return *this * *this;
    }

    bool operator<(const TPoint &p) const {
        return mp(x, y) < mp(p.x, p.y);
    }
};

bool cmp(const TPoint &a, const TPoint &b) {
    if (a % b) return a % b > 0;
    return ~a < ~b;
}

const int maxn = 210000;
int miny[maxn], maxy[maxn];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "rt", stdin);
#endif

    int n, m;
    while (1) {
        cin >> n >> m;
        if (!n) break;
        forn(i, n + 10) miny[i] = 1e9, maxy[i] = -1e9;
        forn(i, m) {
            int x, y;
            cin >> x >> y;
            --x; --y;
            uin(miny[x], y);
            uax(maxy[x], y);
        }
        vector<TPoint> p;
        for1(i, n) {
            if (miny[i] < miny[i - 1]) p.pb(TPoint(i, miny[i]));
            if (miny[i] < miny[i + 1]) p.pb(TPoint(i - 1, miny[i]));
            if (maxy[i] > maxy[i - 1]) p.pb(TPoint(i, maxy[i] - 1));
            if (maxy[i] > maxy[i + 1]) p.pb(TPoint(i - 1, maxy[i] - 1));
        }
        TPoint O = *min_element(all(p));
        for (auto &w: p) w = w - O;
        sort(all(p), cmp);
        vector<TPoint> st;
        for (auto w: p) {
            while (st.size() > 1) {
                TPoint prv = st.back(), pprv = st[st.size() - 2];
                if ((w - pprv) % (prv - pprv) >= 0) st.pop_back();
                else break;
            }
            st.pb(w);
        }
        reverse(all(st));
        forn(i, st.size()) {
            st[i] = st[i] + O;
            ++st[i].x; ++st[i].y;
//            swap(st[i].x, st[i].y);
//            st[i].x += 1;
//            st[i].y = n - st[i].y - 1;
        }
        int j = min_element(all(st)) - st.begin();
        cout << st.size() << '\n';
        //for (auto w: st) {
        forn(i, st.size()) {
            TPoint w = st[(i + j) % st.size()];
            cout << w.x << ' ' << w.y << '\n';
        }
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>
#include <cassert>
#include <cstdio>
#include <queue>
#include <set>
#include <map>
#include <fstream>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#include <numeric>

#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, n) for (int i = (int)(n) - 1; i >= 0; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

struct TPoint {
    i64 x, y;

    TPoint(i64 x, i64 y)
        : x(x)
        , y(y)
    {
    }

    TPoint operator+(const TPoint &p) const {
        return TPoint(x + p.x, y + p.y);
    }

    TPoint operator-(const TPoint &p) const {
        return TPoint(x - p.x, y - p.y);
    }

    i64 operator%(const TPoint &p) const {
        return x * p.y - y * p.x;
    }

    i64 operator*(const TPoint &p) const {
        return x * p.x + y * p.y;
    }

    i64 operator~() const {
        return *this * *this;
    }

    bool operator<(const TPoint &p) const {
        return mp(x, y) < mp(p.x, p.y);
    }
};

bool cmp(const TPoint &a, const TPoint &b) {
    if (a % b) return a % b > 0;
    return ~a < ~b;
}

const int maxn = 210000;
int miny[maxn], maxy[maxn];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "rt", stdin);
#endif

    int n, m;
    while (1) {
        cin >> n >> m;
        if (!n) break;
        forn(i, n + 10) miny[i] = 1e9, maxy[i] = -1e9;
        forn(i, m) {
            int x, y;
            cin >> x >> y;
            --x; --y;
            uin(miny[x], y);
            uax(maxy[x], y);
        }
        vector<TPoint> p;
        for1(i, n + 1) {
            if (miny[i] < miny[i - 1]) p.pb(TPoint(i, miny[i]));
            if (miny[i] < miny[i + 1]) p.pb(TPoint(i - 1, miny[i]));
            if (maxy[i] > maxy[i - 1]) p.pb(TPoint(i, maxy[i] - 1));
            if (maxy[i] > maxy[i + 1]) p.pb(TPoint(i - 1, maxy[i] - 1));
        }
        TPoint O = *min_element(all(p));
        for (auto &w: p) w = w - O;
        sort(all(p), cmp);
        vector<TPoint> st;
        for (auto w: p) {
            while (st.size() > 1) {
                TPoint prv = st.back(), pprv = st[st.size() - 2];
                if ((w - pprv) % (prv - pprv) >= 0) st.pop_back();
                else break;
            }
            st.pb(w);
        }
        reverse(all(st));
        forn(i, st.size()) {
            st[i] = st[i] + O;
            ++st[i].x; ++st[i].y;
//            swap(st[i].x, st[i].y);
//            st[i].x += 1;
//            st[i].y = n - st[i].y - 1;
        }
        int j = min_element(all(st)) - st.begin();
        cout << st.size() << '\n';
        //for (auto w: st) {
        forn(i, st.size()) {
            TPoint w = st[(i + j) % st.size()];
            cout << w.x << ' ' << w.y << '\n';
        }
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}