#include <bits/stdc++.h>
using namespace std;
const bool DEBAG = false;
vector<vector<char> > data;
int dx[4] = {-1, 1, 0, 0};
int dy[4] = {0, 0, -1, 1};
long long H, W;
struct Grid {
  int h;
  int w;
  int depth;
  Grid(int h, int w, int depth) {
    this->h = h;
    this->w = w;
    this->depth = depth;
  }
};
int search(int sh, int sw) {
  queue<Grid> que;
  Grid g(sh, sw, 0);
  que.push(g);
  const int INF = 1000000;
  vector<vector<int> > used(H);
  for (int i = 0; i < H; i++) used[i].resize(W);
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      used[i][j] = INF;
    }
  }
  while (!que.empty()) {
    Grid g = que.front();
    que.pop();
    if (used[g.h][g.w] != INF) continue;
    used[g.h][g.w] = g.depth;
    for (int i = 0; i < 4; i++) {
      int nx = g.h + dx[i];
      int ny = g.w + dy[i];
      int depth = g.depth + 1;
      if (nx < 0 || nx >= H) continue;
      if (ny < 0 || ny >= W) continue;
      if (data[nx][ny] == '#') continue;
      if (used[nx][ny] != INF) continue;
      que.push(Grid(nx, ny, depth));
    }
  }
  int ret = 0;
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      if (data[i][j] == '.') ret = max(ret, used[i][j]);
    }
  }
  return ret;
}
int main() {
  cin >> H >> W;
  data.resize(H);
  for (int i = 0; i < H; i++) data[i].resize(W);
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      cin >> data[i][j];
    }
  }
  int ans = 0;
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      ans = max(ans, search(i, j));
    }
  }
  cout << ans << endl;
}
