#include <bits/stdc++.h>
using namespace std;
bool cmp_x(const complex<double>& a, const complex<double>& b) {
  return abs(a.real() - b.real()) < 1e-6 ? a.imag() < b.imag()
                                         : a.real() < b.real();
}
bool cmp_y(const complex<double>& a, const complex<double>& b) {
  return abs(a.imag() - b.imag()) < 1e-6 ? a.real() < b.real()
                                         : a.imag() < b.imag();
}
double cross(complex<double> a, complex<double> b) {
  return (conj(a) * b).imag();
}
vector<complex<double> > convex_hull(vector<complex<double> > ps) {
  sort(ps.begin(), ps.end(), cmp_x);
  int n = ps.size(), k = 0;
  vector<complex<double> > qs(n * 2);
  for (int i = 0; i < n; i++) {
    while (k > 1 && cross(qs[k - 1] - qs[k - 2], ps[i] - qs[k - 1]) <= 0) k--;
    qs[k++] = ps[i];
  }
  for (int i = n - 2, t = k; i >= 0; i--) {
    while (k > t && cross(qs[k - 1] - qs[k - 2], ps[i] - qs[k - 1]) <= 0) k--;
    qs[k++] = ps[i];
  }
  qs.resize(k - 1);
  return qs;
}
int n;
int a[505][505];
bool vis[505][505];
bool used[505][505];
int di[] = {0, 0, 1, 1}, dj[] = {0, 1, 0, 1};
int dd[] = {-1, 0, 1, 0, -1};
vector<complex<double> > ps;
bool isvalid_point(int i, int j) {
  return i >= 0 && i <= n && j >= 0 && j <= n;
}
bool isvalid_a(int i, int j) { return i >= 0 && i < n && j >= 0 && j < n; }
int main() {
  cin.sync_with_stdio(false);
  while (1) {
    cin >> n;
    if (n == 0) break;
    memset(a, 0, sizeof(a));
    memset(used, 0, sizeof(used));
    memset(vis, 0, sizeof(vis));
    ps.clear();
    for (long long i = (long long)(0); i < (long long)(n); i++) {
      string s;
      cin >> s;
      for (long long j = (long long)(0); j < (long long)(n); j++) {
        a[i][j] = s[j] - '0';
      }
    }
    queue<complex<double> > que;
    for (long long i = (long long)(0); i < (long long)(n); i++)
      for (long long j = (long long)(0); j < (long long)(n); j++) {
        if (a[i][j] == 0) {
          que.push(complex<double>(i, j));
          vis[i][j] = true;
        }
      }
    while (que.size()) {
      complex<double> np = que.front();
      que.pop();
      int i = np.real(), j = np.imag();
      for (long long dir = (long long)(0); dir < (long long)(4); dir++) {
        int ni = i + di[dir], nj = j + dj[dir];
        if (!isvalid_point(ni, nj)) continue;
        if (used[ni][nj]) continue;
        used[ni][nj] = true;
        if (a[i][j] > 0) {
          ps.push_back(complex<double>(ni, nj));
        }
      }
      for (long long dir = (long long)(0); dir < (long long)(4); dir++) {
        int ni = i + dd[dir], nj = j + dd[dir + 1];
        if (!isvalid_a(ni, nj)) continue;
        if (vis[ni][nj]) continue;
        int cnt = 0;
        for (long long ndir = (long long)(0); ndir < (long long)(4); ndir++) {
          int nni = ni + di[ndir], nnj = nj + dj[ndir];
          if (!isvalid_point(nni, nnj)) continue;
          if (used[nni][nnj]) cnt++;
        }
        if (a[ni][nj] + cnt == 4) {
          que.push(complex<double>(ni, nj));
          vis[ni][nj] = true;
        }
      }
    }
    vector<complex<double> > res = convex_hull(ps);
    reverse((res).begin(), (res).end());
    vector<complex<double> > tmp(res.size());
    for (long long i = (long long)(0); i < (long long)(res.size()); i++) {
      tmp[i] = complex<double>((int)res[i].imag(), n - (int)res[i].real());
    }
    res = tmp;
    int idx = 0;
    for (long long i = (long long)(0); i < (long long)(res.size()); i++) {
      if (cmp_x(res[i], res[idx])) idx = i;
    }
    printf("%d\n", (int)res.size());
    for (long long i = (long long)(0); i < (long long)(res.size()); i++) {
      printf("%d %d\n", (int)res[(idx + i) % res.size()].real(),
             (int)res[(idx + i) % res.size()].imag());
    }
  }
  return 0;
}
