#include							<list>
#include                            <iostream>
#include                            <stdio.h>
#include                            <math.h>
#include                            <string.h>
#include                            <time.h>
#include                            <stdlib.h>
#include                            <string>
#include                            <bitset>
#include                            <vector>
#include                            <set>
#include                            <map>
#include                            <queue>
#include                            <algorithm>
#include                            <sstream>
#include                            <stack>
#include                            <iomanip>
#include                            <numeric>
#include							<unordered_map>
using namespace                     std;
#define int                         int64_t
#define baba_shiv                   ios_base::sync_with_stdio(false);cin.tie(NULL);
#define mpii                        map<int,int>
#define pb                          push_back
#define mkp                         make_pair
#define all(x)                      x.begin(),x.end()
#define allr(x)                     x.rbegin(),x.rend()
#define ub(v,x)                     upper_bound(all(v),x)
#define lb(v,x)                     lower_bound(all(v),x)
#define bs(v,x)                     binary_search(all(v),x)
#define gcd(a,b)                    __gcd(a,b)
#define lcm(a,b)                    (a*b)/__gcd(a,b)
#define vi                          vector<int>
#define pii                         pair<int,int>
#define vpii                        vector<pii>
#define vs                          vector<string>
#define ff                          first
#define ss                          second
#define MOD                         1000000007

/***********************************************************************************************************************/
template < typename F, typename S >
ostream& operator << ( ostream& os, const pair< F, S > & p ) {
	return os << "(" << p.first << ", " << p.second << ")";
}

template < typename T >
ostream &operator << ( ostream & os, const vector< T > &v ) {
	os << "{";
	typename vector< T > :: const_iterator it;
	for ( it = v.begin(); it != v.end(); it++ ) {
		if ( it != v.begin() ) os << ", ";
		os << *it;
	}
	return os << "}";
}

template < typename T >
ostream &operator << ( ostream & os, const set< T > &v ) {
	os << "[";
	typename set< T > :: const_iterator it;
	for ( it = v.begin(); it != v.end(); it++ ) {
		if ( it != v.begin() ) os << ", ";
		os << *it;
	}
	return os << "]";
}

template < typename F, typename S >
ostream &operator << ( ostream & os, const map< F, S > &v ) {
	os << "[";
	typename map< F , S >::const_iterator it;
	for ( it = v.begin(); it != v.end(); it++ ) {
		if ( it != v.begin() ) os << ", ";
		os << it -> first << " = " << it -> second ;
	}
	return os << "]";
}

#define deb(x) cerr<< #x << " = " << x << endl;

/***********************************************************************************************************************/
bool BFS(vector<int> adj[], int src, int dest, int v,
         int pred[], int dist[])
{
	// a queue to maintain queue of vertices whose
	// adjacency list is to be scanned as per normal
	// DFS algorithm
	list<int> queue;

	// boolean array visited[] which stores the
	// information whether ith vertex is reached
	// at least once in the Breadth first search
	bool visited[v];

	// initially all vertices are unvisited
	// so v[i] for all i is false
	// and as no path is yet constructed
	// dist[i] for all i set to infinity
	for (int i = 0; i < v; i++) {
		visited[i] = false;
		dist[i] = 1e18;
		pred[i] = -1;
	}

	// now source is first to be visited and
	// distance from source to itself should be 0
	visited[src] = true;
	dist[src] = 0;
	queue.push_back(src);

	// standard BFS algorithm
	while (!queue.empty()) {
		int u = queue.front();
		queue.pop_front();
		for (int i = 0; i < adj[u].size(); i++) {
			if (visited[adj[u][i]] == false) {
				visited[adj[u][i]] = true;
				dist[adj[u][i]] = dist[u] + 1;
				pred[adj[u][i]] = u;
				queue.push_back(adj[u][i]);

				// We stop BFS when we find
				// destination.
				if (adj[u][i] == dest)
					return true;
			}
		}
	}

	return false;
}

// utility function to print the shortest distance
// between source vertex and destination vertex
int printShortestDistance(vector<int> adj[], int s,
                          int dest, int v)
{
	// predecessor[i] array stores predecessor of
	// i and distance array stores distance of i
	// from s
	int pred[v], dist[v];

	if (BFS(adj, s, dest, v, pred, dist) == false)
	{
		//cout << "Given source and destination"
		//<< " are not connected";
		return -1;
	}
	else
		return dist[dest];



	/*cout << "Shortest path length is : "
	     << dist[dest];

	// printing path from source to destination
	/*cout << "\nPath is::\n";
	for (int i = path.size() - 1; i >= 0; i--)
		cout << path[i] << " ";*/
}

signed main()
{
	vector<int> adj[1007];
	baba_shiv;
	int n, m;
	cin >> n >> m;
	char a[n][m];
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			cin >> a[i][j];
		}
	}
	int dx[] = {0, -1, 1, 0};
	int dy[] = {1, 0, 0, -1};
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			if (a[i][j] == '.')
				for (int k = 0; k < 4; k++)
				{
					int X = i + dx[k];
					int Y = j + dy[k];
					if (X < n && X >= 0 && Y < m && Y >= 0)
					{
						if (a[X][Y] == '.')
							adj[i * m + j].pb(X * m + Y);
					}

				}
		}
	}
	//for(int i=0;i<=(n-1)*(m-1);i++)
	/*int ans = 0;
	for (int i = 0; i <= n * m - 1; i++)
	{
		vector<int> dist(12300, 1e18);
		dist[i] = 0;
		queue<int> que;
		que.push(i);
		int u;
		while (!que.empty())
		{
			u = que.front();
			for (int i = 0; i < adj[u].size(); i++) {
				if (dist[adj[u][i]] > dist[u] + 1) {
					dist[adj[u][i]] = dist[u] + 1;
					que.push(adj[u][i]);
				}
			}
			que.pop();
		}
		int temp = 0;
		for (int i = 0; i < n * m - 1; i++)
		{
			if (dist[i] != 1e18)
			{
				temp = max(temp, dist[i]);
			}

		}
		ans = max(ans, temp);
	}

	cout << ans << endl;*/
	int ans = 0;
	for (int i = 0; i <= n * m - 1; i++)
	{
		for (int j = 0; j <= n * m - 1; j++)
		{
			if (i != j && a[i / m][i % m] == '.' && a[j / m][j % m] == '.')
			{
				int x = printShortestDistance(adj, i, j, n * m );
				if (x == -1)
					continue;
				ans = max(ans, x);

			}

		}
	}
	cout << ans << endl;
	//printShortestDistance(adj, source, dest, v);*/


}




Measured memory_bytes: 256