#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int h, w;
vector<string> grid;
vector<vector<bool> > vis;
vector<vector<int> > dis;
struct node {
  int r;
  int c;
  int dis;
  node(int a, int b, int d) : r(a), c(b), dis(d) {}
};
bool isDot(int r, int c) {
  return (r >= 0 && r < h && c >= 0 && c < w && grid[r][c] == '.');
}
bool valid(int r, int c) { return (isDot(r, c) && !vis[r][c]); }
void bfs(int r, int c) {
  queue<node> q;
  q.push(node(r, c, 0));
  vis[r][c] = true;
  dis[r][c] = 0;
  int x[4] = {-1, 1, 0, 0};
  int y[4] = {0, 0, -1, 1};
  while (!q.empty()) {
    node front = q.front();
    q.pop();
    for (int k = 0; k <= (3); ++k) {
      int nr = front.r + x[k];
      int nc = front.c + y[k];
      if (valid(nr, nc)) {
        vis[nr][nc] = true;
        q.push(node(nr, nc, front.dis + 1));
        dis[nr][nc] = dis[front.r][front.c] + 1;
      }
    }
  }
}
int findMinPath(node X, node Y) {
  vis.clear();
  vis.resize(h, vector<bool>(w, false));
  dis.clear();
  dis.resize(h, vector<int>(w, 0));
  queue<node> q;
  q.push(X);
  vis[X.r][X.c] = true;
  int x[4] = {-1, 1, 0, 0};
  int y[4] = {0, 0, -1, 1};
  while (!q.empty()) {
    node front = q.front();
    q.pop();
    dis[front.r][front.c] = front.dis;
    if (front.r == Y.r && front.c == Y.c) return front.dis;
    for (int k = 0; k <= (3); ++k) {
      int nr = front.r + x[k];
      int nc = front.c + y[k];
      if (valid(nr, nc)) {
        vis[nr][nc] = true;
        q.push(node(nr, nc, front.dis + 1));
      }
    }
  }
  return 0;
}
void testcase() {
  cin >> h >> w;
  grid.clear();
  grid.resize(h);
  for (int i = 0; i <= (w - 1); ++i) cin >> grid[i];
  vis.clear();
  vis.resize(h, vector<bool>(w, false));
  dis.clear();
  dis.resize(h, vector<int>(w, 0));
  for (int i = 0; i <= (h - 1); ++i) {
    for (int j = 0; j <= (w - 1); ++j) {
      if (grid[i][j] == '.' && !vis[i][j]) {
        bfs(i, j);
      }
    }
  }
  vector<pair<int, int> > end;
  int maxi = 0;
  for (int i = 0; i <= (h - 1); ++i) {
    for (int j = 0; j <= (w - 1); ++j) {
      if (grid[i][j] == '#') continue;
      if (dis[i][j] > maxi) {
        end.clear();
        end.push_back({i, j});
        maxi = dis[i][j];
      } else if (dis[i][j] == maxi) {
        end.push_back({i, j});
      }
    }
  }
  int res = 0;
  for (pair<int, int> p : end) {
    vis.clear();
    vis.resize(h, vector<bool>(w, false));
    dis.clear();
    dis.resize(h, vector<int>(w, 0));
    bfs(p.first, p.second);
    for (int i = 0; i <= (h - 1); ++i) {
      for (int j = 0; j <= (w - 1); ++j) {
        if (grid[i][j] == '.') res = max(res, dis[i][j]);
      }
    }
  }
  cout << res << endl;
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  int t = 1;
  if (0) cin >> t;
  while (t--) {
    testcase();
  }
  return 0;
}
