//Md Fahad
// CSE 18

#include<bits/stdc++.h>

using  namespace  std;

#define PI              acos(-1.0)
#define lcm(a,b)        (a * (b / __gcd(a,b)))
#define en '\n'

#define READ_IN freopen("Input.txt","r",stdin);
#define READ_OUT freopen("Output.txt","w",stdout);
#define Infi                0x3f3f3f3f

const int dx[] = {+1,-1,+0,+0};                         // 4 X directions
const int dy[] = {+0,+0,+1,-1};                         // 4 Y directions
const int dx8[] = {+0,+0,+1,-1,-1,+1,-1,+1};            // King X Moves
const int dy8[] = {-1,+1,+0,+0,+1,+1,-1,-1};            // King Y Moves
const int kx[] = {-2, -2, -1, -1,  1,  1,  2,  2};      // Knight X Moves
const int ky[] = {-1,  1, -2,  2, -2,  2, -1,  1};      // Knight Y Moves



int  Set    (int N,int pos) {return N=N | (1<<pos);}    /// turn a bit on
int  reset  (int N,int pos) {return N= N & ~(1<<pos);}  /// turn a bit off
bool check  (int N,int pos) {return (bool)(N & (1<<pos));} /// check, if a bit is on or not

void __print(int x) {cerr << x;}
void __print(long x) {cerr << x;}
void __print(long long x) {cerr << x;}
void __print(unsigned x) {cerr << x;}
void __print(unsigned long x) {cerr << x;}
void __print(unsigned long long x) {cerr << x;}
void __print(float x) {cerr << x;}
void __print(double x) {cerr << x;}
void __print(long double x) {cerr << x;}
void __print(char x) {cerr << '\'' << x << '\'';}
void __print(const char *x) {cerr << '\"' << x << '\"';}
void __print(const string &x) {cerr << '\"' << x << '\"';}
void __print(bool x) {cerr << (x ? "true" : "false");}

template<typename T, typename V>
void __print(const pair<T, V> &x) {cerr << '{'; __print(x.first); cerr << ','; __print(x.second); cerr << '}';}
template<typename T>
void __print(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), __print(i); cerr << "}";}
void _print() {cerr << "]\n";}
template <typename T, typename... V>
void _print(T t, V... v) {__print(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#ifndef ONLINE_JUDGE
#define trace(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define trace(x...)
#endif

typedef long long int           ll;
typedef unsigned long long int  llu;

typedef pair<int,int> pii;

const int maxe = 30;

vector<string> grid;
vector<vector<bool> > visited;
vector<vector<int>> level;

int h,w;
int ans=0;
int bfs(int x_sos,int y_sos)
{
    ans=0;

    queue<pii> Q;
    Q.push({x_sos,y_sos});

    visited[x_sos][y_sos]=true;
    level[x_sos][y_sos]=0;

    while(!Q.empty())
    {
        pii p = Q.front();

        Q.pop();

        int xx = p.first;
        int yy = p.second;

        for(int i =0;i<4;i++)
        {
            int ux = xx + dx[i];
            int uy = yy + dy[i];

            if(ux>=0 && ux<h && uy>=0 && uy<w && visited[ux][uy]==false && grid[ux][uy]!='#')
            {
                visited[ux][uy]=true;
                Q.push({ux,uy});
                level[ux][uy]=level[xx][yy]+1;

                ans = max(ans,level[ux][uy]);
            }
        }
    }


    return ans;

}


int main(void)
{
    //READ_IN;
    //READ_OUT;


    cin >> h >> w;

    visited.assign(maxe,vector<bool>(maxe,false));
    level.assign(maxe,vector<int>(maxe,0));

    for(int i=0;i<h;i++)
    {
        string s;
        cin >> s;
        grid.push_back(s);
    }

    bool bol = false;

     int maxe_x=0,maxe_y=0;
    int lev = 1;

    int Ans = 0;

    for(int i=0;i<grid.size();i++)
    {
        for(int j=0;j<grid[i].size();j++)
        {
            if(grid[i][j]!='#'){

                    visited.assign(maxe,vector<bool>(maxe,false));
                    level.assign(maxe,vector<int>(maxe,0));

                 Ans = max(Ans,bfs(i,j));



            }
        }

    }


    cout << Ans << endl;


    return 0;
}




Measured memory_bytes: 256