#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
#define rep(i,s,e) for(i64 (i) = (s);(i) < (e);(i)++)
#define rev(i,s,e) for(i64 (i) = (s);(i) --> (e);)
#define all(x) x.begin(),x.end()

template<class T>
static inline std::vector<T> ndvec(size_t&& n, T val) noexcept {
  return std::vector<T>(n, std::forward<T>(val));
}

template<class... Tail>
static inline auto ndvec(size_t&& n, Tail&&... tail) noexcept {
  return std::vector<decltype(ndvec(std::forward<Tail>(tail)...))>(n, ndvec(std::forward<Tail>(tail)...));
}

vector<vector<i64>> f;
i64 H, W;
i64 d[] = {1, 0, -1, 0};

i64 bfs(i64 s, i64 t) {
  using P = pair<i64, i64>;
  queue<P> que;
  que.push({ s, t });
  vector<vector<i64>> dist(H, vector<i64>(W, 1e18));
  dist[s][t] = 0;
  i64 MAX = 0;
  while(!que.empty()) {
    i64 x = que.front().first;
    i64 y = que.front().second;
    que.pop();
    rep(k,0,4) {
      i64 i = x + d[k];
      i64 j = y + d[k ^ 1];
      if(!(0 <= i && i < H && 0 <= j && j < W)) continue;
      if(f[i][j]) continue;
      if(dist[i][j] > dist[x][y] + 1) {
        dist[i][j] = dist[x][y] + 1;
        que.push({ i, j });
        MAX = std::max(dist[i][j], MAX);
      }
    }
  }
  return MAX;
}

int main() {
  cin >> H >> W;
  f.resize(H, vector<i64>(W));
  rep(i,0,H) {
    string s;
    cin >> s;
    rep(j,0,W) {
      if(s[j] == '#') f[i][j] = 1;
    }
  }
  i64 res = 0;
  rep(i,0,H) {
    rep(j,0,W) {
      i64 ans = bfs(i, j);
      if(ans != -1) {
        res = std::max(res, ans);
      }
    }
  }
  cout << res << endl;
}
