#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<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<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 <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 <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 <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 <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<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();
}

#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 <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 <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<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 <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 <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<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 <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;
}