#include <iostream> // cout, endl, cin
#include <string> // string, to_string, stoi
#include <vector> // vector
#include <algorithm> // min, max, swap, sort, reverse, lower_bound, upper_bound
#include <utility> // pair, make_pair
#include <tuple> // tuple, make_tuple
#include <cstdint> // int64_t, int*_t
#include <cstdio> // printf
#include <map> // map
#include <queue> // queue, priority_queue
#include <set> // set
#include <stack> // stack
#include <deque> // deque
#include <unordered_map> // unordered_map
#include <iomanip>
#include <unordered_set> // unordered_set
#include <bitset> // bitset
#include <cctype> // isupper, islower, isdigit, toupper, tolower
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
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; }
const int INF = 1001001000;
const int MOD = 1000000007;

typedef pair<int, int> P;
int myAbs(int num) {
    if (num > 0)
        return num;
    else
        return -num;
}

long long gcd(long long a, long long b) {
    if (b == 0) return a;
    else return gcd(b, a % b);
}
long long lcm(long long a, long long b) {
    return a * b / gcd(a, b);
}

using Graph = vector<vector<int>>;
//再帰とかグラフを使うときは予めNの最大値のグローバル配列を取っておく
int N;
vector<int> E[200001];
vector<bool> seen;
typedef pair<int, int> P;
int D[101];
//頂点状態を表すcolor[]において、0は未訪問、1は訪問中、2は完了を表す。
int color[101];
int find_time = 0;
vector<int> ans(200001);

//using Maze = vector<vector<char>>;
//using D = vector<vector<int>>;
char Maze[51][51];

int maze_solve(int N, int M, int sx, int sy, int gx, int gy) {
    queue<P> que;
    que.push(P(sx, sy));
    //配列はNとMの最大値+1くらいをとっておく
    int D[51][51];
    
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            //cin >> Maze[i][j];
            D[i][j] = INF;
        }
    }

    int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 };
    D[sx][sy] = 0;
    //Maze[sx][sy] = 0;
    //ここから処理
    while (que.size()) {
        P p = que.front();
        que.pop();
        if (p.first == gx && p.second == gy) break;
        for (int i = 0; i < 4; i++) {
            int nx, ny;
            nx = p.first + dx[i]; ny = p.second + dy[i];
            if (nx >= 0 && nx < N && ny >= 0 && ny < M && D[nx][ny] == INF && Maze[nx][ny] != '#') {
                que.push(P(nx, ny));
                D[nx][ny] = D[p.first][p.second] + 1;
            }
        }
    }
    return D[gx][gy];
}

int main() {
    int H, W; cin >> H >> W;
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            cin >> Maze[i][j];
        }
    }
    int count = 0;
    int ans = 0;
    //スタート地点
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < W; j++) {
            //ゴール地点
            for (int k = 0; k < H; k++) {
                for (int l = 0; l < W; l++) {
                    int sx, sy, gx, gy;
                    sx = i, sy = j, gx = k, gy = l;
                    if (Maze[sx][sy] != '#' && Maze[gx][gy] != '#') { 
                        count = maze_solve(H, W, sx, sy, gx, gy); 
                        ans = max(ans, count);
                    }
                }
            }
        }
    }

    cout << ans << endl;
}


Measured memory_bytes: 5760