#include <bits/stdc++.h>
using namespace std;
int dx8[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy8[8] = {0, 1, 0, -1, 1, 1, -1, -1};
int dx4[4] = {1, 0, -1, 0};
int dy4[4] = {0, 1, 0, -1};
template <class T>
inline bool chmax(T& a, T b) {
  if (a < b) {
    a = b;
    return 1;
  }
  return 0;
}
template <class T>
inline bool chmin(T& a, T b) {
  if (a > b) {
    a = b;
    return 1;
  }
  return 0;
}
template <typename A, size_t N, typename T>
void Fill(A (&array)[N], const T& val) {
  fill((T*)array, (T*)(array + N), val);
}
struct io {
  io() {
    ios::sync_with_stdio(false);
    cin.tie(0);
  }
};
const int INF = INT_MAX;
const long long int LLINF = 1LL << 60;
const long long int MOD = 1000000007;
const double EPS = 1e-9;
int bfs(vector<string>& S, int i, int j) {
  int H = S.size(), W = S[0].size();
  vector<vector<int> > dist(H, vector<int>(W, -1));
  queue<pair<int, int> > que;
  int distMax = 0;
  dist[i][j] = 0;
  que.push({i, j});
  while (!que.empty()) {
    pair<int, int> v = que.front();
    que.pop();
    int curX = v.first, curY = v.second;
    distMax = max(distMax, dist[curX][curY]);
    for (auto dx : dx4) {
      for (auto dy : dy4) {
        int nX = curX + dx, nY = curY + dy;
        if (nX < 0 || nX >= W || nY < 0 || nY >= H) continue;
        if (S[nX][nY] == '#') continue;
        if (dist[nX][nY] != -1) {
          dist[nX][nY] = dist[curX][curY] + 1;
        }
        que.push({nX, nY});
      }
    }
  }
  return distMax;
}
int main() {
  int H, W;
  cin >> H >> W;
  vector<string> S(H);
  for (int i = 0; i < (H); ++i) {
    cin >> S[i];
  }
  int countMax = 0;
  for (int i = 0; i < (H); ++i) {
    for (int j = 0; j < (W); ++j) {
      if (S[i][j] == '#') continue;
      countMax = max(countMax, bfs(S, i, j));
    }
  }
  cout << (countMax) << endl;
}
