import std.algorithm;
import std.array;
import std.container;
import std.conv;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

void scan(T...)(ref T a) {
    string[] ss = readln.split;
    foreach (i, t; T) a[i] = ss[i].to!t;
}
T read(T)() { return readln.chomp.to!T; }
T[] reads(T)() { return readln.split.to!(T[]); }
alias readint = read!int;
alias readints = reads!int;

struct D {
    int row, col, step;
}

int calc(string[] g) {
    int rows = cast(int)g.length;
    int cols = cast(int)g[0].length;
    bool inp(int r, int c) { return 0 <= r && r < rows && 0 <= c && c < cols; }

    auto q = new Queue!(D);
    foreach (r; 0..rows) foreach (c; 0..cols) {
        if (g[r][c] == '#') {
            q.push(D(r, c, 0));
        }
    }

    int ans = 0;
    auto t = new int[][](rows, cols);
    auto dxy = [0, 1, 0, -1];
    while (!q.empty) {
        auto d = q.pop();
        if (t[d.row][d.col]++) continue;

        ans = max(ans, d.step);
        for (int i = 0; i < dxy.length; i++) {
            int r = d.row + dxy[i];
            int c = d.col + dxy[$-1-i];
            if (inp(r, c)) q.push(D(r, c, d.step + 1));
        }
    }
    return ans;
}

void main() {
    int h, w; scan(h, w);
    string[] g;
    foreach (_; 0..h) g ~= read!string;
    writeln(calc(g));
}

class Queue(T) {
    private DList!(T) _dlist;
    private ulong _size;

    this(T[] ary) {
        _dlist = DList!(T)(ary);
        _size = ary.length;
    }

    this() {
        _dlist = DList!(T)();
        _size = 0;
    }

    void push(T x) {
        _dlist.insertBack(x);
        _size++;
    }

    T pop() {
        T x = _dlist.front;
        _dlist.removeFront();
        _size--;
        return x;
    }

    @property T front() {
        return _dlist.front;
    }

    @property ulong size() {
        return _size;
    }

    @property bool empty() {
        return _dlist.empty;
    }
}
