#include <bits/stdc++.h>
using namespace std;
using int64 = long long;
constexpr int DEBUG = 0;
struct Edge {
  const int from, to;
  Edge(int from, int to) : from(from), to(to) {}
};
vector<int> BFS(const vector<vector<Edge>>& graph, int s) {
  int n = graph.size();
  deque<int> queue;
  queue.push_back(s);
  vector<int> ds(n, INT_MAX);
  ds[s] = 0;
  while (!queue.empty()) {
    int v = queue.front();
    queue.pop_front();
    for (const auto& e : graph[v]) {
      if (ds[e.to] < INT_MAX) continue;
      ds[e.to] = ds[v] + 1;
      queue.push_back(e.to);
    }
  }
  return ds;
}
template <class T>
inline bool UpdateMin(T& a, T b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T>
inline bool UpdateMax(T& a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  int h, w;
  cin >> h >> w;
  vector<string> board(h);
  for (int r = 0; r < h; r++) {
    cin >> board[r];
  }
  auto encode_v_fn = [&](int r, int c) { return r * h + c; };
  vector<vector<Edge>> graph(h * w);
  for (int r = 0; r < h; r++) {
    for (int c = 0; c < w; c++) {
      if (board[r][c] == '#') continue;
      int v = encode_v_fn(r, c);
      if (c + 1 < w && board[r][c + 1] == '.')
        graph[v].emplace_back(v, encode_v_fn(r, c + 1));
      if (c - 1 >= 0 && board[r][c - 1] == '.')
        graph[v].emplace_back(v, encode_v_fn(r, c - 1));
      if (r + 1 < h && board[r + 1][c] == '.')
        graph[v].emplace_back(v, encode_v_fn(r + 1, c));
      if (r - 1 >= 0 && board[r - 1][c] == '.')
        graph[v].emplace_back(v, encode_v_fn(r - 1, c));
    }
  }
  int ans = 0;
  for (int s = 0; s < h * w; s++) {
    auto ds = BFS(graph, s);
    for (int d : ds) {
      if (d == INT_MAX) continue;
      UpdateMax(ans, d);
    }
  }
  cout << ans << endl;
}
