#include <bits/stdc++.h>
using namespace std;
long long gcd(long long x, long long y) { return y ? gcd(y, x % y) : x; }
template <class T = long long>
T input() {
  T x;
  cin >> x;
  return x;
}
template <class T>
void output(T x) {
  cout << x << endl;
}
struct Vec2 {
  Vec2(int x, int y) {
    this->x = x;
    this->y = y;
  }
  int x;
  int y;
  Vec2 operator+(Vec2 other) {
    return Vec2(this->x + other.x, this->y + other.y);
  }
};
vector<vector<int>> course;
long saitankyori(Vec2 start) {
  for (auto iter : {Vec2(-1, 0), Vec2(1, 0), Vec2(0, -1), Vec2(0, 1)}) {
    Vec2 targetVec = start + iter;
    if (targetVec.x >= 0 && targetVec.x < course.size() && targetVec.y >= 0 &&
        targetVec.y < course[0].size()) {
      course[targetVec.x][targetVec.y] =
          min(course[start.x][start.y] + 1, course[targetVec.x][targetVec.y]);
      if (course[targetVec.x][targetVec.y] > course[start.x][start.y] &&
          course[targetVec.x][targetVec.y] > 0) {
        saitankyori(targetVec);
      }
    }
  }
  return 0;
}
pair<int, Vec2> getMax(vector<vector<int>> c) {
  int ret = 0;
  Vec2 ret2 = Vec2(0, 0);
  for (int i = 0; i < c.size(); i++) {
    for (int j = 0; j < c[0].size(); j++) {
      if (ret < c[i][j]) {
        ret = c[i][j];
        ret2 = Vec2(i, j);
      }
    }
  }
  return {ret, ret2};
}
int main() {
  int H = input();
  int W = input();
  vector<vector<int>> course_temp(H, vector<int>(W, 100));
  for (int i = 0; i < H; i++) {
    string s = input<string>();
    for (int j = 0; j < W; j++) {
      if (s.substr(j, 1) != ".") {
        course_temp[i][j] = -1;
      }
    }
  }
  course = course_temp;
  course[0][0] = 0;
  saitankyori(Vec2(0, 0));
  Vec2 v = getMax(course).second;
  course = course_temp;
  course[v.x][v.y] = 0;
  saitankyori(v);
  output(getMax(course).first);
  return 0;
}
