#include <bits/stdc++.h>
using namespace std;
const vector<int> dx = {1, 0, -1, 0}, dy = {0, 1, 0, -1};
void set_frame(vector<string>& vstr, string s) {
  vector<string> t(vstr.size() + 2, "");
  for (int i = 0; i < (vstr[0].size() + 2); i++) {
    t[0] += s;
  }
  t[vstr.size() + 1] = t[0];
  for (int i = 0; i < (vstr.size()); i++) {
    t[i + 1] = vstr[i];
    t[i + 1] = s + t[i + 1] + s;
  }
  vstr = t;
}
void print_vvi(vector<vector<int>> vector<vector<int>>) {
  int s = vector<vector<int>>[0].size();
  for (int i = 0; i < (vector<vector<int>>.size()); i++) {
    for (int j = 0; j < (s); j++) {
      cout << vector<vector<int>>[i][j] << " ";
    }
    cout << "\n";
  }
}
int main() {
  int h, w;
  cin >> h >> w;
  vector<string> s(h);
  for (int i = 0; i < (h); i++) cin >> s[i];
  set_frame(s, "#");
  queue<tuple<int, int, int>> que;
  vector<vector<int>> checked(h + 2, vector<int>(w + 2, 0));
  int frag = 0;
  for (int i = (1); i < (h + 2); i++) {
    for (int j = (1); j < (w + 2); j++) {
      if (s[i][j] == '.') {
        que.emplace(i, j, 0);
        frag = 1;
        break;
      }
    }
    if (frag) break;
  }
  int mx, my, max = 0;
  while (!que.empty()) {
    int y, x, c;
    tie(y, x, c) = que.front();
    que.pop();
    if (checked[y][x] == 1) continue;
    checked[y][x] = 1;
    if (max < c) {
      mx = x;
      my = y;
      max = c;
    }
    for (int i = 0; i < (4); i++) {
      if (s[y + dy[i]][x + dx[i]] == '.')
        que.emplace(y + dy[i], x + dx[i], c + 1);
    }
  }
  max = 0;
  que.emplace(my, mx, 0);
  while (!que.empty()) {
    int y, x, c;
    tie(y, x, c) = que.front();
    que.pop();
    if (checked[y][x] == 2) continue;
    checked[y][x] = 2;
    if (max < c) {
      mx = x;
      my = y;
      max = c;
    }
    for (int i = 0; i < (4); i++) {
      if (s[y + dy[i]][x + dx[i]] == '.')
        que.emplace(y + dy[i], x + dx[i], c + 1);
    }
  }
  cout << max << "\n";
  return 0;
}
