//#pragma GCC optimize("Ofast")
//#pragma GCC optimize("inline")
//#pragma GCC optimize("-ffast-math")
//#pragma GCC optimize("unroll-loops")
//#pragma GCC optimize("inline-small-functions")
//#pragma GCC optimize("-finline-small-functions")
//#pragma GCC optimize("-fexpensive-optimizations")
//#pragma GCC optimize("-funsafe-loop-optimizations")
//#pragma GCC optimize("inline-functions-called-once")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
#define pb push_back
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
using namespace std;
using ll = long long;
using vi = vector<ll>;
using pi = pair<ll, ll>;
using vpi = vector<pi>;
using oset = tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update>;
const int maxn = 2e5 + 33, mod = 1e9 + 7;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int n, m, vis[33][33], dx[] = {1, -1, 0, 0}, dy[] = {0, 0, 1, -1};
char mat[33][33];
int bfs(int x, int y) {
	memset(vis, 0, sizeof vis);
	vis[x][y] = 1;
	int ans = 0;
	queue<pi> q;
	q.push(pi{x, y});
	while(!q.empty()) {
		tie(x, y) = q.front();
		q.pop();
		ans = vis[x][y];
//		cout << x << " " << y << " " << vis[x][y] << "\n";
		for(int i = 0; i < 4; i++) {
			int tx = x + dx[i], ty = y + dy[i];
//			cout << tx << " " << ty << "\n";
			if(tx<0||ty<0||tx>=n||ty>=m) continue;
//			cout << tx << " " << ty <</<< "\n";
			if(vis[tx][ty]||mat[tx][ty]=='#') continue;
			q.push({tx, ty});
			vis[tx][ty] = vis[x][y]+1;
		}
	}
	return ans-1;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    int ans = 0;
    for(int i = 0; i <n ; i++)
    	for(int j = 0;j < m; j++) {
    		cin >> mat[i][j];
    	}
    for(int i = 0; i <n ; i++)
    	for(int j = 0;j < m; j++)
    		ans = max(ans, bfs(i, j));
//    bfs(n-1, 0);
    cout << ans;
}
