//Himanshu Shukla
#pragma GCC optimize("O2")
#include <bits/stdc++.h>
using namespace std;
#define FASTIO ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0)
//#define file_input
//#define multitest
//#define measure_time
#define ll long long
#define v32 vector<int>
#define v64 vector<ll>
#define s32 set<int>
#define s64 set<ll>
#define graph vector<v32>
#define p32 pair<int, int>
#define p64 pair<ll, ll>
#define sz(v) (ll)(v).size()
#define fi first
#define se second
#define ln '\n'
#define debug(x) cerr << (#x) << ": " << (x) << ln
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
inline ll add(ll a, ll b, ll m) { return (((a % m + b % m) % m + m) % m); }
inline ll mul(ll a, ll b, ll m) { return (((a % m * b % m) % m + m) % m); }
const double EPS = 1e-6;
const ll MOD = 1e9 + 7;
template <typename T, typename U>
ostream &operator<<(ostream &out, const pair<T, U> &p)
{
	out << '[' << p.fi << ", " << p.se << ']';
	return out;
}
template <template <typename, typename...> class ContainerType, typename ValueType, typename... Args>
void print_container(const ContainerType<ValueType, Args...> &c)
{
	cout << "{ ";
	for (const auto &v : c)
		cout << v << ' ';
	cout << '}' << ln;
}

const int N = 21;
const int V = 441;
string s[N];
map<p32, int> vertex;
graph g(V, v32());
int cnt = 1, h, w;

bool in_bound(int i, int j)
{
	return (i >= 0 && i < h && j >= 0 && j < w && s[i][j] == '.');
}

void make_edges(int i, int j)
{
	int x = i - 1, y = j;
	if (in_bound(x, y))
		g[vertex[{i, j}]].push_back(vertex[{x, y}]);
	x = i + 1, y = j;
	if (in_bound(x, y))
		g[vertex[{i, j}]].push_back(vertex[{x, y}]);
	x = i, y = j + 1;
	if (in_bound(x, y))
		g[vertex[{i, j}]].push_back(vertex[{x, y}]);
	x = i, y = j - 1;
	if (in_bound(x, y))
		g[vertex[{i, j}]].push_back(vertex[{x, y}]);
	return;
}

pair<int, p32> f(int src)
{
	pair<int, p32> ans;
	ans.fi = 0;
	ans.se.fi = src;
	ans.se.se = -1;
	v32 dist(cnt + 1, 1e9), visited(cnt + 1, 0);
	priority_queue<p32, vector<p32>, greater<p32>> Q;
	dist[src] = 0;
	Q.push({0, src});
	while (sz(Q))
	{
		auto itr = Q.top();
		Q.pop();
		int ii = itr.se;
		visited[ii] = 1;
		int l = itr.fi;
		for (auto jj : g[ii])
		{
			if (!visited[jj] && l + 1 < dist[jj])
			{
				dist[jj] = l + 1;
				Q.push({dist[jj], jj});
			}
		}
	}
	int mx = -1, v = -1;
	for (int i = 1; i < cnt; i++)
	{
		if (i != src && dist[i] > mx)
		{
			mx = dist[i];
			v = i;
		}
	}
	ans.fi = mx;
	ans.se.se = v;
	return ans;
}

void solve()
{
	cin >> h >> w;
	for (int i = 0; i < h; i++)
		cin >> s[i];
	for (int i = 0; i < h; i++)
		for (int j = 0; j < w; j++)
			if (s[i][j] == '.')
				vertex[{i, j}] = cnt++;
	for (int i = 0; i < h; i++)
		for (int j = 0; j < w; j++)
			if (s[i][j] == '.')
				make_edges(i, j);

	int ans = 0;
	for (int i = 0; i < h; i++)
	{
		for (int j = 0; j < w; j++)
		{
			if (s[i][j] == '.')
			{
				auto itr = f(vertex[{i, j}]);
				ans = max(ans, itr.fi);
			}
		}
	}
	cout << ans << ln;
	return;
}

int main()
{
	FASTIO;
#ifdef file_input
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	clock_t start, stop;
	int t = 1;
#ifdef multitest
	cin >> t;
#endif
#ifdef measure_time
	start = clock();
#endif
	for (int tc = 1; tc < t + 1; tc++)
		solve();
#ifdef measure_time
	stop = clock();
	cerr << "Time :" << fixed << setprecision(5) << double(stop - start) / double(CLOCKS_PER_SEC) << "s" << ln;
#endif
	return 0;
}


Measured memory_bytes: 384