#include <bits/stdc++.h>
#pragma GCC target("avx")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
using namespace std;
char s[21][21];
int d[21][21];
bool visited[21][21];
int d4[5] = {0, 1, 0, -1, 0};
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int h, w, ans = 0, ni, nj, i, j, a, b;
  cin >> h >> w;
  for (int i = 0; i < h; i++)
    for (int j = 0; j < w; j++) cin >> s[i][j];
  for (i = 0; i < h; i++)
    for (int j = 0; j < w; j++) {
      if (s[i][j] == '#') continue;
      for (int a = 0; a < h; a++)
        for (int b = 0; b < w; b++) d[a][b] = 0;
      for (int a = 0; a < h; a++)
        for (int b = 0; b < w; b++) visited[a][b] = false;
      queue<tuple<int, int, int>> q;
      q.push(make_tuple(i, j, 0));
      visited[i][j] = true;
      while (!q.empty()) {
        tuple<int, int, int> p = q.front();
        q.pop();
        visited[get<0>(p)][get<1>(p)] = true;
        d[get<0>(p)][get<1>(p)] = get<2>(p);
        for (int k = 0; k < 4; k++) {
          ni = get<0>(p) + d4[k], nj = get<1>(p) + d4[k + 1];
          if (visited[ni][nj] == false && s[ni][nj] == '.' && 0 <= ni &&
              ni < h && 0 <= nj && nj < w)
            q.push(make_tuple(ni, nj, get<2>(p) + 1));
        }
      }
      for (int a = 0; a < h; a++)
        for (int b = 0; b < w; b++) ans = max(ans, d[a][b]);
    }
  cout << ans << endl;
  return 0;
}
