#include"bits/stdc++.h"
using namespace std;
#define REP(k,m,n) for(int (k)=(m);(k)<(n);(k)++)
#define rep(i,n) REP((i),0,(n))
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using tp3 = tuple<int, int, int>;
using Mat = vector<vector<ll>>;
constexpr int INF = 1 << 28;
constexpr ll INFL = 1ll << 60;
constexpr int dh[4] = { 0,1,0,-1 };
constexpr int dw[4] = { -1,0,1,0 };
bool isin(const int H, const int W, const int h, const int w) {
    return 0 <= h && h < H && 0 <= w && w < W;
}
template<typename T>
void output(const T& val) {
    cout << val << endl;
}
template<typename T>
void output(const vector<T>& vec, const bool newline = false) {
    for (const T& val : vec)cout << val << (newline ? '\n' : ' '); cout << endl;
}
template<typename T>
void output(const vector<vector<T>>& mat) {
    for (const auto& row : vec)output(row);
}
// ============ template finished ============

int solve(const vector<string>& maze, const int sh, const int sw) {
    const int H = maze.size(), W = maze.front().size();
    vector<vector<int>> d(H, vector<int>(W, INF));
    priority_queue<tp3, vector<tp3>, greater<tp3>> pq;
    d[sh][sw] = 0;
    pq.push(make_tuple(0, sh, sw));
    while (!pq.empty()) {
        int score, h, w;
        tie(score, h, w) = pq.top(); pq.pop();
        rep(dir, 4) {
            int nh = h + dh[dir], nw = w + dw[dir];
            if (!isin(H, W, nh, nw) || maze[nh][nw] == '#' || d[nh][nw] <= score + 1)continue;
            d[nh][nw] = score + 1;
            pq.push(make_tuple(score + 1, nh, nw));
        }
    }
    int res = 0;
    for (const auto& row : d)for (const auto& col : row)if (col != INF)res = max(res, col);
    return res;
}

int main()
{
    int H, W;
    cin >> H >> W;
    vector<string> maze(H);
    rep(h, H)cin >> maze[h];

    int res = 0;
    rep(h, H)rep(w, W)if (maze[h][w] != '#')res = max(res, solve(maze, h, w));
    output(res);
    return 0;
}
