#pragma region Header
#ifdef DEBUG
#include "debug.hpp"
#else
#define NDEBUG
#define debug(...)
#define IFD(...)
#endif
#include <utility>
#include <cstdint>
#include <cmath>
#include <cassert>
#include <vector>
#include <array>
#include <deque>
#include <queue>
#include <stack>
#include <tuple>
#include <set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <string>
#include <functional>
#include <algorithm>
#include <numeric>
#include <stdexcept>
#include <iostream>
#include <iomanip>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using u32 = uint32_t;
using u64 = uint64_t;
#define rep(i, n) for (int i = 0; i < static_cast<int>(n); ++i)
#define repd(i, n) for (int i = static_cast<int>(n) - 1; i >= 0; --i)
#define FOR(i, a, b) for (int i = static_cast<int>(a); i <= static_cast<int>(b); ++i)
#define FORD(i, b, a) for (int i = static_cast<int>(b); i >= static_cast<int>(a); --i)
template <typename T>
int SZ(T const &x)
{
    return static_cast<int>(x.size());
}
template <class T>
bool chmax(T &a, T const &b)
{
    if (a < b)
    {
        a = b;
        return true;
    }
    return false;
}
template <class T>
bool chmin(T &a, T const &b)
{
    if (b < a)
    {
        a = b;
        return true;
    }
    return false;
}
#pragma endregion

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int h, w;
    cin >> h >> w;
    vector can(h, vector(w, false));
    rep(y, h)
    {
        rep(x, w)
        {
            char c;
            cin >> c;
            can[y][x] = (c == '.');
        }
    }

    constexpr int INF = 401;

    auto mat = [&](int y1, int x1, int y2, int x2) {
        int d = abs(y1 - y2) + abs(x1 - x2);
        return (d != 1) ? INF : d;
    };

    vector dp(h, vector(w, vector(h, vector(w, INF))));
    rep(y1, h)
    {
        rep(x1, w)
        {
            rep(y2, h)
            {
                rep(x2, w)
                {
                    dp[y1][x1][y2][x2] = mat(y1, x1, y2, x2);
                }
            }
        }
    }
    rep(hk, h)
    {
        rep(wk, w)
        {
            if (not can[hk][wk])
            {
                continue;
            }
            rep(hi, h)
            {
                rep(wi, w)
                {
                    if (not can[hi][wi])
                    {
                        continue;
                    }
                    rep(hj, h)
                    {
                        rep(wj, w)
                        {
                            if (not can[hj][wj])
                            {
                                continue;
                            }
                            chmin(dp[hi][wi][hj][wj], dp[hi][wi][hk][wk] + dp[hk][wk][hj][wj]);
                        }
                    }
                }
            }
        }
    }

    int ans = 0;
    rep(y, h)
    {
        rep(x, w)
        {
            if (not can[y][x])
            {
                continue;
            }
            rep(y2, h)
            {
                rep(x2, w)
                {
                    if (not can[y2][x2])
                    {
                        continue;
                    }
                    chmax(ans, dp[y][x][y2][x2]);
                }
            }
        }
    }
    cout << ans << '\n';

    return 0;
}
