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