pub fn read<T: std::str::FromStr>() -> T {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().parse().ok().unwrap()
}
pub fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>()
        .split_whitespace()
        .map(|e| e.parse().ok().unwrap())
        .collect()
}
pub fn read_vec2<T: std::str::FromStr>(n: usize) -> Vec<Vec<T>> {
    (0..n).map(|_| read_vec()).collect()
}
pub fn read_col<T: std::str::FromStr>(n: usize) -> Vec<T> {
    (0..n).map(|_| read()).collect()
}

use std::cmp::{max, min};
use std::collections::VecDeque;

fn main() {
    let hw: Vec<usize> = read_vec();
    let h = hw[0];
    let w = hw[1];
    let sv: Vec<String> = read_col(h);
    let mat: Vec<Vec<char>> = sv.into_iter().map(|s| s.chars().collect()).collect();
    let mut ans = 0;

    for i in 0..h * w {
        let sh = i / w;
        let sw = i % w;

        if &mat[sh][sw] == &'#' {
            continue;
        }

        // dfs
        let longest = dfs(&mat, h, w, sh, sw);
        ans = max(ans, longest);
    }
    println!("{}", ans);
}

fn dfs(map: &Vec<Vec<char>>, h: usize, w: usize, sh: usize, sw: usize) -> i64 {
    let mut vd = VecDeque::new();
    let mut check: Vec<Vec<bool>> = vec![vec![false; w]; h];
    let mut ret = 0;
    for i2 in 0..h {
        for j2 in 0..w {
            if map[i2][j2] == '#' {
                check[i2][j2] = true;
            }
        }
    }

    let mut ret = 0;
    vd.push_back((sh, sw, 0));
    let mut map_cnt: Vec<Vec<i64>> = vec![vec![std::i64::MAX; w]; h];

    loop {
        match vd.pop_front() {
            None => {
                break;
            }
            Some((sh2, sw2, d)) => {
                check[sh2][sw2] = true;
                if sh2 > 0 && !check[sh2 - 1][sw2] {
                    vd.push_back((sh2 - 1, sw2, d + 1));
                    ret = d + 1;
                }

                if sw2 > 0 && !check[sh2][sw2 - 1] {
                    vd.push_back((sh2, sw2 - 1, d + 1));
                    ret = d + 1;
                }
                if sh2 < h - 1 && !check[sh2 + 1][sw2] {
                    vd.push_back((sh2 + 1, sw2, d + 1));
                    ret = d + 1;
                }
                if sw2 < w - 1 && !check[sh2][sw2 + 1] {
                    vd.push_back((sh2, sw2 + 1, d + 1));
                    ret = d + 1;
                }
            }
        }
    }
    return ret;
}
