#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int BLOCK = 100000;
struct Path {
  int x, y, cost;
  Path(int _x, int _y, int _cost) {
    x = _x;
    y = _y;
    cost = _cost;
  }
};
void solve() {
  int h, w;
  cin >> h >> w;
  vector<vector<int> > initial_maze(h, vector<int>(w, -1));
  string s;
  for (int i = 0; i < h; ++i) {
    cin >> s;
    for (int j = 0; j < w; ++j) {
      initial_maze[i][j] = ((s[j] == '.') ? -1 : BLOCK);
    }
  }
  vector<vector<int> > maxPathCost(initial_maze);
  for (int i = 0; i < w; ++i) {
    for (int j = 0; j < h; ++j) {
      if (initial_maze[j][i] == BLOCK) {
        continue;
      }
      vector<vector<int> > maze(initial_maze);
      queue<Path> que;
      Path p(i, j, 0);
      maze[i][j] = 0;
      que.push(p);
      int dx[4] = {0, 1, 0, -1};
      int dy[4] = {1, 0, -1, 0};
      while (!que.empty()) {
        Path now = que.front();
        que.pop();
        for (int k = 0; k < 4; ++k) {
          int next_x = now.x + dx[k];
          int next_y = now.y + dy[k];
          if (next_x < 0 || w <= next_x || next_y < 0 || h <= next_y) {
            continue;
          }
          if (maze[next_y][next_x] == -1) {
            Path next(next_x, next_y, now.cost + 1);
            maze[next.y][next.x] = next.cost;
            que.push(next);
          }
        }
      }
      for (int y = 0; y < h; ++y) {
        for (int x = 0; x < w; ++x) {
          maxPathCost[y][x] = max(maze[y][x], maxPathCost[y][x]);
        }
      }
    }
  }
  int ans = 0;
  for (int y = 0; y < h; ++y) {
    for (int x = 0; x < w; ++x) {
      if (maxPathCost[y][x] == BLOCK) {
        continue;
      }
      ans = max(ans, maxPathCost[y][x]);
    }
  }
  cout << ans;
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  ;
  solve();
  return 0;
}
