#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <functional>
#include <iostream>
using namespace __gnu_pbds;
using namespace std;

typedef long long ll;

#define pf(n) cout << n << endl
#define ps() cout <<" ";
#define sf(n) cin >> n
#define in(i,n) for (int i = 0; i < n; i++)
#define vi vector<int>
#define vp vector<pair<int, int>>
#define graph vector< vector<int> >
/**  '' "\n" ^ - = + **/


typedef tree<ll, null_type, less_equal<ll>, rb_tree_tag,
                 tree_order_statistics_node_update>
        new_data_set;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,m;
    cin>>n>>m;
    vector<vi> g(n*m);
    vector<string> str(n);

    for(int i=0;i<n;i++)
    {
        cin>>str[i];
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<str[i].length();j++)
        {
            if(i>0&&str[i-1][j]=='.')
            {
                g[(i*m)+j].push_back(((i-1)*m)+j);
            }
            if(i+1<n&&str[i+1][j]=='.')
            {
                g[(i*m)+j].push_back(((i+1)*m)+j);
            }


            if(j>0&&str[i][j-1]=='.')
            {
                g[(i*m)+j].push_back((i*m)+(j-1));
            }
            if(j+1<m&&str[i][j+1]=='.')
            {
                g[(i*m)+j].push_back((i*m)+(j+1));
            }
        }
    }
    int start=0;
    for(int i=0;i<n*m;i++)
    {
        if(g[i].size())
        {
            start=i;
            break;
        }
    }
    //cout<<start<<endl;

    queue<int> q;
    bool visited[n*m];
    ll distance[n*m];
    for(int i=0;i<n*m;i++)
    {
        visited[i]=false;
        distance[i]=0;
    }

    visited[start] = true;
    distance[start] = 0;
    q.push(start);
    ll mx=0,in=0;
    while (!q.empty()) {
       int s = q.front(); q.pop();
       // process node s
       //cout<<s;ps();
       for (auto u : g[s]) {
       if (visited[u]) continue;
          visited[u] = true;
          distance[u] = distance[s]+1;
          if(distance[u]>mx)
          {
              mx=distance[u];
              in=u;
          }
          q.push(u);
          }
      }
      //cout<<endl;
      start=in;
      mx=0;

    queue<int> q1;
    bool visited1[n*m];
    ll distance1[n*m];
    for(int i=0;i<n*m;i++)
    {
        visited1[i]=false;
        distance1[i]=0;
    }
    visited1[start] = true;
    distance1[start] = 0;
    q1.push(start);
    //int mx=0,in=0;
    while (!q1.empty()) {
       int s = q1.front(); q1.pop();
       // process node s
       for (auto u : g[s]) {
       if (visited1[u]) continue;
          visited1[u] = true;
          distance1[u] = distance1[s]+1;
          if(distance1[u]>mx)
          {
              mx=distance1[u];
              in=u;
          }
          q1.push(u);
          }
      }
      cout<<mx<<endl;
}
