// Original C++ solution (slower):
#include<bits/stdc++.h>

#include<ext/pb_ds/assoc_container.hpp>

#include<ext/pb_ds/tree_policy.hpp>



using namespace std;

using namespace __gnu_pbds;



/* msi1427 */



#define ll           long long

#define ull          long long unsigned

#define LD           long double

#define FOR(i,n)     for(int i=0;i<n;i++)

#define FLR(i,n)     for(ll i=0;i<n;i++)

#define RFOR(i,n)    for(int i=n-1;i>=0;i--)

#define RFLR(i,n)    for(ll i=n-1;i>=0;i--)

#define rep(i,a,b)   for(int i=a;i<=b;i++)

#define repl(i,a,b)  for(ll i=a;i<=b;i++)

#define casep(z)     cout << "Case " << z << ": ";

#define Fast         ios_base::sync_with_stdio(0);cin.tie(0);

#define sz(a)        a.size()

#define all(x)       x.begin(),x.end()

#define SORT(a,n)    sort(a,a+n)

#define RSORT(a,n)   sort(a,a+n,greater<ll>())

#define pii          pair<int,int>

#define pll          pair<ll,ll>

#define tll          tuple<ll,ll,ll>

#define VSORT(v)     sort(all(v))

#define VRSORT(v)    sort(v.rbegin(),v.rend())

#define pb           push_back

#define eb           emplace_back

#define pf           push_front

#define pob          pop_back()

#define pof          pop_front()

#define ff           first

#define ss           second

#define tt           true

#define fs           false

#define MP           make_pair

#define MEM(x,n)     memset((x),n,sizeof(x))

#define bsrch(a,n,x) binary_search(a,a+n,x)

#define vi           vector<int>

#define vll          vector<ll>

#define PI           acos(-1.0)

#define LB(a,x)      (lower_bound(all(a),x)-a.begin()) //  first element in the range [first,last) which does not compare less than val.

#define UB(a,x)      (upper_bound(all(a),x)-a.begin()) //  first element in the range [first,last) which compares greater than val.

#define PQ           priority_queue

#define heap         PQ< ll , vector<ll> , greater < ll > >

#define REV(x)       reverse(all(x))

#define mpii         map<int,int>

#define mpll         map<ll,ll>

#define cig          cin.ignore()

#define INF          (ll)1e18

#define EPS          1e-9

#define prec(n)      fixed << setprecision(n)

#define lb           lower_bound

#define ub           upper_bound

#define fin          freopen("in.txt","r",stdin)

#define fout         freopen("out.txt","w",stdout)

#define sc           scanf

#define pt           printf

#define np           next_permutation

#define IT(it,x)     for(auto it=x.begin();it!=x.end();it++)

#define sci(x)       scanf("%d",&x);

#define scl(x)       scanf("%lld",&x);

#define scd(x)       scanf("%lf",&x);

#define scs(x)       scanf("%s",x);



#define min3(a,b,c)     min(a,min(b,c))

#define max3(a,b,c)     max(a,max(b,c))

#define min4(a,b,c,d)   min(min(a,b),min(c,d))

#define max4(a,b,c,d)   max(max(a,b),max(c,d))

#define max5(a,b,c,d,e) max(max3(a,b,c),max(d,e))

#define min5(a,b,c,d,e) min(min3(a,b,c),min(d,e))

#define EulerGamma      0.57721566490153286060651209



typedef

tree<

  ll,

  null_type,

  less<ll>,

  rb_tree_tag,

  tree_order_statistics_node_update>

ordered_set;



ll dx[] = {1,-1,0,0};

ll dy[] = {0,0,1,-1};



ll ceiling(ll x,ll y)

{

    if(x%y) return ((x/y)+1);

    else return (x/y);

}



ll gcd(ll x,ll y)

{

    return ((y==0)?x:gcd(y,x%y));

}



ll lcm(ll x,ll y)

{

    return ((x*y)/gcd(x,y));

}



ll BMod(ll B,ll P,ll M)

{

    ll R=1;

    B=B%M;

    while(P)

    {

        if(P&1)

            R=(R*B)%M;

        P >>= 1;

        B=(B*B)%M;

    }

    return R;

}



bool check(ll n,ll pos) {return (n&(1<<pos));}

ll SET(ll n,ll pos){return (n|(1<<pos));}

ll RESET(ll n,ll pos) {return(n&~(1<<pos));}

mt19937 rng32(chrono::steady_clock::now().time_since_epoch().count());



#define MOD 1000000007

#define MAX 1000005



ll h,w,ad[705][705];

string s[25];



int main()

{

    Fast

    FLR(i,700) FLR(j,700) ad[i][j]=INF;

    cin>>h>>w;

    map<pll,ll>mp;

    ll c = 1;

    FLR(i,h) cin>>s[i];

    FLR(i,h) FLR(j,w){

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

            if(!mp[{i,j}]) mp[{i,j}]=c++;

            ll u = mp[{i,j}];

            if(i+1<h && s[i+1][j]=='.'){

                if(!mp[{i+1,j}]) mp[{i+1,j}]=c++;

                ll v = mp[{i+1,j}];

                ad[u][v]=1;

            }

            if(j+1<w && s[i][j+1]=='.'){

                if(!mp[{i,j+1}]) mp[{i,j+1}]=c++;

                ll v = mp[{i,j+1}];

                ad[u][v]=1;

            }

            if(i-1>=0 && s[i-1][j]=='.'){

                if(!mp[{i-1,j}]) mp[{i-1,j}]=c++;

                ll v = mp[{i-1,j}];

                ad[u][v]=1;

            }

            if(j-1>=0 && s[i][j-1]=='.'){

                if(!mp[{i,j-1}]) mp[{i,j-1}]=c++;

                ll v = mp[{i,j-1}];

                ad[u][v]=1;

            }

        }

    }

    repl(k,1,c) repl(i,1,c) repl(j,1,c) ad[i][j]=min(ad[i][j],ad[i][k]+ad[k][j]);

    ll mx = 0;

    repl(i,1,c) repl(j,1,c) if(i!=j) mx = max(mx,(ad[i][j]==INF)?0:ad[i][j]);

    cout << mx << "\n";

}

/*

4 4

####

#..#

####

####

*/


// Optimized solution to the same problem (faster):
//coded by: pranonrahman-------------------------------------

//-----------------------------------------------------------

//-----------------------------------------------------------

#include<bits/stdc++.h>

using namespace std;

#define O_o ios_base::sync_with_stdio(0)

#define O_O ios_base::sync_with_stdio(0); cin.tie(NULL)

#define o_O ios_base::sync_with_stdio(0); cin.tie(NULL); cout.tie(NULL)

#define fixedprecision(n) cout<<fixed<<setprecision(n)

#define endl '\n'

#define CASE(n) cout << "Case " << n << ": "

#define pi acos(-1.0)

#define _____(n) cout << "Dhukse " << n << endl



long long w,h;

char arr[25][25];

long long vis[25][25];

long long xx[]={+1,0,-1,0};

long long yy[]={0,+1,0,-1};

long long check(long long i,long long j)

{

    if(i<0 or i>=h or j<0 or j>=w or arr[i][j]=='#')  return 0;

    return 1;

}



long long bfs(long long i,long long j)

{

    long long mx =0;

    deque<pair<long long,long long>>dq;

    memset(vis,-1,sizeof(vis));

    dq.push_back({i,j});

    vis[i][j]=0;

    while(dq.size())

    {



        long long px = dq.front().first;

        long long py = dq.front().second;

        dq.pop_front();

        for(long long i=0;i<4;i++)

        {

           long long nx=px+xx[i];

           long long ny=py+yy[i];

           if(check(nx,ny)!=0 and vis[nx][ny]==-1 and arr[nx][ny]!='#')

           {

               vis[nx][ny]=vis[px][py]+1;

               mx = max(vis[nx][ny],mx);

               dq.push_back({nx,ny});

           }

        }

    }

   // for(long long i=0;i<h;i++)

   // {

  //      for(long long j=0;j<w;j++)    cout << vis[i][j] << ' ' ;

  //      cout<< endl;

 //   }

  //  cout << endl;

    return mx;

}



int main()

{

    O_o;

    long long t=1;

    //cin >> t;

    long long T=t;

    while(t--)

    {

        cin >> h >> w;

        for(long long i=0;i<h;i++)

        {

            for(long long j=0;j<w;j++)

            {

                cin >> arr[i][j];

            }

        }

        long long mx = 0;

       for(long long i=0;i<h;i++)

        {

            for(long long j=0;j<w;j++)

            {

                if(arr[i][j]!='#')

                {

                    mx = max(mx,bfs(i,j));

                }

            }

        }

        cout << mx << endl;



    }





    return 0;

}




// Fastest known solution for this problem: