#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
template <typename T>
inline bool chmax(T& a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <typename T>
inline bool chmin(T& a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
vector<vector<int>> grid_bfs(const vector<string>& S, int sh, int sw) {
  const int delta_h[4] = {0, 1, 0, -1}, delta_w[4] = {1, 0, -1, 0};
  const char wall = '#';
  int H = S.size(), W = S.at(0).size();
  vector<vector<int>> dist(H, vector<int>(W, -1));
  dist[sh][sw] = 0;
  vector<vector<bool>> seen(H, vector<bool>(W, false));
  queue<pair<int, int>> que;
  que.emplace(sh, sw);
  while (!que.empty()) {
    int h, w;
    tie(h, w) = que.front();
    que.pop();
    if (seen[h][w]) {
      continue;
    }
    int d = dist[h][w] + 1;
    seen[h][w] = true;
    for (int i = 0; i < 4; i++) {
      int nh = h + delta_h[i], nw = w + delta_w[i];
      if (nh < 0 || H <= nh || nw < 0 || W <= nw) continue;
      if (S[nh][nw] == wall || seen[nh][nw]) continue;
      dist[nh][nw] = d;
      que.emplace(nh, nw);
    }
  }
  return dist;
}
int main() {
  int H, W;
  cin >> H >> W;
  vector<string> S(H);
  for (int i = 0; i < H; i++) cin >> S[i];
  auto longest_path = [&](vector<vector<int>> G) {
    int longest = 0;
    for (int i = 0; i < H; i++) {
      for (int j = 0; j < W; j++) {
        if (G[i][j] > longest) longest = G[i][j];
      }
    }
    return longest;
  };
  int ans = 0;
  for (int i = 0; i < H; i++)
    for (int j = 0; j < H; j++) {
      if (S[i][j] == '#') continue;
      int res = longest_path(grid_bfs(S, i, j));
      chmax(ans, res);
    }
  cout << ans << endl;
  return 0;
}
