#include <bits/stdc++.h>
#include <boost/range/irange.hpp>
using namespace std;
using boost::irange;

using ll = int64_t;
constexpr char LN = '\n';
template<class T> bool chmax(T& a, const T& b) {if(a<b){a=b;return true;}else{return false;}}
template<class T> bool chmin(T& a, const T& b) {if(b<a){a=b;return true;}else{return false;}}

#ifdef LOCAL
template<class H> void dump_(const char* s, H h) {cout<<s<<"="<<h<<LN; }
template<class H, class... T> void dump_(const char* s, H h, T... t) {for(;*s!=',';++s){cout<<*s;}cout<<"="<<h<<",";dump_(++s,t...);}
#define dump(...) dump_(#__VA_ARGS__, __VA_ARGS__)
#else
#define dump(...)
#endif

struct init_ {init_(){ 
    cin.tie(nullptr); ios::sync_with_stdio(false);
    cout << fixed << setprecision(20);
}} init_;

template<class C> C scan(size_t n) {C c(n);for(auto& v:c){cin>>v;}return c;}
template<class C> C scan(size_t n, size_t m) {C vss(n);for(auto& vs:vss){vs.resize(m);for(auto& v:vs){cin>>v;}}return vss;}

template<class R> struct Joined { const R& r; const char* s; };
template<class R> Joined<R> joined(const R& r, const char* s = " ") {return{r,s};}
template<class R> ostream& operator<<(ostream& out, Joined<R> j) {bool f=true;for(const auto& v:j.r){if(f){f=false;}else{out<<j.s;}out<<v;}return out;}

template<class T> using matrix = vector<vector<T>>;
template<class T> matrix<T> make_matrix(size_t n, size_t m, const T& init = T()) {matrix<T> vss(n);for(auto& vs:vss){vs.resize(m,init);}return vss;}
template<class T> ostream& operator<<(ostream& out, Joined<matrix<T>> j) {bool a=true;for(const auto& vs:j.r){if(a){a=false;}else{out<<LN;}bool f=true;for(const auto& v:vs){if(f){f=false;}else{out<<j.s;}out << v;}}return out;}

int main() {
    int H, W;
    cin >> H >> W;
    auto field = scan<matrix<char>>(H, W);
    int maxc = 0;
    for (int si : irange(0, H)) {
        for (int sj : irange(0, W)) {
            dump(si, sj);
            if (field[si][sj] == '#') {
                continue;
            }
            queue<pair<int, int>> q;
            auto dist = make_matrix<int>(H, W, -1);
            q.push(make_pair(si, sj));
            dist[si][sj] = 0;
            while (!q.empty()) {
                dump(joined(dist));
                int i, j;
                tie(i, j) = q.front();
                q.pop();
                if (i > 0 && field[i-1][j] == '.' && dist[i-1][j] == -1) {
                    q.push(make_pair(i-1,j));
                    dist[i-1][j] = dist[i][j] + 1;
                }
                if (i < H-1 && field[i+1][j] == '.' && dist[i+1][j] == -1) {
                    q.push(make_pair(i+1,j));
                    dist[i+1][j] = dist[i][j] + 1;
                }
                if (j > 0 && field[i][j-1] == '.' && dist[i][j-1] == -1) {
                    q.push(make_pair(i,j-1));
                    dist[i][j-1] = dist[i][j] + 1;
                }
                if (j < W-1 && field[i][j+1] == '.' && dist[i][j+1] == -1) {
                    q.push(make_pair(i,j+1));
                    dist[i][j+1] = dist[i][j] + 1;
                }
            }
            for (int gi : irange(0, H)) {
                for (int gj : irange(0, W)) {
                    chmax(maxc, dist[gi][gj]);
                }
            }
        }
    }
    cout << maxc << LN;
}


Measured memory_bytes: 256