#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using Point = pair<int, int>;

// #define int ll
#define REP(i,n) for (int i = 0; i < (n); ++i)
#define FORE(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define debug(x) cerr << #x << ": " << x << '\n'
#define hyphen() cerr << "--\n"

#define ALL(vec) (vec).begin(), (vec).end()
#define REVALL(vec) (vec).rbegin(), (vec).rend()

#define fst first
#define pb push_back

const int MOD = (int)1e9 + 7;

bool is_valid_point(const int H, const int W, const vector<vector<bool>> S, const int y, const int x) {
    return 0 <= y && y < H && 0 <= x && x < W && S.at(y).at(x);
}

vector<Point> get_next_points(const int y, const int x) {
    vector<Point> ans(4);
    ans.at(0) = make_pair(y, x+1);
    ans.at(1) = make_pair(y, x-1);
    ans.at(2) = make_pair(y+1, x);
    ans.at(3) = make_pair(y-1, x);

    return ans;
}

int distance(const int H, const int W, const vector<vector<bool>> S, const int start_h, const int start_w) {
    vector<vector<int>> d(H, vector<int>(W, -1));
    d.at(start_h).at(start_w) = 0;

    queue<Point> q;
    q.push(make_pair(start_h, start_w));

    int ans = 0;

    while(!q.empty()) {
        Point p = q.front();
        q.pop();

        int y = p.first;
        int x = p.second;

        vector<Point> next_points = get_next_points(y, x);
        for (auto next_p : next_points) {
            int next_y = next_p.first;
            int next_x = next_p.second;

            if (!is_valid_point(H, W, S, next_y, next_x)) {
                continue;
            }

            // もう通ったことがあるなら更新しない
            if (d.at(next_y).at(next_x) != -1) {
                continue;
            }

            int new_distance = d.at(y).at(x) + 1;
            // debug(y);
            // debug(y);
            // debug(d.at(y).at(x));
            // debug(next_y);
            // debug(next_x);
            // debug(new_distance);
            // hyphen();

            d.at(next_y).at(next_x) = new_distance;
            ans = max(ans, new_distance);
            q.push(next_p);
        }
    }
    return ans;
}

signed main() {
    int H, W;
    cin >> H >> W;

    // そのマスが通れるならtrue
    vector<vector<bool>> S(H, vector<bool>(W, false));

    REP(h, H) {
        string s;
        cin >> s;

        REP(w, W) {
            if (s.at(w) == '.') {
                S.at(h).at(w) = true;
            } else if (s.at(w) == '#') {
                S.at(h).at(w) = false;
            }
        }
    }

    int ans = 0;

    // 全探索
    REP(start_h, H) {
        REP(start_w, W) {
            if (!S.at(start_h).at(start_w)) {
                    continue;
            }

            // REP(goal_h, H) {
            //     REP(goal_w, W) {
            // if (!S.at(goal_h).at(goal_w)) {
            //     continue;
            // }

            // if (start_h == goal_h && start_w == goal_w) {
            //     continue;
            // }
            int d = distance(H, W, S, start_h, start_w);
            // int d = distance(H, W, S, start_h, start_w, goal_h, goal_w);
            ans = max(ans, d)
    //     }
    // }
        }
    }
    cout << ans << endl;
}
