// 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.221820664740617x):
#include<bits/stdc++.h>

using namespace std;

char Map[1005][1005];

int n,m,turn[4][2]={1,0,0,1,-1,0,0,-1};

void judge(int _x,int _y) {

    if(_x<0||_x>=n) return;

    if(_y<0||_y>=m) return;

    if(Map[_x][_y]=='.') Map[_x][_y]='*';

}

struct node {

    int a,b;

    node (int x,int y) {

        a=x,b=y;

    }

    node(){}

}point[1005];

int dis(int a,int b,int c,int d) {

    return abs(a-c)+abs(b-d);

}

int main() {

    scanf("%d%d",&n,&m);

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

        scanf("%s",Map[i]);

    }

    int cn=0;

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

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

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

                if(cn<=1005) {

                    point[cn++]=node(i,j);

                }

                else {

                    break;

                }

            }

        }

    }

    if(cn<1000) {

        int ans=0;



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

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

                int Min=0x3f3f3f3f;

                if(Map[i][j]=='.') {

                    for(int k=0;k<cn;k++) {

                        Min=min(Min,dis(i,j,point[k].a,point[k].b));

                    }

                    ans=max(ans,Min);

                }

            }

        }

        printf("%d\n",ans);

        return 0;

    }

    int ans=0;

    while(true) {

        bool falg=false;

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

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

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

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

                        int _x=i+turn[k][0];

                        int _y=j+turn[k][1];

                        judge(_x,_y);

                    }

                }

                else {

                    falg=true;

                }

            }

        }



        if(!falg) break;

        ans++;

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

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

                if(Map[i][j]=='*') Map[i][j]='#';

            }

        }

    }

    printf("%d\n",ans);

}