package main
import (
"bufio"
"fmt"
"io"
"os"
)
type Point struct {
x, y int
}
var data []byte
var pos int
func nextInt() int {
for pos < len(data) && data[pos] <= ' ' {
pos++
}
n := 0
for pos < len(data) && data[pos] > ' ' {
n = n*10 + int(data[pos]-'0')
pos++
}
return n
}
func nextToken() []byte {
for pos < len(data) && data[pos] <= ' ' {
pos++
}
start := pos
for pos < len(data) && data[pos] > ' ' {
pos++
}
return data[start:pos]
}
func cross(o, a, b Point) int64 {
return int64(a.x-o.x)*int64(b.y-o.y) - int64(a.y-o.y)*int64(b.x-o.x)
}
func convexHull(points []Point) []Point {
if len(points) <= 1 {
return points
}
lower := make([]Point, 0, len(points))
for _, p := range points {
for len(lower) >= 2 && cross(lower[len(lower)-2], lower[len(lower)-1], p) <= 0 {
lower = lower[:len(lower)-1]
}
lower = append(lower, p)
}
upper := make([]Point, 0, len(points))
for i := len(points) - 1; i >= 0; i-- {
p := points[i]
for len(upper) >= 2 && cross(upper[len(upper)-2], upper[len(upper)-1], p) <= 0 {
upper = upper[:len(upper)-1]
}
upper = append(upper, p)
}
hull := make([]Point, 0, len(lower)+len(upper)-2)
hull = append(hull, lower[:len(lower)-1]...)
hull = append(hull, upper[:len(upper)-1]...)
return hull
}
func main() {
data, _ = io.ReadAll(os.Stdin)
out := bufio.NewWriterSize(os.Stdout, 1<<20)
defer out.Flush()
for {
n := nextInt()
if n == 0 {
break
}
m := n + 1
c := make([]byte, m*m)
for row := 0; row < n; row++ {
s := nextToken()
y := n - row
base := y * m
for x := 1; x <= n; x++ {
c[base+x] = s[x-1] - '0'
}
}
a := make([]int, m*m)
for y := 1; y <= n; y++ {
base := y * m
prev := base - m
for x := 1; x <= n; x++ {
a[base+x] = int(c[base+x]) - a[prev+x-1] - a[prev+x] - a[base+x-1]
}
}
points := make([]Point, 0)
for x := 0; x <= n; x++ {
for y := 0; y <= n; y++ {
if a[y*m+x] != 0 {
points = append(points, Point{x, y})
}
}
}
hull := convexHull(points)
fmt.Fprintln(out, len(hull))
if len(hull) > 0 {
fmt.Fprintln(out, hull[0].x, hull[0].y)
for i := len(hull) - 1; i >= 1; i-- {
fmt.Fprintln(out, hull[i].x, hull[i].y)
}
}
}
}