#include <iostream>
#include <set>
#include <vector>
#include <tuple>
#include <queue>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
typedef unsigned int ui;
typedef std::vector<int> vi;
typedef std::vector<ll> vl;
typedef std::vector<vi> vvi;
typedef std::vector<vl> vvl;
typedef std::pair<int,int> pii;
typedef std::pair<int,ll> pil;
typedef std::pair<ll,int> pli;
typedef std::pair<ll,ll> pll;
typedef std::vector<std::pair<int,int>> vpii;
#define fori(n) for(int i = 0; i < (n); i++)
#define forj(n) for(int j = 0; j < (n); j++)
#define fork(n) for(int k = 0; k < (n); k++)
#define isz(x) (int)size(x)
#define all(x) std::begin(x), std::end(x)
#define fi first
#define se second
// Input:
template<typename T>
std::istream& operator>>(std::istream& is, std::vector<T>& vec) {
    for (auto &it : vec) is >> it;
    return is;
}
template<typename T1, typename T2>
std::istream& operator>>(std::istream& is, const std::pair<T1, T2>& p) {
    is >> p.fi >> p.se;
    return is;
}
// Output:
template<typename T> std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
    os << "[";
    for (int i = 0; i < vec.size(); i++) os << (i?", ":"") << vec[i];
    return os << "]\n";
}
template<typename T> std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
    os << "{";
    if(s.begin()!=s.end()) os << *s.begin();
    for (typename std::set<T>::iterator i = s.begin(); i != s.end(); i++) os << ", " << *i;
    return os << "}\n";
}
template<typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1, T2>& p) {
    return os << "(" << p.first << ", " << p.second << ")";
}
template<typename T1, typename T2, typename T3> 
std::ostream& operator<<(std::ostream& os, const std::tuple<T1, T2, T3>& p) {
    return os << "(" << p.first << ", " << p.second << ", " << p.third << ")";
}
template<typename T1, typename T2>
std::pair<T1, T2> operator+(const std::pair<T1, T2>& p1, const std::pair<T1, T2>& p2) {
    return std::pair<T1, T2>(p1.fi+p2.fi,p1.se+p2.se);
}
template<int>
class residue;
template<int Mod>
residue<Mod> pow(residue<Mod> a, int n);
template<int Mod=int(1e9+7)>
class residue
{
public:
    long long val;
    residue(long long Value){
        val = Value<0?(-Value)%Mod: Value%Mod;if(Value<0)*(this)=*(this)*residue(Mod-1);}
    residue operator+(residue A){return residue((val+A.val) % Mod);}
    residue operator*(residue A){return residue((val*A.val) % Mod);}
    residue operator/(residue A){return *(this)*pow(A, -1);}
    operator int(){return val;}
};
template<int Mod=int(1e9+7)>
residue<Mod> pow(residue<Mod> a, ui n) {
    return n?n&1?pow(a*a, n/2)*a:pow(a*a, n/2):residue<Mod>(1);}
template<int Mod=int(1e9+7)>
residue<Mod> pow(residue<Mod> a, int n){
    return n==-1?pow(a, ui(Mod-2)):n<0?pow(pow(a,-1), ui(-n)):pow(a, ui(n));}
int main()
{
	ios_base::sync_with_stdio(0); cin.tie(0); cin.tie(nullptr);
	int h, w, ans=0;
    char c;
    cin >> h >> w;
    std::vector<std::vector<bool>> v(h, std::vector<bool>(w));
    fori(h)forj(w)
    {
        cin >> c;
        v[i][j]=(c=='.');
    }
    fori(h)forj(w)if(v[i][j])
    {
        queue<pii> Q;
        Q.push(pii(i,j));
        std::vector<std::vector<int>> used(h, std::vector<int>(w, -1));
        used[i][j]=0;
        vector<pii> conecting{pii(0, -1), pii(-1, 0), pii(1, 0), pii(0, 1)};
        while(!Q.empty())
        {
            for(auto& el:conecting)
            {
                pii p =el+Q.front();
                if((p.fi>=0&&p.se>=0)&&(p.fi<h &&p.se<w)&&(v[p.fi][p.se])&&(used[p.fi][p.se]==-1))
                {
                    used[p.fi][p.se]=used[Q.front().fi][Q.front().se]+1;
                    ans=max(ans, used[p.fi][p.se]);
                    Q.push(p);
                }
            }
            Q.pop();
        }
    }
    cout << ans<<endl;
    return 0;
}

Measured memory_bytes: 256