#include <bits/stdc++.h>
using namespace std;
long long gcd(long long a, long long b) {
  if (a % b == 0) {
    return b;
  } else
    return gcd(b, a % b);
}
long long lcm(long long a, long long b) {
  if (a == 0) {
    return b;
  }
  return a / gcd(a, b) * b;
}
template <class T>
long long LBI(vector<T>& ar, T in) {
  return lower_bound(ar.begin(), ar.end(), in) - ar.begin();
}
template <class T>
long long UBI(vector<T>& ar, T in) {
  return upper_bound(ar.begin(), ar.end(), in) - ar.begin();
}
long long h, w, ans = 0;
char s[30][30] = {};
const int INF = 7 + (1e+9);
struct Edge {
  int src, dst;
  int weight;
  Edge(int src, int dst, int weight) : src(src), dst(dst), weight(weight) {}
};
bool operator<(const Edge& e, const Edge& f) {
  return e.weight != f.weight ? e.weight > f.weight
         : e.src != f.src     ? e.src < f.src
                              : e.dst < f.dst;
}
bool shortestPath(const vector<vector<Edge> >& g, vector<vector<int> >& dist,
                  vector<vector<int> >& inter) {
  int n = g.size();
  dist.assign(n, vector<int>(n, INF));
  for (int i = 0; i < n; i++) {
    dist[i][i] = 0;
  }
  for (int i = 0; i < n; i++) {
    for (auto f = g[i].begin(); f != g[i].end(); f++) {
      dist[i][f->dst] = f->weight;
    }
  }
  inter.assign(n, vector<int>(n, -1));
  for (int k = 0; k < n; k++) {
    for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
        if (dist[i][k] < INF && dist[k][j] < INF &&
            dist[i][j] > dist[i][k] + dist[k][j]) {
          dist[i][j] = dist[i][k] + dist[k][j];
          inter[i][j] = k;
        }
      }
    }
  }
  for (int i = 0; i < n; i++) {
    if (dist[i][i] < 0) {
      return false;
    }
  }
  return true;
}
void buildPath(const vector<vector<int> >& inter, int s, int t,
               vector<int>& path) {
  int u = inter[s][t];
  if (u < 0)
    path.push_back(s);
  else
    buildPath(inter, s, u, path), buildPath(inter, u, t, path);
}
int main() {
  cin >> h >> w;
  for (int i = 0; i < (h); ++i) {
    for (int j = 0; j < (w); ++j) cin >> s[i][j];
  }
  vector<vector<Edge> > g(h * w);
  for (int i = 0; i < (h); ++i) {
    for (int j = 0; j < (w); ++j) {
      if (i < h - 1 && s[i][j] == '.' && s[i + 1][j] == '.') {
        g[i * h + j].push_back(Edge(i * h + j, (i + 1) * h + j, 1));
        g[(i + 1) * h + j].push_back(Edge((i + 1) * h + j, i * h + j, 1));
      }
      if (j < w - 1 && s[i][j] == '.' && s[i][j + 1] == '.') {
        g[i * h + j].push_back(Edge(i * h + j, i * h + j + 1, 1));
        g[i * h + j + 1].push_back(Edge(i * h + j + 1, i * h + j, 1));
      }
    }
  }
  vector<vector<int> > dist;
  vector<vector<int> > inter;
  bool negative_cycle = shortestPath(g, dist, inter);
  for (int i = 0; i < (h * w); ++i) {
    for (int j = 0; j < (h * w); ++j) {
      if (dist[i][j] != INF) ans = max(ans, (long long)dist[i][j]);
    }
  }
  cout << ans << endl;
  return 0;
}
