#include <bits/stdc++.h>
using namespace std;
const long long INF = 1LL << 60;
const long long MOD = 1000000007;
template <class T>
inline bool chmin(T &a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template <class T>
inline bool chmax(T &a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &vec) {
  for (T &x : vec) is >> x;
  return is;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, pair<T, U> &pair_var) {
  os << "(" << pair_var.first << ", " << pair_var.second << ")";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &vec) {
  os << "{";
  for (long long i = 0; i < vec.size(); i++) {
    os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
  }
  os << "}";
  return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, map<T, U> &map_var) {
  os << "{";
  for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
    os << *itr;
    itr++;
    if (itr != map_var.end()) os << ", ";
    itr--;
  }
  os << "}";
  return os;
}
template <typename T>
ostream &operator<<(ostream &os, set<T> &set_var) {
  os << "{";
  for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
    os << *itr;
    itr++;
    if (itr != set_var.end()) os << ", ";
    itr--;
  }
  os << "}";
  return os;
}
void dump_func() { cerr << endl; }
template <class Head, class... Tail>
void dump_func(Head &&head, Tail &&...tail) {
  cerr << head;
  if (sizeof...(Tail) > 0) {
    cerr << ", ";
  }
  dump_func(std::move(tail)...);
}
signed main(void) {
  cin.tie(0);
  ios::sync_with_stdio(false);
  long long h, w;
  cin >> h >> w;
  vector<vector<char>> grid(h, vector<char>(w));
  for (long long(i) = 0; (i) < (h); (i)++) {
    for (long long(j) = 0; (j) < (w); (j)++) cin >> grid[i][j];
  }
  vector<vector<long long>> d(500, vector<long long>(500, INF));
  for (long long(i) = 0; (i) < (h); (i)++) {
    for (long long(j) = 0; (j) < (w); (j)++) {
      if (grid[i][j] == '#') continue;
      if (i - 1 >= 0) {
        if (grid[i - 1][j] == '.') {
          d[j + (i * w)][j + ((i - 1) * w)] = 1;
          d[j + ((i - 1) * w)][j + (i * w)] = 1;
        }
      }
      if (i + 1 < h) {
        if (grid[i + 1][j] == '.') {
          d[j + (i * w)][j + ((i + 1) * w)] = 1;
          d[j + ((i + 1) * w)][j + (i * w)] = 1;
        }
      }
      if (j - 1 >= 0) {
        if (grid[i][j - 1] == '.') {
          d[j + (i * w)][j - 1 + i * w] = 1;
          d[j - 1 + (i * w)][j + (i * w)] = 1;
        }
      }
      if (j + 1 < w) {
        if (grid[i][j + 1] == '.') {
          d[j + (i * w)][j + 1 + i * w] = 1;
          d[j + 1 + (i * w)][j + (i * w)] = 1;
        }
      }
    }
  }
  for (long long k = 0; k < 500; k++) {
    for (long long i = 0; i < 500; i++) {
      for (long long j = 0; j < 500; j++) {
        chmin(d[i][j], d[i][k] + d[k][j]);
      }
    }
  }
  long long ans = 1;
  for (long long(i) = 0; (i) < (500); (i)++) {
    for (long long(j) = 0; (j) < (500); (j)++) {
      if (d[i][j] != INF) {
        chmax(ans, d[i][j]);
      }
    }
  }
  cout << ans << endl;
}
