#pragma region RegionDefs
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#include "boost/multi_array.hpp"
#define rep(i,n) for(int i=0,i##_len=(n);i<i##_len;++i)
#define reps(i,j,n) for(int i=(j),i##_len=(n);i<i##_len;++i)
#define repr(i,n) for(int i=(n);i>=0;--i)
#define all(x) begin(x),end(x)
using namespace std;
template<class T=int> using P  = pair<T, T>;
template<class T=int> using V  = vector<T>;
template<class T=int> using PQ = priority_queue<T>;
template<class T=int> using PQG = priority_queue<T, V<T>, greater<T>>;
typedef long long ll;
const int INF = 1e9;
const ll MOD = 1000000007LL;
void in() {}
template<class Head, class... Tail>
void in(Head&& head, Tail&&... tail)
{
    cin >> head;
    in(move(tail)...);
}
#define IN(...) ll __VA_ARGS__; in(__VA_ARGS__)
//時間が厳しいとき使う
#define INI(...) int __VA_ARGS__; in(__VA_ARGS__)
#define INS(T, ...) T __VA_ARGS__; in(__VA_ARGS__)
#define VIN(T, v, n) V<T> v(n); for(auto& _elem:v)cin>>_elem
template<class T>bool chmax(T &a, const T &b) {if (a<b) {a=b; return 1;} return 0;}
template<class T>bool chmin(T &a, const T &b) {if (a>b) {a=b; return 1;} return 0;}
#define y0 y__0
#define y1 y__1
#define j0 j__0
#define j1 j__1
#pragma endregion RegionDefs

ll d[30][30];

pair<int,pair<int,int>> getDis(int x, int y, int w, int h)
{
    bool mark[30][30];
    ll dis[30][30];
    queue<pair<int,int>> q;
    dis[x][y] = 0;
    q.emplace(x, y);
    rep(j, w)
    {
        rep(i, h)
        {
            dis[i][j] = 0;
            mark[i][j] = !d[i][j];
        }
    }
    mark[x][y] = true;
    while (!q.empty())
    {
        auto p = q.front(); q.pop();
        if (p.first > 0 && !mark[p.first-1][p.second])
        {
            dis[p.first-1][p.second] = dis[p.first][p.second]+1;
            q.emplace(p.first-1, p.second);
            mark[p.first-1][p.second] = true;
        }
        if (p.second > 0 && !mark[p.first][p.second-1])
        {
            dis[p.first][p.second-1] = dis[p.first][p.second]+1;
            q.emplace(p.first, p.second-1);
            mark[p.first][p.second-1] = true;
        }
        if (p.first < h-1 && !mark[p.first+1][p.second])
        {
            dis[p.first+1][p.second] = dis[p.first][p.second]+1;
            q.emplace(p.first+1, p.second);
            mark[p.first+1][p.second] = true;
        }
        if (p.second < w-1 && !mark[p.first][p.second+1])
        {
            dis[p.first][p.second+1] = dis[p.first][p.second]+1;
            q.emplace(p.first, p.second+1);
            mark[p.first][p.second+1] = true;
        }
    }
    pair<int, int> m = make_pair(x, y);
    ll far = 0;
    rep(i, h)
    {
        rep(j, w)
        {
            if (dis[i][j] > dis[m.first][m.second])
            {
                far = dis[i][j];
                m = make_pair(i, j);
            }
        }
    }
    return make_pair(far, m);
}

void solve()
{
    IN(h, w);
    vector<pair<int,int>> v;
    rep(i, h)
    {
        string s; cin >> s;
        rep(j, w)
        {
            d[i][j] = s[j] == '.' ? 1 : 0;
            v.emplace_back(i, j);
        }
    }
    int m = 0;
    for (auto init : v)
    {
        auto p = getDis(init.first, init.second, w, h);
        p = getDis(p.second.first, p.second.second, w, h);
        p = getDis(p.second.first, p.second.second, w, h);
        p = getDis(p.second.first, p.second.second, w, h);
        p = getDis(p.second.first, p.second.second, w, h);
        chmax(m, p.first);
    }
    cout << m << endl;
}

int main()
{
    cin.tie(0); cout.tie(0);
    ios::sync_with_stdio(false);
    cout << setprecision(numeric_limits<double>::max_digits10);

    solve();

    return 0;
}

Measured memory_bytes: 256