import core.bitop, std.algorithm, std.ascii, std.bigint, std.conv, std.math,
    std.functional, std.numeric, std.range, std.stdio, std.string, std.random,
    std.typecons, std.container, std.format;
static import std.ascii;

// dfmt off
T lread(T = long)(){return readln.chomp.to!T();}
T[] aryread(T = long)(){return readln.split.to!(T[])();}
void scan(TList...)(ref TList Args){auto line = readln.split();
foreach (i, T; TList){T val = line[i].to!(T);Args[i] = val;}}
alias sread = () => readln.chomp();enum MOD = 10 ^^ 9 + 7;
alias PQueue(T, alias less = "a<b") = BinaryHeap!(Array!T, less);
// dfmt on

void main()
{
    long H, W;
    scan(H, W);
    auto S = new string[](H);
    foreach (i; 0 .. H)
        scan(S[i]);
    auto G = new long[][](H * W, H * W);
    long id(long h, long w)
    {
        return h * W + w;
    }

    foreach (ref row; G)
        row[] = 1234567;
    foreach (i; 0 .. H)
        foreach (j; 0 .. W)
            if (S[i][j] != '#')
                G[id(i, j)][id(i, j)] = 0;

    foreach (h; 0 .. H)
        foreach (w; 0 .. W)
        {
            if (S[h][w] == '#')
                continue;
            if (0 < h && S[h - 1][w] != '#')
                G[id(h, w)][id(h - 1, w)] = 1;

            if (0 < w && S[h][w - 1] != '#')
                G[id(h, w)][id(h, w - 1)] = 1;

            if (h < H - 1 && S[h + 1][w] != '#')
                G[id(h, w)][id(h + 1, w)] = 1;

            if (w < W - 1 && S[h][w + 1] != '#')
                G[id(h, w)][id(h, w + 1)] = 1;
        }

    // foreach (ref row; G)
    //     writeln(row);
    // writeln();

    foreach (k; 0 .. (H * W))
        foreach (i; 0 .. (H * W))
            foreach (j; 0 .. (H * W))
                if (G[i][j] > G[i][k] + G[k][j])
                    G[i][j] = G[i][k] + G[k][j];

    long ans = -1;
    foreach (row; G)
    {
        // writeln(row);
        foreach (x; row)
            if (x < 1234567)
                ans = max(ans, x);
    }
    writeln(ans);
}
