#include <bits/stdc++.h>
bool is_path[20][20] = {false};
bool is_passed[20][20] = {false};
int height, width;
struct pos {
  int x;
  int y;
  int step;
};
bool isPath(pos p) { return is_path[p.y][p.x]; }
bool canGo(pos p) {
  int x = p.x;
  int y = p.y;
  if (x < 0 || width <= x || y < 0 || height <= y) return false;
  if (!isPath(p)) return false;
  return !is_passed[y][x];
}
void setPassed(pos p) { is_passed[p.y][p.x] = true; }
int main() {
  std::queue<pos> path_pos;
  std::cin >> height >> width;
  for (int h = 0; h < height; h++) {
    for (int w = 0; w < width; w++) {
      char s = '#';
      std::cin >> s;
      if (s == '.') {
        is_path[h][w] = true;
        path_pos.push({w, h, 0});
      }
    }
  }
  int ans = -1;
  while (!path_pos.empty()) {
    std::fill(&is_passed[0][0], &is_passed[19][19], false);
    pos start = path_pos.front();
    path_pos.pop();
    std::queue<pos> q;
    q.push(start);
    auto do_push = [&](pos p) {
      if (canGo(p)) {
        setPassed(p);
        q.push(p);
      }
    };
    while (!q.empty()) {
      pos p = q.front();
      q.pop();
      do_push({p.x + 1, p.y, p.step + 1});
      do_push({p.x - 1, p.y, p.step + 1});
      do_push({p.x, p.y + 1, p.step + 1});
      do_push({p.x, p.y - 1, p.step + 1});
      ans = std::max(ans, p.step);
    }
  }
  std::cout << ans << std::endl;
}
