#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <functional>
#include <vector>
#include <queue>
#include <deque>
#include <map>
#include <set>
#include <cassert>
#define InfL 1000000000
#define InfLL 1000000000000000000LL
#define mod 1000000007
#define rep(i,n) for(int (i)=0;(i)<(n);(i)++)
#define rrep(i,n) for(int (i)=(n-1);(i)>=(0);(i)--)
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<bool> vb;
typedef vector<db> vd;

class Graph_class {
public:
	bool UDLR_and_corner = false;
	int N;
	int M;
	vector<vector<char>> xy;

	vector<vector<pii>> adj_to_root;
	vector<vector<int>> DP;
	vector<pii> vlist_from_root;
	vector<vl> vdist;

	vector<vb> v_visited;
	deque<pii> v_que;

	void read_edge();
	void adjini();
	void visited_ini();
	void graph_BFS();
	void graph_DFS(pii DFS_ini);
	void ReRooting(pii root);
	void solve();
};

void Graph_class::read_edge() {
	cin >> N >> M;
	xy.resize(N);
	rep(i, N) {
		xy[i].resize(M);
		string S;
		cin >> S;
		rep(j, M) {
			xy[i][j] = S[j];
			//cin >> xy[i][j];
			//scanf("%c", &xy[i][j]);
		}
	}
	return;
}

void Graph_class::adjini() {
	vdist.resize(N);
	adj_to_root.resize(N);
	DP.resize(N);
	v_visited.resize(N);
	rep(i, N) {
		vdist[i].resize(M, -1);
		adj_to_root[i].resize(M, make_pair(-1, -1));
		DP[i].resize(M, 0);
		v_visited[i].resize(M, false);
	}
	visited_ini();
	return;
}

void Graph_class::visited_ini() {
	rep(i, N) {
		rep(j, M) {
			v_visited[i][j] = false;
		}
	}
	v_que.clear();
}

void Graph_class::graph_BFS() {
	v_que.clear();
	rep(i, N) {
		rep(j, M) {
			if(xy[i][j]=='#'){
				v_que.push_back(make_pair(i, j));
				v_visited[i][j] = true;
				vdist[i][j] = 0;
			}
		}
	}

	// option
	//cout << BFS_ini.first << " " << BFS_ini.second << endl;

	while (!v_que.empty()) {
		pii ij0 = v_que.front();
		v_que.pop_front();
		int i0 = ij0.first;
		int j0 = ij0.second;
		for (int idiff = -1; idiff <= 1; idiff++) {
			for (int jdiff = -1; jdiff <= 1; jdiff++) {
				if (UDLR_and_corner) {
					if ((idiff == 0) && (jdiff == 0)) // 8 (UDLR + corner)
						continue;
				}
				else {
					if ((idiff == 0) == (jdiff == 0)) // 4 (UDLR)
						continue;
				}
				int i1 = i0 + idiff;
				int j1 = j0 + jdiff;
				if (i1 < 0 || i1 >= N || j1 < 0 || j1 >= M)
					continue;
				pii ij1 = make_pair(i1, j1);
				if (!v_visited[i1][j1]) {
					v_visited[i1][j1] = true;
					v_que.push_back(ij1);

					// option
					vdist[i1][j1] = vdist[i0][j0] + 1;
					//cout << i1 << " " << j1 << endl;
				}
			}
		}
	}
	return;
}

void Graph_class::graph_DFS(pii DFS_ini) {
	v_que.clear();
	v_que.push_back(DFS_ini);
	v_visited[DFS_ini.first][DFS_ini.second] = true;

	while (!v_que.empty()) {
		pii ij0 = v_que.back();
		v_que.pop_back();
		int i0 = ij0.first;
		int j0 = ij0.second;

		// option
		//cout << i0 << " " << j0 << endl;

		for (int idiff = -1; idiff <= 1; idiff++) {
			for (int jdiff = -1; jdiff <= 1; jdiff++) {
				if (UDLR_and_corner) {
					if ((idiff == 0) && (jdiff == 0)) // 8 (UDLR + corner)
						continue;
				}
				else {
					if ((idiff == 0) == (jdiff == 0)) // 4 (UDLR)
						continue;
				}
				int i1 = i0 + idiff;
				int j1 = j0 + jdiff;
				if (i1 < 0 || i1 >= N || j1 < 0 || j1 >= M)
					continue;
				pii ij1 = make_pair(i1, j1);
				if (xy[i1][j1] == 0 && !v_visited[i1][j1]) {
					v_visited[i1][j1] = true;
					v_que.push_back(ij1);
				}
			}
		}
	}
	return;
}

void Graph_class::ReRooting(pii root) {
	rep(i, N) {
		rep(j, M) {
			DP[i][j] = 1;
		}
	}
	//graph_BFS(root);

	rrep(i, vlist_from_root.size()) { // 根から遠い点から見る
		pii ij0 = vlist_from_root[i];
		int i0 = ij0.first;
		int j0 = ij0.second;
		for (int idiff = -1; idiff <= 1; idiff++) {
			for (int jdiff = -1; jdiff <= 1; jdiff++) {
				if (UDLR_and_corner) {
					if ((idiff == 0) && (jdiff == 0)) // 8 (UDLR + corner)
						continue;
				}
				else {
					if ((idiff == 0) == (jdiff == 0)) // 4 (UDLR)
						continue;
				}
				int i1 = i0 + idiff;
				int j1 = j0 + jdiff;
				if (i1 < 0 || i1 >= N || j1 < 0 || j1 >= M)
					continue;
				pii ij1 = make_pair(i1, j1);
				if (ij1 == adj_to_root[i0][j0]) // 根側
					continue;
				DP[i0][j0] += DP[i1][j1];
			}
		}
	}
	return;
}

void Graph_class::solve() {
	graph_BFS();
	ll ans = 0;
	rep(i, N) {
		rep(j, M)
			ans = max(ans, vdist[i][j]);
	}
	cout << ans << endl;
	return;
}

int main() {
	Graph_class graph;
	graph.read_edge();
	graph.adjini();
	graph.solve();
	return 0;
}

Measured memory_bytes: 29328