#include <algorithm>
#include <cmath>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <numeric>
#include <set>
#include <stack>
#include <string>
#include <unordered_set>
#include <vector>

using namespace std;
using LLONG = long long;
const LLONG MOD = 1000000007;

class Graph
{
private:
    int m_nodeNum;
    vector<vector<int>> m_adList;

    vector<vector<int>> m_connectedComponents;
    vector<int> m_connectedCompunentIndex;

public:
    Graph(const int N) : m_nodeNum(N)
    {
        m_adList = vector<vector<int>>(N);
        m_connectedCompunentIndex = vector<int>(N, -1);
    }

    void Connect(const int v, const int u)
    {
        m_adList[v].push_back(u);
        m_adList[u].push_back(v);
    }

    void ComputeConnectedComponents()
    {
        vector<bool> hasNotVisited(m_nodeNum, true);
        stack<int> stack;
        int ccIndex = 0;
        vector<int> cc;
        for (int v = 0; v < m_nodeNum; ++v)
        {
            if (hasNotVisited[v])
            {
                stack.push(v);
                cc.clear();
                while (!stack.empty())
                {
                    int u = stack.top();
                    stack.pop();
                    hasNotVisited[u] = false;
                    m_connectedCompunentIndex[u] = ccIndex;
                    cc.push_back(u);
                    for (const int n : m_adList[u])
                    {
                        if (hasNotVisited[n])
                        {
                            hasNotVisited[n] = false;
                            stack.push(n);
                        }
                    }
                }
                m_connectedComponents.push_back(cc);
                ++ccIndex;
            }
        }
    }

    const int GetConnectedComponentSize(const int v)
    {
        int index = m_connectedCompunentIndex[v];
        return static_cast<int>(m_connectedComponents[index].size());
    }

    const int GetConnectedComponentIndex(const int v)
    {
        return m_connectedCompunentIndex[v];
    }

    const int Distance(const int u, const int v)
    {
        vector<int> distances(m_nodeNum, m_nodeNum + 1);
        distances[u] = 0;
        deque<int> Q{ u };
        while (!Q.empty())
        {
            const int key = Q.back(); Q.pop_back();
            for (const int n : m_adList[key])
            {
                int tmpDist = distances[key] + 1;
                if (tmpDist < distances[n])
                {
                    distances[n] = tmpDist;
                    Q.push_back(n);
                }
            }
        }
        return distances[v];
    }

};

int main()
{
    int H, W; cin >> H >> W;
    vector<vector<bool>> S(H, vector<bool>(W));
    for (auto &row : S) for (auto &Sij : row)
    {
        char ch;
        cin >> ch;
        Sij = (ch == '.');
    }
    Graph graph(H * W);
    vector<int> roads;
    for (int r = 0; r < H; ++r)
    {
        for (int c = 0; c < W; ++c)
        {
            int ID = r * W + c;
            if (S[r][c])
            {
                roads.push_back(ID);
                if (c < W - 1 && S[r][c + 1])
                {
                    graph.Connect(ID, r * W + c + 1);
                }
                if (r < H - 1 && S[r + 1][c])
                {
                    graph.Connect(ID, (r + 1) * W + c);
                }
            }
        }
    }
    // 全ての道ー道ペアについて最短移動距離を計算
    int ans = 0;
    int num = roads.size();
    for (int i = 0; i < num; ++i)
    {
        for (int j = i + 1; j < num; ++j)
        {
            int tmp = graph.Distance(roads[i], roads[j]);
            ans = max(ans, tmp);
        }
    }
    cout << ans << endl;
}
