// Original C++ solution (slower):
#include<iostream>

#include<vector>

#include<algorithm>

#include<queue>

#include<map>

#include<stack>

#include<cmath>

#include<iomanip>

#include<set>

#include<numeric>

#include<sstream>

#include<random>

#include<cassert>

#include<climits>

#include<cstring>

using namespace std;

typedef long long ll;

#define rep(i, n) for (int i = 0; i < n; ++i)

#define rrep(i, st, n) for (int i = st; i < n; ++i)

using pii = pair<int, int>;

const int inf = 1e9 + 7;

int dy[] = {0, 0, -1, 1, -1, 1, -1, 1};

int dx[] = {1, -1, 0, 0, -1, 1, 1, -1};

#define ceil(a, b) a / b + !!(a % b)

#define chmax(a, b) a = max(a, b)

#define chmin(a, b) a = min(a, b)



int main() {

    int h, w; cin >> h >> w;

    char a[h][w]; rep(i, h) rep(j, w) cin >> a[i][j];

    int c = 0;

    int reached[1001][1001] = {0};

    queue<pii> q;

    rep(i, h) rep(j, w) if (a[i][j] == '#') q.push({i, j});

    while (!q.empty()) {

        int y = q.front().first, x = q.front().second;

        q.pop();

        rep(k, 4) {

            int ny = y + dy[k], nx = x + dx[k];

            if (ny < 0 || ny >= h || nx < 0 || nx >= w) continue;

            if (a[ny][nx] == '#') continue;

            reached[ny][nx] = reached[y][x] + 1;

            a[ny][nx] = '#';

            q.push({ny, nx});

        }

    }

    int ans = 0;

    rep(i, h) rep(j, w) chmax(ans, reached[i][j]);

    cout << ans << endl;

    //rep(i, h) {rep(j, w) cout << reached[i][j] << " "; cout << endl;}

}


// Optimized solution to the same problem (faster):
#include<bits/stdc++.h>

using namespace std;

typedef long long ll;

#define F first

#define S second

#define pii pair<int, int>

#define eb emplace_back

#define all(v) v.begin(), v.end()

#define rep(i, n) for (int i = 0; i < n; ++i)

#define rep3(i, l, n) for (int i = l; i < n; ++i)

#define chmax(a, b) a = (a >= b ? a : b)

#define chmin(a, b) a = (a <= b ? a : b)

#define out(a) cout << a << endl

#define outa(a, n) rep(_, n) cout << a[_] << " "; cout << endl

#define SZ(v) (int)v.size()

#define inf (int)(1e9+7)

#define abs(x) (x >= 0 ? x : -(x))

#define ceil(a, b) a / b + !!(a % b)

#define FIX(a) fixed << setprecision(a)



int h, w;

const int MAX_N = 1000;

char c[MAX_N + 1][MAX_N + 1];

int cnt;

int used[MAX_N + 1][MAX_N + 1];

int main() {

    cin >> h >> w;

    queue<pii> q;

    rep(i, h) rep(j, w) { cin >> c[i][j]; if (c[i][j] == '#') { q.push({i, j}); used[i][j] = 1; } }

    

    while (1) {

        queue<pii> qq;

        while (!q.empty()) {

            int y = q.front().F, x = q.front().S;

            q.pop();

            rep3(i, -1, 2) rep3(j, -1, 2) {

                if ((i != 0 && j != 0) || ((i | j) == 0)) continue;

                int ny = y + i;

                int nx = x + j;

                if (ny < 0 || ny >= h || nx < 0 || nx >= w) continue;

                if (c[ny][nx] == '#' || used[ny][nx]) continue;

                c[ny][nx] = '#';

                used[ny][nx] = 1;

                qq.push({ny, nx});

            }

        }

        q = qq;

        

        if (SZ(q) == 0) break;

        cnt++;

    }

    out(cnt);

}


// Fastest known solution for this problem: