#include <bits/stdc++.h>
using namespace std;
#define FAST_IO                       \
	ios_base::sync_with_stdio(false); \
	cin.tie(NULL);                    \
	cout.tie(NULL);
#define pb push_back
#define ll long long
/*

to make a change to a sort do this : 

sort (a.begin(), a.end(), [&](int x , int y){
	return x<y;
})

*/
struct Q
{
	ll x, y;
	ll operator*(Q b)
	{
		// cout << x << " "<< y<<endl;
		// cout << b.y << " "<< b.x << endl;
		return (x * b.y - y * b.x);
	}
	void read()
	{
		cin >> x >> y;
	}
	Q operator-(Q b)
	{
		return {x - b.x, y - b.y};
	}
	double operator%(Q b)
	{
		return sqrt(pow(x - b.x, 2) + pow(y - b.y, 2));
	}
};
bool inters(Q a, Q b, Q c, Q d)
{
	for (int i = 0; i < 2; i++)
	{
		Q zg = (b - a), zg1 = (b - c), zg2 = (b - d);
		ll v1 = zg * zg1, v2 = zg * zg2;
		if (v1 * v2 > 0)
		{
			return false;
		}
		else if (v1 == 0 && v2 == 0)
		{
			if (max(a.x, b.x) < min(c.x, d.x) || max(a.y, b.y) < min(c.y, d.y))
			{
				return false;
			}
		}
		swap(a, c);
		swap(b, d);
	}
	return true;
}
bool inter(Q a, Q b, Q c, Q d)
{
	if ((b - a) * (c - a) == 0) // check if b a (c) is coliner
	{
		if (((c.x <= b.x && c.x >= a.x) || (c.x <= a.x && c.x >= b.x)) && ((c.y <= b.y && c.y >= a.y) || (c.y <= a.y && c.y >= b.y)))
			return true;
		else
			return false;
	}
	else if ((b - a) * (d - a) == 0) // check if b a (d) is coliner
	{
		if (((d.x <= b.x && d.x >= a.x) || (d.x <= a.x && d.x >= b.x)) && ((d.y <= b.y && d.y >= a.y) || (d.y <= a.y && d.y >= b.y)))
			return true;
		else
			return false;
	}
	else if ((d - c) * (a - c) == 0) // check if d c (a) is coliner
	{
		if (((a.x <= d.x && a.x >= c.x) || (a.x <= c.x && a.x >= d.x)) && ((a.y <= d.y && a.y >= c.y) || (a.y <= c.y && a.y >= d.y)))
			return true;
		else
			return false;
	}
	else if ((d - c) * (b - c) == 0) // check if d c (b) is coliner
	{
		if (((b.x <= d.x && b.x >= c.x) || (b.x <= c.x && b.x >= d.x)) && ((b.y <= d.y && b.y >= c.y) || (b.y <= c.y && b.y >= d.y)))
			return true;
		else
			return false;
	}
	else
	{

		bool a1 = true, a2 = true, a3 = true, a4 = true;
		if ((a - c) * (d - c) < 0)
		{
			a1 = false;
		}
		if ((b - c) * (d - c) < 0)
		{
			a2 = false;
		}
		if ((c - a) * (b - a) < 0)
		{
			a3 = false;
		}
		if ((d - a) * (b - a) < 0)
		{
			a4 = false;
		}
		if (a1 != a2 && a3 != a4)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}
int maxdist;
vector<vector<bool>> vis;
vector<vector<char>> v;
void bfs(int a, int b)
{
	queue<pair<pair<int, int>, int>> q;
	q.push({{a, b}, 0});
	vis[a][b] = true;
	while (!q.empty())
	{
		int i = q.front().first.first, j = q.front().first.second;
		if (v[i][j + 1] == '.' && !vis[i][j + 1])
		{
			vis[i][j + 1] = true;
			q.push({{i, j + 1}, q.front().second + 1});
		}
		if (v[i][j - 1] == '.' && !vis[i][j - 1])
		{
			vis[i][j - 1] = true;
			q.push({{i, j - 1}, q.front().second + 1});
		}
		if (v[i + 1][j] == '.' && !vis[i + 1][j])
		{
			vis[i + 1][j] = true;
			q.push({{i + 1, j}, q.front().second + 1});
		}
		if (v[i - 1][j] == '.' && !vis[i - 1][j])
		{
			vis[i - 1][j] = true;
			q.push({{i - 1, j}, q.front().second + 1});
		}
		maxdist = max(maxdist, q.front().second);
		q.pop();
	}
}
int main()
{
	FAST_IO
	int n, m;
	//	maxdist =0;
	cin >> n >> m;
	v.assign(n + 2, vector<char>(m + 2, '#'));
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			cin >> v[i + 1][j + 1];
		}
	}
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			if (v[i + 1][j + 1] == '.')
			{
				vis.assign(n + 2, vector<bool>(m + 2, false));
				bfs(i + 1, j + 1);
			}
		}
	}
	cout << maxdist << endl;
}


Measured memory_bytes: 256