#include<iostream>
#include <bits/stdc++.h>
#include<string>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)
typedef pair<int,int> P;


const int INF = 1001001001;




int main(){
    //1行目を取得
    int h,w;
    cin >> h >> w;
    //1行ずつごと　h個のvectorに突っ込む
    vector<string> s(h);
    rep(i,h) cin >> s[i]; 
    //加算していくカウンター
    int ans = 0;
    //スタート地点を全探索する。スタート地点ごとにBFSを実行
    rep(si,h)rep(sj,w){
        //壁のマスはスルー
        if (s[si][sj] == '#') continue;
        //ベクターの2次元配列による到達番号表。初期値はINFにしておく
        vector<vector<int>> dist(h, vector<int>(w, INF));
        //BFS用のqueueを用意
        queue<P> q;
        //番号表のS[i][j]マスをx（到達番号）にアップデートする無名関数
        //アップデート後、対象のマスを次の処理待ちとしてqueueに追加もしている
        //[&]にすることで、無名関数内でdistやqを更新できるようにする。
        auto update = [&](int i, int j, int x){
            //対象マスが更新済みなら、再更新はしない。（大きい値への上書きを防ぐ）
            if (dist[i][j] != INF) continue;
            //xで更新
            dist[i][j] = x;
            //queueにS[i][j]を突っ込む。（隣接探しの処理待ちにする）
            q.push(P(i,j));
        }
        //スタート地点(si,sj)の番号表を0で更新
        update(si,sj,0);
        //BFS実行。queueがなくなるまで、「隣接する(最大4つの)マスを探し、到達番号表のupdate」を繰り返す
        while(!q.empty){
            //queueの最初の要素（front())から、座標i,jを取得する
            //要素はpair型なので、firstで1要素目、secondで2要素目を取得
            int i = q.front().first;
            int j = q.front().second;
            //最初の要素を使い終わったので、取り出す
            q.pop();
            //移動できる4方向で到達番号表のupdateを行う
            //4方向のdirを配列として定義しておくことで、for文（rep）でシンプルに書ける
            rep(dir,4){
                //ni -> Next i
                int ni = i+di[dir], nj = j+dj[dir];
                //移動できないケース（範囲外の場合、壁の場合）スルー
                if(ni < 0 || nj <0 || ni>=h || nj>=w) continue;
                if(S[ni][nj] =='#') continue;
                //(i,j)の到達番号＋1で、(ni,nj)をアップデート（さらにupdateの中でqueueにプッシュしている）
                update(ni,nj,dist[i][j]+1);
            }
        }
        rep(i,h)rep(j,w){
            //未更新の（=壁または到達不可能）マスはスルー
            if (dist[i][j] == INF) continue;
            //これまでの最大ans（別のスタート地点のものも含む）と、今回の番号表の(i,j)のうち、大きいものに更新
            ans = max(ans, dist[i][j]);
        }
    //出力
    cout << ans <<endl;
    return 0;
}