#include <bits/stdc++.h>
using namespace std;
template <class T>
inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <class T>
inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
class Elem {
 public:
  int vertex;
  long long distance;
  bool operator<(const Elem &other) const { return distance < other.distance; }
  bool operator>(const Elem &other) const { return distance > other.distance; }
};
void dijkstra(const int n, const int start, const vector<vector<Elem>> &edges,
              vector<long long> &d_list,
              priority_queue<Elem, vector<Elem>, greater<Elem>> &queue) {
  for (int i = 0; i < n; i++) {
    if (i == start) {
      d_list[i] = 0;
    } else {
      d_list[i] = 1000000001;
    }
    Elem elem;
    elem.vertex = i;
    elem.distance = d_list[i];
    queue.push(elem);
  }
  while (queue.size() > 0) {
    Elem elem = queue.top();
    queue.pop();
    for (int i = 0; i < (int)edges[elem.vertex].size(); i++) {
      Elem next = edges[elem.vertex][i];
      long long alt = d_list[elem.vertex] + next.distance;
      if (d_list[next.vertex] > alt) {
        d_list[next.vertex] = alt;
        Elem e;
        e.vertex = next.vertex;
        e.distance = d_list[next.vertex];
        queue.push(e);
      }
    }
  }
}
vector<vector<Elem>> edges;
int main(void) {
  int H, W;
  cin >> H >> W;
  vector<vector<char>> maze(H, vector<char>(W, '.'));
  for (int i = 0; i < H; i++) {
    string S;
    cin >> S;
    for (int j = 0; j < W; j++) {
      if (S[j] == '#') {
        maze[i][j] = '#';
      }
    }
  }
  const int N = H * W;
  edges.resize(N, vector<Elem>());
  for (int i = 0; i < H; i++) {
    for (int j = 0; j < W; j++) {
      if (i >= 1 && maze[i - 1][j] != '#') {
        edges[((i)*W + j)].push_back({((i - 1) * W + j), 1});
      }
      if (j < W - 1 && maze[i][j + 1] != '#') {
        edges[((i)*W + j)].push_back({((i)*W + j + 1), 1});
      }
      if (i < H - 1 && maze[i + 1][j] != '#') {
        edges[((i)*W + j)].push_back({((i + 1) * W + j), 1});
      }
      if (j >= 1 && maze[i][j - 1] != '#') {
        edges[((i)*W + j)].push_back({((i)*W + j - 1), 1});
      }
    }
  }
  priority_queue<Elem, vector<Elem>, greater<Elem>> q;
  long long max = 0;
  for (int i = 0; i < N; i++) {
    vector<long long> d_list(N, 1000000001);
    d_list[i] = 0;
    dijkstra(N, i, edges, d_list, q);
    for (int i = 0; i < N; i++) {
      if (d_list[i] != 1000000001) {
        chmax(max, d_list[i]);
      }
    }
  }
  cout << max << endl;
  return 0;
}
