import std.stdio, std.conv, std.array, std.algorithm, std.range, std.string, std.typecons;

long h, w;
char[][] field;
long[][] dists;
long[] xs;
long[] ys;

const INF = 99999999;

alias T = Tuple!(long, long, long);


void main() {
    readf("%d %d\n", &h, &w);
    foreach (_; 0..h) {
        field ~= readln.strip.dup;
    }
    dists = new long[][](h, w);

    foreach (y; 0..h) {
        foreach (x; 0..w) {
            dists[y][x] = INF;
            if (field[y][x] == '#') {
                xs ~= x;
                ys ~= y;
            }
        }
    }


    foreach (i; 0..xs.length) {
        int[][] checked = new int[][](h, w);
        checked[ys[i]][xs[i]] = 1;
        T[] todos = [T(ys[i], xs[i], 0)];
        int dist = 0;
        while (todos.length > 0) {
            T p = todos[0];
            long y = p[0];
            long x = p[1];
            long d = p[2];
            todos.popFront();

            dists[y][x] = min(dists[y][x], d);

            long[] dx = [0, -1, 1, 0];
            long[] dy = [-1, 0, 0, 1];
            foreach (j; 0..dx.length) {
                long x2 = x + dx[j];
                long y2 = y + dy[j];
                if (x2 >= 0 && x2 < w && y2 >= 0 && y2 < h && checked[y2][x2] == 0) {
                    todos ~= T(y2, x2, d+1);
                    checked[y2][x2] = 1;
                }
            }
        }
    }

    long ans = 0;
    foreach (y; 0..h) {
        foreach (x; 0..w) {
            ans = max(ans, dists[y][x]);
        }
    }
    writeln(ans);


}
