#include <stdio.h>

#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>

using namespace std;

void __print(int x) { cerr << x; }
void __print(long x) { cerr << x; }
void __print(long long x) { cerr << x; }
void __print(unsigned x) { cerr << x; }
void __print(unsigned long x) { cerr << x; }
void __print(unsigned long long x) { cerr << x; }
void __print(float x) { cerr << x; }
void __print(double x) { cerr << x; }
void __print(long double x) { cerr << x; }
void __print(char x) { cerr << '\'' << x << '\''; }
void __print(const char *x) { cerr << '\"' << x << '\"'; }
void __print(const string &x) { cerr << '\"' << x << '\"'; }
void __print(bool x) { cerr << (x ? "true" : "false"); }

template <typename T, typename V>
void __print(const pair<T, V> &x) {
    cerr << '{';
    __print(x.first);
    cerr << ',';
    __print(x.second);
    cerr << '}';
}
template <typename T>
void __print(const T &x) {
    int f = 0;
    cerr << '{';
    for (auto &i : x) cerr << (f++ ? "," : ""), __print(i);
    cerr << "}";
}
void _print() { cerr << "]\n"; }
template <typename T, typename... V>
void _print(T t, V... v) {
    __print(t);
    if (sizeof...(v)) cerr << ", ";
    _print(v...);
}
#ifdef LOCAL
#define debug(x...)               \
    cerr << "[" << #x << "] = ["; \
    _print(x)
#else
#define debug(x...)
#endif

#define UNIQUE(v) v.erase(unique(v.begin(), v.end()), v.end());
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

typedef long long ll;
const ll INF = 1000000000;

queue<pair<int, int>> q;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);

    int H, W;
    cin >> H >> W;
    vector<vector<char>> S(H, vector<char>(W));
    int dx[4] = {1, 0, -1, 0};
    int dy[4] = {0, 1, 0, -1};
    int max_ans = 0;
    rep(y, H) {
        rep(x, W) { cin >> S[y][x]; }
    }
    rep(y_s, H) {
        rep(x_s, W) {
            rep(y_g, H) {
                rep(x_g, W) {
                    if (S[y_s][x_s] == '#') continue;
                    if (S[y_g][x_g] == '#') continue;
                    vector<vector<ll>> d(H, vector<ll>(W, INF));
                    pair<int, int> start = {y_s, x_s};
                    pair<int, int> goal = {y_g, x_g};
                    queue<pair<int, int>> que;
                    que.push(start);
                    d[start.first][start.second] = 0;
                    while (que.size()) {
                        pair<int, int> p = que.front();
                        que.pop();
                        if (p.first == goal.first && p.second == goal.second) {
                            break;
                        }
                        for (int i = 0; i < 4; i++) {
                            int ny = p.first + dy[i], nx = p.second + dx[i];
                            if (0 <= nx && nx < W && 0 <= ny && ny < H &&
                                S[ny][nx] != '#' && d[ny][nx] == INF) {
                                que.push({ny, nx});
                                d[ny][nx] = d[p.first][p.second] + 1;
                            }
                        }
                    }
                    int ans = d[goal.first][goal.second];
                    if (ans > max_ans && ans != INF) {
                        max_ans = ans;
                    }
                    debug(start, goal, d, ans);
                }
            }
        }
    }
    cout << max_ans << endl;

    return 0;
}


Measured memory_bytes: 256