#[test]
fn test_solve() {
    assert_eq!(solve("3 3\n...\n...\n...\n"), "4\n");
    assert_eq!(solve("3 5\n...#.\n.#.#.\n.#...\n"), "10\n");
}

fn solve(src: &str) -> String {
    let mut sc = Scanner::from_str(src);

    let h: usize = sc.read();
    let w: usize = sc.read();
    let s: Vec<Vec<char>> = (0..h).map(|_| sc.chars()).collect();
    let mut nbr: Vec<Vec<(usize, i64)>> = vec![Vec::new(); h*w];
    for i in 0..h {
        for j in 0..w {
            if s[i][j] == '#' {
                continue;
            }
            if i > 0 && s[i-1][j] == '.' {
                nbr[i*w+j].push(((i-1)*w+j, 1));
            }
            if i < h-1 && s[i+1][j] == '.' {
                nbr[i*w+j].push(((i+1)*w+j, 1));
            }
            if j > 0 && s[i][j-1] == '.' {
                nbr[i*w+j].push((i*w+(j-1), 1));
            }
            if j < w-1 && s[i][j+1] == '.' {
                nbr[i*w+j].push((i*w+(j+1), 1));
            }
        }
    }

    let d= shortest_dists(&nbr);

    let mut ans = 0;

    for i in 0..h*w {
        for j in 0..h*w {
            if d[i][j] > ans && d[i][j] <= 400 {
                ans = d[i][j]
            }
        }
    }

    format!("{}\n", ans)
}

fn shortest_dists(neighbor: &[Vec<(usize, i64)>]) -> Vec<Vec<i64>> {
    let n = neighbor.len();
    let mut d = vec![vec![i64::max_value() >> 1; n]; n];
    for v in 0..n {
        for &(w, c) in &neighbor[v] {
            d[v][w] = c;
        }
    }
    for k in 0..n {
        for i in 0..n {
            for j in 0..n {
                d[i][j] = std::cmp::min(d[i][j], d[i][k] + d[k][j])
            }
        }
    }
    d
}

fn main() {
    let mut buf = String::new();
    use std::io;
    use std::io::{Read, Write};
    io::stdin().read_to_string(&mut buf).unwrap();
    io::stdout().write_all(solve(&buf).as_bytes()).unwrap();
}

struct Scanner<'a>(std::str::SplitWhitespace<'a>);
impl<'a> Scanner<'a> {
    fn from_str(src: &str) -> Scanner {
        Scanner(src.split_whitespace())
    }
    fn get(&mut self) -> &str {
        self.0.next().unwrap()
    }
    fn read<T: std::str::FromStr>(&mut self) -> T {
        self.get().parse().ok().unwrap()
    }
    fn chars(&mut self) -> Vec<char> {
        self.get().chars().collect()
    }
}