#include <bits/stdc++.h>
int H, W;
char map[20][20];
int dist_value;
int dist[20][20];
void initdist() {
  dist_value = 0;
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      dist[i][j] = -1;
    }
  }
  return;
}
struct coord {
  int x;
  int y;
};
int drow[4] = {1, -1, 0, 0};
int dcolumn[4] = {0, 0, 1, -1};
std::queue<coord> queue_next;
coord last;
void bfs(int start_i, int start_j) {
  queue_next.push((coord){start_i, start_j});
  dist_value = 0;
  while (queue_next.size()) {
    std::queue<coord> queue(queue_next);
    std::queue<coord> empty;
    std::swap(queue_next, empty);
    while (queue.size()) {
      int thisi = queue.front().x;
      int thisj = queue.front().y;
      last.x = thisi;
      last.y = thisj;
      queue.pop();
      dist[thisi][thisj] = dist_value;
      for (int k = 0; k < 4; k++) {
        if (thisi + drow[k] >= 0 && thisi + drow[k] < H &&
            thisj + dcolumn[k] >= 0 && thisj + dcolumn[k] < W) {
          if (dist[thisi + drow[k]][thisj + dcolumn[k]] == -1 &&
              map[thisi + drow[k]][thisj + dcolumn[k]] != '#') {
            queue_next.push((coord){thisi + drow[k], thisj + dcolumn[k]});
          }
        }
      }
    }
    dist_value++;
  }
  return;
}
int maxdist() {
  int ans = 0;
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      if (map[i][j] == '#') {
        continue;
      }
      initdist();
      bfs(i, j);
      ans = std::max(ans, dist_value - 1);
    }
  }
  return ans;
}
int main() {
  scanf("%d", &H);
  scanf("%d", &W);
  std::string S;
  for (int i = 0; i < H; i++) {
    std::cin >> S;
    for (int j = 0; j < W; j++) {
      map[i][j] = S[j];
    }
  }
  int ans = maxdist();
  printf("%d\n", ans);
  return 0;
}
