//
// author  : Abhishek
//
#include <bits/stdc++.h>
#include<chrono>

#define ll long long
#define db double
#define deb(x) cout<<#x<<": "<<x<<"\n"
#define all(x) x.begin(),x.end()
#define fo(i, n) for(i=0 ; i<n ; i++)
#define Fo(i, k, n) for(i=k ; i<n ; i++)

using namespace std;
using namespace chrono;

const ll MOD = 1000000007;
const ll N = 300005;  // array size
const ll inf = 10000000000000000;


void print(vector<ll> v) {
    ll i;
    fo(i, v.size())cout << v[i] << " ";
    cout << "\n";
}

void print(vector<pair<ll, ll> > v) {
    ll i;
    fo(i, v.size()) {
        cout << v[i].first << " " << v[i].second << "\n";
    }
}

vector<ll> read(ll n) {
    ll i;
    vector<ll> arr(n, 0);
    fo(i, n)cin >> arr[i];
    return arr;
}

vector<ll> read(ll n, ll k) {
    ll i;
    vector<ll> arr(n + k, 0);
    Fo(i, k, n + k)cin >> arr[i];
    return arr;
}

bool isEven(ll n) {
    return n % 2 == 0;
}

bool isOdd(ll n) {
    return n % 2 != 0;
}

ll n, m;
vector<string> str;
ll dp[100][100];
bool vis[100][100];
vector<ll> dx = {-1, 0, 0, 1};
vector<ll> dy = {0, -1, 1, 0};

bool isVal(ll i, ll j) {
    return (0 <= i && i < n && 0 <= j && j < m);
}

void dfs(ll x, ll y) {
    if (!isVal(x, y)) {
        return;
    }
    if (str[x][y] == '#')
        return;

    vis[x][y] = true;
    ll i;
    fo(i, 4) {
        if (isVal(x + dx[i], y + dy[i]) &&
            !vis[x + dx[i]][y + dy[i]] &&
            str[x + dx[i]][y + dy[i]] != '#') {
            dp[x + dx[i]][y + dy[i]] = dp[x][y] + 1;
            dfs(x + dx[i], y + dy[i]);
        }
    }
}


void bfs(ll x1, ll y1) {
    queue<pair<ll, ll> > q;
    dp[x1][y1] = 0;
    ll i, x, y;
    q.push({x1, y1});
    while (!q.empty()) {
        pair<ll, ll> next = q.front();
        q.pop();
        x = next.first, y = next.second;
        vis[x][y] = true;
        fo(i, 4) {
            if (isVal(x + dx[i], y + dy[i]) &&
                !vis[x + dx[i]][y + dy[i]] &&
                str[x + dx[i]][y + dy[i]] != '#') {
                dp[x + dx[i]][y + dy[i]] = dp[x][y] + 1;
                q.push({x + dx[i], y + dy[i]});
            }
        }

    }
}

void solve() {
    ll t = 1;
//    cin >> (t);
    while (t--) {

        ll i, j, k, p, q, x, y, a, b, l, r;
        cin >> n >> m;
        bool has = 0;
        fo(i, n) {
            string s;
            cin >> s;
            str.push_back(s);
            fo(j, s.size()) {
                if (s[j] == '#') {
                    has = 1;
                }
            }
        }

        if (!has) {
            cout << n + m - 2;
            return;
        }


        ll ans = 0;

        fo(i, n) {
            fo(j, m) {
                if (str[i][j] == '.') {
                    fo(x, n) {
                        fo(y, m) {
                            dp[x][y] = -1;
                            vis[x][y] = false;
                        }
                    }
                    dp[i][j] = 0;
                    bfs(i, j);
                    ll mx = -1;
                    fo(x, n) {
                        fo(y, m) {
                            mx = max(mx, dp[x][y]);
                        }
                    }
                    ans = max(ans, mx);
                }
            }
        }
        cout << ans;


    }
}

int main() {

    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    freopen("error.txt", "w", stderr);
#endif

    auto start = high_resolution_clock::now();

    solve();

    ll i, j, k, n, m, p, q, x, y, a, b, l, r;


    auto stop = high_resolution_clock::now();
    auto duration = duration_cast<microseconds>(stop - start);
#ifndef ONLINE_JUDGE
    cerr << "Time: " << duration.count() / 1000.0 << endl;
#endif


    return 0;
}


Measured memory_bytes: 3528