#include <bits/stdc++.h>
using namespace std;
template <class T>
using VV = vector<vector<T>>;
template <typename T>
ostream& operator<<(ostream& os, vector<T>& vec) {
  os << "[";
  for (int i = 0; i < (vec.size()); i++)
    os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
  os << "]";
  return os;
}
template <typename T>
ostream& operator<<(ostream& os, vector<vector<T>>& mat) {
  os << "[";
  for (int i = 0; i < (mat.size()); i++)
    os << mat[i] << (i + 1 == mat.size() ? "" : ",\n ");
  os << "]";
  return os;
}
template <typename T>
istream& operator>>(istream& is, vector<T>& vec) {
  for (T& x : vec) is >> x;
  return is;
}
template <typename V, typename H>
void resize(vector<V>& vec, const H head) {
  vec.resize(head);
}
template <typename V, typename H, typename... T>
void resize(vector<V>& vec, const H& head, const T... tail) {
  vec.resize(head);
  for (auto& v : vec) resize(v, tail...);
}
constexpr double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
string tostring(int i, int digit) {
  auto cur = cout.flags();
  stringstream ss;
  ss << setw(4) << setfill('0') << i;
  string ret = ss.str();
  cout.flags(cur);
  return ret;
}
template <class T>
bool chmax(T& a, const T& b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T>
bool chmin(T& a, const T& b) {
  if (b < a) {
    a = b;
    return 1;
  }
  return 0;
}
bool inbound(int x, int y, int N, int M) {
  return 0 <= x && x < N && 0 <= y && y < M;
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  vector<vector<int>> seen;
  vector<vector<char>> board;
  queue<pair<int, int>> bfs;
  int N, M;
  cin >> N >> M;
  seen.assign(N, vector<int>(M, -1));
  board.assign(N, vector<char>(M, 0));
  pair<int, int> start;
  bool start_set = false;
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < M; ++j) {
      cin >> board[i][j];
      if (board[i][j] == '.' && start_set == false) {
        start_set = true;
        start = make_pair(i, j);
        seen[i][j] = 0;
      }
    }
  }
  vector<vector<int>> dir = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
  bfs.push(start);
  while (!bfs.empty()) {
    pair<int, int> next = bfs.front();
    bfs.pop();
    for (int k = 0; k < 4; ++k) {
      int x = next.first + dir[k][0];
      int y = next.second + dir[k][1];
      if (!inbound(x, y, N, M)) {
        continue;
      }
      if (seen[x][y] >= 0) {
        continue;
      }
      if (board[x][y] == '.') {
        bfs.push(make_pair(x, y));
        seen[x][y] = seen[next.first][next.second] + 1;
      }
    }
  }
  int maxdist = -1;
  vector<pair<int, int>> dest(0);
  for (int i = 0; i < N; ++i) {
    for (int j = 0; j < M; ++j) {
      if (seen[i][j] > maxdist && seen[i][j] > 0) {
        dest.assign(1, make_pair(i, j));
        maxdist = seen[i][j];
      } else if (seen[i][j] == maxdist && seen[i][j] > 0) {
        dest.push_back(make_pair(i, j));
      }
    }
  }
  for (int i = 0; i < (dest.size()); i++) {
    seen.assign(N, vector<int>(M, -1));
    start = dest[i];
    seen[start.first][start.second] = 0;
    bfs.push(start);
    while (!bfs.empty()) {
      pair<int, int> next = bfs.front();
      bfs.pop();
      for (int k = 0; k < 4; ++k) {
        int x = next.first + dir[k][0];
        int y = next.second + dir[k][1];
        if (!inbound(x, y, N, M)) {
          continue;
        }
        if (seen[x][y] >= 0) {
          continue;
        }
        if (board[x][y] == '.') {
          bfs.push(make_pair(x, y));
          seen[x][y] = seen[next.first][next.second] + 1;
        }
      }
    }
    for (int x = 0; x < N; ++x) {
      for (int y = 0; y < M; ++y) {
        if (seen[x][y] > maxdist) {
          maxdist = seen[x][y];
        }
      }
    }
  }
  cout << (maxdist) << "\n";
  return 0;
}
