#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
struct __INIT{__INIT(){cin.tie(0);ios::sync_with_stdio(false);cout<<fixed<<setprecision(15);}} __init;
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
#define MOD 1000000007
#define INF (1<<30)
#define LINF (lint)(1LL<<56)
#define endl "\n"
#define rep(i,n) for(int (i)=0;(i)<(n);(i)++)
#define reprev(i,n) for(int (i)=(n-1);(i)>=0;(i)--)
#define Flag(x) (1<<(x))
#define Flagcount(x) __builtin_popcount(x)
#define pint pair<int,int>
#define pdouble pair<double,double>
#define plint pair<lint,lint>
typedef unsigned long long int ull;
typedef long long lint;

int main(void){
    int H,W;
    cin >> H >> W;
    char S[H][W];
    rep(i,H) cin >> S[i];
    bool reach[H][W]={};
    int dis[H][W];
    int ans=0;
    rep(k,H) rep(l,W){
        if(S[k][l]=='#') continue;
        rep(i,H) rep(j,W) dis[i][j]=INF,reach[i][j]=false;
        dis[k][l]=0;
        queue<pint> q;
        q.push(pint(k,l));
        while(!q.empty()){
            pint p=q.front();
            q.pop();
            if(p.first<0 || p.first>=H || p.second<0 || p.second>=W) continue;
            if(reach[p.first][p.second]) continue;
            reach[p.first][p.second]=true;
            if(p.first<H-1) if(S[p.first+1][p.second]!='#') q.push(pint(p.first+1,p.second));
            if(p.first>0) if(S[p.first-1][p.second]!='#') q.push(pint(p.first-1,p.second));
            if(p.second<W-1) if(S[p.first][p.second+1]!='#') q.push(pint(p.first,p.second+1));
            if(p.second>0) if(S[p.first][p.second-1]!='#') q.push(pint(p.first,p.second-1));
            if(p.first!=0) dis[p.first-1][p.second]=min(dis[p.first-1][p.second],dis[p.first][p.second]+1);
            if(p.first!=H-1) dis[p.first+1][p.second]=min(dis[p.first+1][p.second],dis[p.first][p.second]+1);
            if(p.second!=0) dis[p.first][p.second-1]=min(dis[p.first][p.second-1],dis[p.first][p.second]+1);
            if(p.second!=W-1) dis[p.first][p.second+1]=min(dis[p.first][p.second+1],dis[p.first][p.second]+1);
        }
        rep(i,H) rep(j,W) if(dis[i][j]!=INF) ans=max(ans,dis[i][j]);
    }
  cout << ans << endl;
}