#include "bits/stdc++.h"

//region Template
#include "ext/pb_ds/assoc_container.hpp"

using namespace __gnu_pbds;
using namespace std;

typedef long long ll;
typedef long double ld;
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> indexed_set;

const int MOD = 1000000007;
using namespace std;
#define finish(x) cout << x; exit(0);
#define fastIO cin.tie(0); cin.sync_with_stdio(false);

void setIn(string s) { freopen(s.c_str(), "r", stdin); }
void setOut(string s) { freopen(s.c_str(),"w",stdout); }

//const string USCAO_TAG = "mountains";
void usaco(const string& USACO_TAG) { setIn(USACO_TAG + ".in"); setOut(USACO_TAG + ".out"); }
/*
template<typename... Args>
void print(Args... args) {
	#ifdef LOCAL
	((std::cout << args << " "), ...);
	cout << endl;
	#endif
}
 */
//endregion

/* Notes:
 * Farah </3
 */

const int MAXN = 1e5 + 5;
const int INF = 2e9;

char grid[21][21];
int n, m;

int dp[21][21];
int cc[21][21];

bool v[21][21];

vector<pair<int, int>> cells[402];

int cur = 1;
void dfs(int x, int y){
	if(x == -1 || y == -1 || x == n || y == m || grid[x][y] == '#') return;

	if(v[x][y]) return;
	v[x][y] = 1;

	cc[x][y] = cur;

	dfs(x + 1, y);
	dfs(x - 1, y);
	dfs(x, y + 1);
	dfs(x, y - 1);

}
int mx = 0;

void solve(int x, int y, int cnt){

	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			v[i][j] = (grid[i][j] == '#');
		}
	}
	queue<pair<int, int>> q;

	q.push({x, y});

	v[x][y] = 1;

	while(!q.empty()){
		auto p = q.front();
		q.pop();

		if (p.first - 1 >= 0 &&
			!v[p.first - 1][p.second]) {
			q.push({p.first - 1, p.second});
			mx = max(mx , dp[p.first - 1][p.second] = dp[p.first][p.second] + 1);
			v[p.first - 1][p.second] = true;
		}

		if (p.first + 1 < n &&
			!v[p.first + 1][p.second]) {
			q.push({p.first + 1, p.second});
			mx = max(mx ,dp[p.first + 1][p.second] = dp[p.first][p.second] + 1);

			v[p.first + 1][p.second] = true;
		}

		if (p.second - 1 >= 0 &&
			!v[p.first][p.second - 1]) {
			q.push({p.first, p.second - 1});
			mx = max(mx, dp[p.first][p.second - 1] = dp[p.first][p.second] + 1);

			v[p.first][p.second - 1] = true;
		}

		if (p.second + 1 < m &&
			!v[p.first][p.second + 1]) {
			q.push({p.first, p.second + 1});
			mx = max(mx ,dp[p.first][p.second + 1] = dp[p.first][p.second] + 1);

			v[p.first][p.second + 1] = true;
		}
	}
}

int main() {
	//usaco("milkvisits");

#ifdef LOCAL
	setIn("in.txt");
	setOut("out.txt");
#endif

	cin >> n >> m;
	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			cin >> grid[i][j];
		}
	}

	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			if(grid[i][j] != '#' && cc[i][j] == 0){
				dfs(i, j);
				cur++;
			}
		}
	}

	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			cells[cc[i][j]].emplace_back(i, j);
		}
	}

	for(auto x : cells){
		for(auto y : x){
			memset(dp, 0, sizeof dp);
			memset(v, 0, sizeof v);
			solve(y.first, y.second, 0);
		}
	}

	cout << mx;
}