#include <bits/stdc++.h>
using namespace std;
 
#define REP(i, s) for (int i = 0; i < s; ++i)
#define ALL(v) (v).begin(), (v).end()
#define COUT(x) cout << #x << " = " << (x) << " (L" << __LINE__ << ")" << endl
#define EACH(i, s) for (__typeof__((s).begin()) i = (s).begin(); i != (s).end(); ++i)
#define DEBUG
#define int long long
#define INF 1e18
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }
template<class T1, class T2> ostream& operator << (ostream &s, pair<T1,T2> P)
{ return s << '<' << P.first << ", " << P.second << '>'; }
template<class T> ostream& operator << (ostream &s, vector<T> P)
{ for (int i = 0; i < P.size(); ++i) { if (i > 0) { s << " "; } s << P[i]; } return s; }
template<class T> ostream& operator << (ostream &s, vector<vector<T> > P)
{ for (int i = 0; i < P.size(); ++i) { s << endl << P[i]; } return s << endl; }
template<class T> ostream& operator << (ostream &s, set<T> P)
{ EACH(it, P) { s << "<" << *it << "> "; } return s << endl; }
template<class T1, class T2> ostream& operator << (ostream &s, map<T1,T2> P)
{ EACH(it, P) { s << "<" << it->first << "->" << it->second << "> "; } return s << endl; }
template<class T>void show(vector<T>v){for (int i = 0; i < v.size(); i++){cerr<<v[i]<<" ";}cerr<<"\n";}
typedef long long ll;


struct Corr
{
    ll y;
    ll x;
    ll depth;
};

vector<string> vec;
vector<ll> y_vec = {0, 0, -1, +1}; // 進む方向の簡便化，テクニックとして覚えておく．
vector<ll> x_vec = {-1, +1, 0, 0}; // ループで回すことで上下左右に移動できるようになっている
ll y, x, depth;

bool ok[30][30];
int h, w;
ll bfs(queue<Corr> q,ll s_y ,ll s_x, ll g_y, ll g_x)
{
    while (!q.empty())
    {
        Corr now = q.front();
        q.pop();                                 // キューの先頭を取り出す
        y = now.y, x = now.x, depth = now.depth; // 行，列が y, x になっているので注意

        // 停止条件：現在の座標がゴールなら深さを返す
        if (y == g_y && x == g_x)
            return depth;

        // 上下左右 4 方向を探索．進むことができればキューに格納する．
        for (ll i = 0; i < 4; ++i)
        {
            Corr next = {y + y_vec[i], x + x_vec[i], depth + 1};
            if (0 <= next.y && next.y <= h - 1 && 0 <= next.x && next.x <= w - 1 && vec[next.y][next.x] == '.')
            {
                vec[next.y][next.x] = 'x'; // 同じ場所を探索しないようにする
                q.push(next);
            }
        }
    }
    return 0;
}


signed main()
{
 
    cin >> h >> w;
    vec.resize(h);
    for (ll i = 0; i < h; ++i)
        cin >> vec[i];
    int ans = 0;
    for (int s_x = 0; s_x < w; s_x++)
    {
        for (int s_y = 0; s_y < h; s_y++)
        {
            for (int g_x = 0; g_x < w; g_x++)
            {
                for (int g_y = 0; g_y < h; g_y++)
                {
                    if(vec[s_y][s_x]== '#' || vec[g_y][g_x]=='#' )
                        continue;
                    queue<Corr> q;
                    Corr start = {s_y, s_x, 0};
                    q.emplace(start);
                    
                    int tmp = bfs(q, s_y, s_x, g_y, g_x);
                 //   cerr << tmp << endl;
                    chmax(ans, tmp);
                    for (int i = 0; i < h; i++)
                    {
                        for (int j = 0; j < w; j++)
                        {
                            if(vec[i][j]=='x')
                                vec[i][j] = '.';
                        }
                    }
                    
                }
            }
            
        }
        
    }
    cout << ans << endl;

    return 0;
}

Measured memory_bytes: 256