#pragma GCC optimize("Ofast")
  
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <unordered_map>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <unordered_set>
#include <list>
#include <tuple>
#include <iomanip>
#include <climits>
#include <cstdlib>
#include <cassert>
#include <numeric>
#include <math.h>
#include <random>

using namespace std;
  
#define rep(i,n) for(int i=0;i<(n);++i)
#define reps(i,n) for(int i=1;i<=(n);++i)
#define all(x) (x).begin(),(x).end()
#define setout(n,x) setw(n+1) << setfill(x)
#define Fixed fixed << setprecision(14)
#define int int64_t
using pii = pair<int,int>;
constexpr int INF  = 0x3f3f3f3f;
constexpr long long LINF = 0x3f3f3f3f3f3f3f3fLL;
constexpr int mod = 1e9+7; 

constexpr int dy[] = {1,0,-1,0,1,-1,-1,1};
constexpr int dx[] = {0,1,0,-1,1,1,-1,-1};
 
template <class A, class B> inline bool chmax(A &a, const B &b) { return b > a && (a = b, true); }
template <class A, class B> inline bool chmin(A &a, const B &b) { return b < a && (a = b, true); }
 
template <class T> using min_heap = priority_queue<T,vector<T>,greater<T> >;
template <class T> using max_heap = priority_queue<T>;

int gcd(int a,int b){ return b ? gcd(b,a % b) : a;}
int lcm(int a,int b){ return a / gcd(a,b) * b;}

signed main(void){
    cin.tie(nullptr);
    ios_base::sync_with_stdio(false);

    int h,w;
    cin >> h >> w;

    vector<string> mat(h);
    vector<pii> pos(h*w);
    vector<vector<int> > num(h,vector<int>(w));

    int cnt = 0;
    rep(i,h){
        cin >> mat[i];
        rep(j,w){
            pos[cnt] = {i,j};
            num[i][j] = cnt;
            ++cnt;
        }
    }

    auto inside = [&](int y,int x){
        return (y < h && x < w && y >= 0 && x >= 0);
    };

    auto WarshallFloyd = [&](){
        vector<vector<int> > min_cost(h*w,vector<int>(h*w,INF));

        rep(i,h*w){
            min_cost[i][i] = 0;
        }

        rep(i,h){
            rep(j,w){
                if(mat[i][j] == '#') continue;
                rep(k,4){
                    int ny = i + dy[k];
                    int nx = j + dx[k];
                    if(inside(ny,nx) && mat[ny][nx] != '#'){
                        min_cost[num[i][j]][num[ny][nx]] = 1;
                        min_cost[num[ny][nx]][num[i][j]] = 1;
                    }
                }
            }
        }

        rep(i,h*w){
            rep(j,h*w){
                rep(k,h*w){
                    if(min_cost[j][i] == INF || min_cost[i][k] == INF) continue;
                    int pix,piy,pjx,pjy,pkx,pky;
                    tie(piy,pix) = pos[i];
                    tie(pjy,pjx) = pos[j];
                    tie(pky,pkx) = pos[k];
                    if(mat[piy][pix] == '#' || mat[pjy][pjx] == '#' || mat[pky][pkx] == '#') continue;
                    chmin(min_cost[j][k],min_cost[j][i] + min_cost[i][k]);
                }
            }
        }
        return min_cost;
    };

    int ans = 0;
    auto res = WarshallFloyd();
    
    rep(i,h*w){
        for(auto e : res[i]){
            if(e == INF) continue;
            else chmax(ans,e);
        }
    }

    cout << ans << '\n';

    return 0;
}

Measured memory_bytes: 1536