#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 ull;
typedef long 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 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 bb break
#define rem 1000000007
#define debug(n1) cout << "debug... " << n1 << "\n"
#define PI 3.141592653589793238462643383279502
//fflush(stdin);
// do {
// // process permutation
// } while (next_permutation(permutation.begin(),permutation.end()));
class abc
{
public:
    ll x, y;
};
void bfs(ll node, ve<ll> adj[], ve<bool> visit, ve<ll> &dis)
{
    queue<ll> q;
    // ve<bool> visit(n+1);
    // ve<ll> dis(n+1);
    visit[node] = true;
    dis[node] = 0;
    q.push(node);
    while (!q.empty())
    {
        ll s = q.front();
        q.pop();
        // process node s
        for (auto u : adj[s])
        {
            if (visit[u])
                continue;
            visit[u] = true;
            dis[u] = dis[s] + 1;
            q.push(u);
        }
    }
}
// ll dis(ll x1, ll y1, ll x2, ll y2, ve<ll> adj[], ll h, ll w)
// {
//     ll start = x1 * h + y1;
//     ll end = x2 * h + y2;
//     ve<ll> dd(405, 0);
//     ve<bool> visit(405, false);
//     bfs(start, adj, visit, dd);
//     return dd[end];
// }
int main()
{
    FAST
        // freopen("input1.txt", "r", stdin);
        // freopen("output.txt", "w", stdout);
        /*ll tests;
    cin>>tests;
    rep (gg,0,tests)
    {}*/
        ll h,
        w;
    cin >> h >> w;
    ve<string> arr(h);
    rep(i, 0, h)
    {
        cin >> arr[i];
    }
    ve<ll> adj[h * w + 1];
    rep(i, 0, h)
    {
        rep(j, 0, w - 1)
        {
            if (arr[i][j] == '.' && arr[i][j + 1] == '.')
            {
                adj[i * w + j].pb(i * w + j + 1);
                adj[i * w + j + 1].pb(i * w + j);
            }
        }
    }
    rep(i, 0, w)
    {
        rep(j, 0, h - 1)
        {
            if (arr[j][i] == '.' && arr[j + 1][i] == '.')
            {
                adj[j * w + i].pb((j+1) * w + i);
                adj[(j+1) * w + i].pb(j * w + i);
            }
        }
    }
    // rep (i,0,h*w+1)
    // {
    //     cout<<i<<" ";
    //     rep (j,0,adj[i].size())
    //     {
    //         cout<<adj[i][j]<<" ";
    //     }
    //     cout<<"\n";
    // }
    ve<ll> ans;
    ve<bool> visit(405, false);
    rep(i, 0, h)
    {
        rep(j, 0, w)
        {
            ll start = i * w + j;
            ve<ll> dd(405, 0);
            bfs(start, adj, visit, dd);
            rep(i1, 0, h)
            {
                rep(j1, 0, w)
                {
                    if (arr[i][j] == '#' || arr[i1][j1] == '#')
                    {
                        cc;
                    }
                    if (i == i1 && j == j1)
                    {
                        ans.pb(1);
                        cc;
                    }
                    ll end = i1 * w + j1;
                    ans.pb(dd[end]);
                }
            }
        }
    }
    sort(all(ans));
    cout << *(ans.end() - 1) << "\n";
}


Measured memory_bytes: 2432