#include <bits/stdc++.h>
#include <regex>
#ifdef _DEBUG
#include "debug.h"
#endif
#define int ll
#define float double
#define FOR(i, s, e) for (int i = int(s); i < int(e); ++i)
#define REP(i, e) FOR(i, 0, e)
#define all(v) (v).begin(),(v).end()
#define mkpr make_pair
#define mktp make_tuple
#define tv(tp, i) get<(i)>(tp)
#define CLEAR(obj) obj = decltype(obj)()
#define var auto
#define OUT(type) type &
#define IN(type) const type &
#define self (*this)
#define in :
#define True true
#define False false
using namespace std; using int32 = int32_t; using ll = long long; using ull = unsigned long long;
using vi = vector<int>; using vvi = vector<vi>; using vl = vector<ll>; using vvl = vector<vl>;
using vb = vector<bool>; using vvb = vector<vb>; using vc = vector<char>; using vvc = vector<vc>;
using vf = vector<float>; using vvf = vector<vf>; using vd = vector<double>; using vvd = vector<vd>;
using str = string; using vs = vector<string>;
using pii = pair<int, int>; using pll = pair<ll, ll>; using pff = pair<float, float>; using pdd = pair<double, double>;
using psl = pair<string, ll>; using tiii = tuple<int, int, int>; using tlll = tuple<ll, ll, ll>;
static const int MGN = 10; static const int ARYSZ_MAX = (int)1e7; static const ll LINF = LLONG_MAX/2;
#ifdef int
static const int INF = LINF;
#else
static const int INF = INT_MAX/2;
#endif
static double EPS = 1e-9;
#define FASTCIN() cin.tie(0);ios::sync_with_stdio(false);
#ifdef IMPORT_SAMPLE
#define DEBUG_IMPORT(file) vs args(argv, argv+argc);str sample = make_sample(args, file);ifstream ifs(sample); cin.rdbuf(ifs.rdbuf());
#else
#define DEBUG_IMPORT(file)
#endif
static inline int ord(char c) {return (int)c;}
static inline char chr(int n) {return (char)n;}
static inline bool DBLEQ(double a, double b) {return abs(a - b) < EPS;}
static inline void EPR(str msg) {cerr << msg << endl;}
static inline void AST(bool exp, str msg) {if(!exp){EPR(msg);} assert(exp);}
static inline void TAST(bool exp, str msg) {if(!exp){EPR(msg);} while(!exp){}}

struct GridBFS {
    vs G;
    int H,W;
    char Wall;
    vi dx = {0,1,0,-1};
    vi dy = {1,0,-1,0};

    GridBFS(IN(vs) G, char Wall='#') {
        self.G = G;
        self.H = G.size();
        self.W = G[0].size();
        self.Wall = Wall;
    }

    int fill(vector<pii> starts) {
        queue<pii> que;
        var step = vvi(self.H, vi(self.W, INF));
        for (pii pr in starts) {
            que.push(mkpr(pr.first, pr.second));
            step[pr.first][pr.second] = 0;
        }

        while(not que.empty()) {
            var pr = que.front(); que.pop();
            int x = pr.first, y = pr.second;

            REP(i,dx.size()) {
                int nx = x + self.dx[i], ny = y + self.dy[i];
                if (nx<0 or self.H<=nx or ny<0 or self.W<=ny)
                    continue;
                //if (self.G[nx][ny] == self.Wall)
                //    continue;

                if (step[nx][ny] > step[x][y] + 1) {
                    step[nx][ny] = step[x][y] + 1;
                    que.push(mkpr(nx, ny));
                }
            }
        }

        int res = 0;
        REP(i,self.H)
            REP(j,self.W)
                res = max(res, step[i][j]);

        return res;
    }
};

int32 main(int32 argc, char* argv[]) {
    FASTCIN();
    DEBUG_IMPORT("sample-1");


    int H,W; cin>>H>>W;
    vs G(H); REP(i,H) cin>>G[i];

    vector<pii> starts;
    REP(i,H)
        REP(j,W)
            if (G[i][j] == '#')
                starts.push_back(mkpr(i,j));

    var gbfs = GridBFS(G, '-');
    int ans = gbfs.fill(starts);
    cout << ans << endl;


    return 0;
}


Measured memory_bytes: 57828