#include <bits/stdc++.h>
using namespace std;
constexpr int64_t MOD = 1000000007;
struct point {
  int r;
  int c;
  int d;
  point(int r, int c, int d) : r(r), c(c), d(d) {}
};
int32_t dfs(vector<vector<char>>& maize, point s, int32_t gr, int32_t gc,
            int32_t H, int32_t W) {
  queue<point> q;
  vector<vector<bool>> visited(H, vector<bool>(W, false));
  q.push(s);
  int32_t res = 0;
  while (!q.empty()) {
    point cur = q.front();
    q.pop();
    if (cur.r == gr && cur.c == gc) {
      res = cur.d;
      break;
    }
    if (visited[cur.r][cur.c] == true) {
      continue;
    } else {
      visited[cur.r][cur.c] = true;
    }
    if (cur.r > 0 && maize[cur.r - 1][cur.c] != '#' &&
        visited[cur.r - 1][cur.c] == false) {
      q.push(point(cur.r - 1, cur.c, cur.d + 1));
    }
    if (cur.r < H - 1 && maize[cur.r + 1][cur.c] != '#' &&
        visited[cur.r + 1][cur.c] == false) {
      q.push(point(cur.r + 1, cur.c, cur.d + 1));
    }
    if (cur.c > 0 && maize[cur.r][cur.c - 1] != '#' &&
        visited[cur.r][cur.c - 1] == false) {
      q.push(point(cur.r, cur.c - 1, cur.d + 1));
    }
    if (cur.c < W - 1 && maize[cur.r][cur.c + 1] != '#' &&
        visited[cur.r][cur.c + 1] == false) {
      q.push(point(cur.r, cur.c + 1, cur.d + 1));
    }
  }
  return res;
}
int main() {
  std::cin.tie(0);
  std::ios::sync_with_stdio(false);
  int32_t H, W;
  cin >> H >> W;
  vector<vector<char>> maize(H, vector<char>(W));
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      cin >> maize[i][j];
    }
  }
  int32_t max_step = 0;
  for (int sr = 0; sr < H; sr++) {
    for (int sc = 0; sc < W; sc++) {
      point start(sr, sc, 0);
      for (int gr = 0; gr < H; gr++) {
        for (int gc = 0; gc < W; gc++) {
          int32_t step = dfs(maize, start, gr, gc, H, W);
          max_step = max(max_step, step);
        }
      }
    }
  }
  cout << max_step << endl;
  return 0;
}
