#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define ll long long
#define ld long double
#define fi first
#define se second
#define pb push_back
#define all(v) v.begin(),v.end()
#define repf(i,a,b) for(ll i=a;i<b;i++)
#define repb(i,a,b) for(ll i=a;i>=b;i--)
#define IOS ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define mod 1000000007
#define MOD 998244353 

using namespace std;
using namespace __gnu_pbds;

template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};

ll power(ll a, ll n, ll m)
{
    ll ans=1;
    while(n)
    {
        if(n&1) ans=(ans*a)%m;
        n>>=1;
        a=(a*a)%m;
    }
    return ans;
}

string s[20];
ll h,w;

ll f(int sx, int sy, int ex, int ey)
{
    vector<vector<ll>> dp(h,vector<ll>(w,-1));
    queue<pair<int,int>> q;
    q.push({sx,sy});
    dp[sx][sy]=0;
    while(!q.empty())
    {
        int x=q.front().fi;
        int y=q.front().se;
        q.pop();
        if(x==ex && y==ey) return dp[x][y];
        repf(i,0,4)
        {
            repf(j,0,4)
            {
                int nx=x+dx[i];
                int ny=y+dy[i];
                if(nx>=0 && nx<h && ny>=0 && ny<w && s[nx][ny]=='.' && dp[nx][ny]==-1)
                {
                    q.push({nx,ny});
                    dp[nx][ny]=dp[x][y]+1;
                }
            }
        }
    }
    return -1;
}

int main()
{
    IOS; 
    cin>>h>>w;
    repf(i,0,h) cin>>s[i];
    ll ans=0;
    repf(i,0,h)
    {
        repf(j,0,w)
        {
            if(s[i][j]=='#') continue;
            repf(k,0,h)
            {
                repf(l,0,w)
                {
                    if(s[k][l]=='#') continue;
                    ans=max(ans,f(i,j,k,l));
                }
            }
        }
    }
    cout<<ans<<endl;
}  