// Slower C++ solution:
#include <bits/stdc++.h>



using namespace std;

int n, m;

char op[1005][1005];

bool vis[1005][1005];

int dp[1005][1005];

const int X[] = {-1, 0, 1, 0}, Y[] = {0, 1, 0, -1};



struct Node {

    int x, y;



    Node(int a, int b) : x(a), y(b) {}

};



queue<Node> que;



int main() {

    ios::sync_with_stdio(false), memset(dp, 127, sizeof(dp));

    cin >> n >> m;

    for (int i = 1; i <= n; i++)cin >> (op[i] + 1);

    for (int i = 1; i <= n; i++) {

        for (int j = 1; j <= m; j++) {

            if (op[i][j] == '#') {

                for (int p = 0; p < 4; p++) {

                    int xx = i + X[p], yy = j + Y[p];

                    if (op[xx][yy] == '.' && !vis[xx][yy])vis[xx][yy] = true, dp[xx][yy] = 1, que.push(Node(xx, yy));

                }

            }

        }

    }

    while (!que.empty()) {

        Node s = que.front();

        que.pop(), vis[s.x][s.y] = false;

        for (int i = 0; i < 4; i++) {

            int xx = s.x + X[i], yy = s.y + Y[i];

            if (xx < 1 || xx > n || yy < 1 || yy > m)continue;

            if (op[xx][yy] == '.' && dp[xx][yy] > dp[s.x][s.y] + 1) {

                dp[xx][yy] = dp[s.x][s.y] + 1;

                if (!vis[xx][yy])que.push(Node(xx, yy)), vis[xx][yy] = true;

            }

        }

    }

    int ans = 0;

    for (int i = 1; i <= n; i++) {

        for (int j = 1; j <= m; j++) {

            if (op[i][j] == '.')ans = max(ans, dp[i][j]);

        }

    }

    cout << ans;

    return 0;

}

// Faster C++ solution for the same problem (measured speedup: 5.05209921148802x):
#include <bits/stdc++.h>

#define N 1005



using namespace std;



short n, m;

char a[N][N];

bool mark[N][N];



struct Element

{

    short lin, col;

    short nivel;

};



queue < Element > c;



short dl[] = {-1, 0, 1,  0};

short dc[] = { 0, 1, 0, -1};



bool inline Verif(Element v)

{

    if(a[v.lin - 1][v.col] == '.' || a[v.lin + 1][v.col] == '.' || a[v.lin][v.col + 1] == '.' || a[v.lin][v.col - 1] == '.')

        return true;



    return false;

}



bool inline Inside(Element p)

{

    if(p.lin >= 1 && p.lin <= n && p.col >= 1 && p.col <= m)

        return true;



    return false;

}



int main()

{

    ios_base::sync_with_stdio(false), cin.tie(0);

    short cnt = 0, i, j;



    cin >> n >> m;



    for(i = 1 ; i <= n ; ++i)

        for(j = 1 ; j <= m ; ++j)

            cin >> a[i][j];



    short ans = 0;

    bool ok = 0;

    Element p, v;



    for(i = 1 ; i <= n ; i++)

        for(j = 1 ; j <= m ; j++)

        {

            if(a[i][j] == '#')

            {

                c.push(Element{i, j , 1});

                mark[i][j] = 1;

            }

        }



    int nivel = 1;



    while(!c.empty())

    {

        p = c.front();

        c.pop();



        if(Inside(p) == false)

            continue;



        if(Verif(p) == true && p.nivel == nivel)

            ++ans , nivel++;



        a[p.lin - 1][p.col] = a[p.lin + 1][p.col] = a[p.lin][p.col - 1] = a[p.lin][p.col + 1] = '#';



        //for(i = 1 ; i <= n ; i++)

            //for(j = 1 ; j <= m ; j++)



        for(short t = 0 ; t < 4 ; t++)

        {

            v = {p.lin + dl[t], p.col + dc[t] , nivel};



            if(Inside(v) && !mark[v.lin][v.col])

                c.push(v), mark[v.lin][v.col] = 1 ;

        }

    }



    cout << ans;



    return 0;

}