#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
typedef    long long int ll;
typedef unsigned long long int sll;
typedef  double ld;
typedef tree <int,null_type,less <int>, rb_tree_tag, tree_order_statistics_node_update> indexed_set;
#define rep(g, i, n) for (ll g = i; g < n; g++)
#define rev(g, n, i) for (ll g = n - 1; g >= i; g--)
#define FAST ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define all(v) v.begin(), v.end()
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define mp make_pair
 
#define um unordered_multiset
#define us unordered_set
#define mxe(v) *max_element(v.begin(),v.end())
#define mne(v) *min_element(v.begin(),v.end())
#define bs binary_search
#define lb lower_bound
#define ub upper_bound
#define ve vector
#define cc continue
#define br break
#define rem 500009
#define PI 3.1415926535
 
ll n,m=0,k=0;
 ll A=998244353 ;
 bool bbb;
 ll dis[200005]={0};
 
 
 ve <ll> adj[1000005];
 
 ll a[1000];
 
ll b[1000];
 bool vis[2000005]={0};
 ll cnt[2000005]={0};
 ve<ll> path;
 ve <ll> v;
bool prime[100];
 queue <ll> q;
 queue <ll> p;
 
 bool isb()
 { b[1]=1;
   q.push(1);
   while(!q.empty())
   {
                          ll x=q.front();
                          q.pop();
                          for(auto u:adj[x])
                          {
                                                 if(b[u]==-1){b[u]=1-b[x];}
                                                 else if(b[u]==b[x]){return false;}
                          }
   }
                        
 }
 
ll power(ll x,  ll y, ll p) 
{ 
    ll res = 1;      // Initialize result 
  
    x = x % p;  // Update x if it is more than or  
                // equal to p 
  
    while (y > 0) 
    { 
        // If y is odd, multiply x with result 
        if (y & 1) 
            res = (res*x) % p; 
  
        // y must be even now 
        y = y>>1; // y = y/2 
        x = (x*x) % p;   
    } 
    return res; 
} 
 
 
void SieveOfEratosthenes(ll n) 
{ 
    // Create a boolean array "prime[0..n]" and initialize 
    // all entries it as true. A value in prime[i] will 
    // finally be false if i is Not a prime, else true. 
    //bool prime[n+1]; 
   // memset(prime, true, sizeof(prime)); 
  
    for (ll p=2; p*p<=n; p++) 
    { 
        // If prime[p] is not changed, then it is a prime 
        if (prime[p] == true) 
        { 
            // Update all multiples of p greater than or  
            // equal to the square of it 
            // numbers which are multiple of p and are 
            // less than p^2 are already been marked.  
            for (int i=p*p; i<=n; i += p) 
                prime[i] = false; 
        } 
    } 
  
    
} 
ll gcd(ll a,ll b)
{
 if(a%b==0)return b;
 else {return gcd(b,a%b);}
}
ll poww(ll x,ll y)
{
                       ll res=1;
                       ll i=0;
                       while(i<y)
                       {
                                              res*=(x);
                                              i++;
                       }
                       return res;
}
 
 
 
ll getsq(ll x)
{
                       ll l=sqrt(x);
                       for( ll i=-2;i<=2;i++)
                       {
                                              if(l+i>=0&&(l+i)*(l+i)==x)
                                              return l;
                       }
                       return -1;
}
 ll inv(ll x)
 {
    return power(x,A-2,A);                    
 }
bool comp(const pair<pair<ll,ll>,ll> &a,const pair<pair<ll,ll>,ll> &b)
{
       if(a.first.first<b.first.first)return true; 
       else if(a.first.first==b.first.first)
       {
                              if(a.first.second>b.first.second)return true;
                              else{return false;}
       }
       else{return false;}
}
   
ll maxSubArraySum(ll a[], ll size) 
{ 
   ll max_so_far = a[0]; 
   ll curr_max = a[0]; 
  
   for (ll i = 1; i < size; i++) 
   { 
        curr_max = max(a[i], curr_max+a[i]); 
        max_so_far = max(max_so_far, curr_max); 
   } 
   return max_so_far; 
} 
 void dfs(ll x,ve <ll> adj[],bool vis[])
 {
     vis[x]=true;
     
     v.pb(x);
    dis[x]=1;
    
     for(auto u : adj[x])
     {
         if(vis[u]==0)
         {  
                                 
                                
                                dfs(u,adj,vis);
                                dis[x]+=dis[u];
         }
     }
  
 }
 void bfs (ll x,bool vis[],ll dis[])
 { vis[x]=true;
   
   q.push(x);
   while(!q.empty())
   {
   ll s=q.front();q.pop();
     for(auto i=adj[s].begin();i!=adj[s].end();i++)
     {     if(vis[*i]){continue;}
         vis[*i]=true;
         q.push(*i);
         dis[*i]=dis[s]+1;                   
     }
   
   }
                        
 }
void solve()
{
                       ll h,w;cin>>h>>w;
                       char c[h+2][w+2];
                       rep(i,1,h+1)
                       {
                                              rep(j,1,w+1)
                                              {cin>>c[i][j];}
                       }
                       rep(i,1,h+1)
                       {
                                              rep(j,1,w+1)
                                              {
                                                if(i<h&&c[i][j]=='.'&&c[i+1][j]=='.'){adj[w*(i-1)+j].pb(w*i+j);adj[w*(i)+j].pb(w*(i-1)+j);}  
                                                if(j<w&&c[i][j]=='.'&&c[i][j+1]=='.'){adj[w*(i-1)+j].pb(w*(i-1)+j+1);adj[w*(i-1)+j+1].pb(w*(i-1)+j);}  
                                                
                                              }
                       }
                      
                       ll ans=0;
                       rep(i,1,h+1)
                       {
                                              rep(j,1,w+1)
                                              {if(vis[w*(i-1)+j]==0&&c[i][j]=='.')
                                              {bfs(w*(i-1)+j,vis,dis);
                                                rep(k,1,h+1)
                                              {
                                              rep(l,1,w+1)
                                              { ans=max(ans,dis[w*(k-1)+l]);}
                                              }  
                                               rep(k,1,h+1)
                                              {
                                              rep(l,1,w+1)
                                              { dis[w*(k-1)+l]=0;vis[w*(k-1)+l]=0;}
                                              }
                                              ///cout<<ans<<" ";
                                              }
                                                                     
                                                    
                                              
                                              }
                       }
                       
                       cout<<ans;
}
 
 
int main()
{ FAST;
 
    ll t=1;//cin>>t;
   
    while(t--){
                           solve();
    }
    return 0;
}

Measured memory_bytes: 27008