// https://atcoder.jp/contests/abcXXX/tasks/abcXXX_x

#include <iostream>
#include <vector>
#include <tuple>
#include <algorithm>
#include <string>
#include <cmath>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>

using namespace std;
using ll = long long;
using ull = unsigned long long;
using pll = pair<ll, ll>;

static const ll INF = 1001001001;
static const ll LLINF = 1001001001001001001;

#define REP(i, n) for(ll i = 0; i < (n); ++i)
#define RANGE(i, m, n) for(ll i = (m); i <= (n); ++i)

void debug_out() {}
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
    cerr << " " << to_string(H);
    debug_out(T...);
}
#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 1
#endif

static const int dy[4] = { -1, 0, 1, 0};
static const int dx[4] = { 0, 1, 0, -1};

#define INDEX(i,j) ((i)*W+(j))

int run(istream& in, ostream& out) {
    ll H{}, W{};
    in >> H >> W;
    vector<string> v(H);
    vector<vector<ll>> dist(H*W, vector<ll>(H*W, INF));
    REP(i, H) {
        in >> v[i];
    }
    REP(i1, H) {
        REP(j1, W) {
            if (v[i1][j1] == '#') {
                continue;
            }
            dist[INDEX(i1, j1)][INDEX(i1, j1)] = 0;
            REP(i, 4) {
                auto y = i1 + dy[i];
                auto x = j1 + dx[i];
                if (x >= 0 && y >= 0 && x < W && y < H && v[y][x] == '.') {
                    dist[INDEX(i1, j1)][INDEX(y, x)] = 1;
                    dist[INDEX(y, x)][INDEX(i1, j1)] = 1;
                }
            }
        }
    }

    REP(i2, H) {
        REP(j2, W) {
            if (v[i2][j2] == '#') {
                continue;
            }
            REP(i1, H) {
                REP(j1, W) {
                    if (v[i1][j1] == '#') {
                        continue;
                    }
                    REP(i3, H) {
                        REP(j3, W) {
                            if (v[i3][j3] == '#') {
                                continue;
                            }
                            auto direct = dist[INDEX(i1, j1)][INDEX(i3, j3)];
                            auto pass_by = dist[INDEX(i1, j1)][INDEX(i2, j2)] + dist[INDEX(i2, j2)][INDEX(i3, j3)];
                            if(direct > pass_by) {
                                dist[INDEX(i1, j1)][INDEX(i3, j3)] = pass_by;
                                dist[INDEX(i3, j3)][INDEX(i1, j1)] = pass_by;
                            }
                        }
                    }
                }
            }
        }
    }
    ll max_dist = 0;
    REP(i1, H) {
        REP(j1, W) {
            if (v[i1][j1] == '#') {
                continue;
            }
            REP(i2, H) {
                REP(j2, W) {
                    if (v[i2][j2] == '#') {
                        continue;
                    }
                    auto candidate = dist[INDEX(i1,j1)][INDEX(i2,j2)];
                    if (candidate < INF) {
                        max_dist = max(max_dist, candidate);
                        max_dist = max_dist;
                    }
                }
            }
        }
    }
    out << max_dist << endl;
    return 0;
}

int main() {
    return run(cin, cout);
}


Measured memory_bytes: 1536