use std::io::*;
use std::str::FromStr;

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char) 
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

fn readc() -> char {
    let s: String = read();
    return s.chars().nth(0).unwrap();
}

fn read_vec<T: FromStr>(n: usize) -> Vec<T> {
    return (0..n).map(|_| read()).collect();
}

fn solve(map: Vec<Vec<char>>) -> usize {
    fn _solve(i: i32, j: i32, map: &Vec<Vec<char>>) -> usize {
        let v_vec: Vec<(i32, i32)> = vec![(1, 0), (-1, 0), (0, 1), (0, -1)];
        let mut next_pos: Vec<(i32, i32)> = Vec::new();

        let mut visited: Vec<Vec<bool>> = (0..map.len()).map(|_| (0..map[0].len()).map(|_| false).collect()).collect();
        visited[i as usize][j as usize] = true;
        let mut cnt = 0;

        fn is_bad_pos_or_visited(i: i32, j: i32, visited: &Vec<Vec<bool>>) -> bool {
            if i < 0 || i >= visited.len() as i32 {
                return true;
            }
            if j < 0 || j >= visited[0].len() as i32 {
                return true;
            }

            let i = i as usize;
            let j = j as usize;
            if visited[i][j] {
                return true;
            }

            return false;
        }

        loop {
            let tmp_next_pos = next_pos.clone();
            next_pos = Vec::new();
            for pos in tmp_next_pos.iter() {
                let i = pos.0;
                let j = pos.1;
                if is_bad_pos_or_visited(i, j, &visited) {
                    continue;
                }

                let i = i as usize;
                let j = j as usize;
                visited[i][j] = true;
                if map[i][j] == '#' {
                    continue;
                }

                let i = i as i32;
                let j = j as i32;
                for v in v_vec.iter() {
                    next_pos.push((i+v.0, j+v.1));
                }
            }

            for v in v_vec.iter() {
                let i = i+v.0;
                let j = j+v.1;
                if is_bad_pos_or_visited(i, j, &visited) {
                    continue;
                }
                next_pos.push((i, j));
            }

            if next_pos.len() == 0 {
                return cnt - 1;
            }

            cnt += 1;
        }

        return 0;
    }

    let mut ans = 0;
    for i in 0..map.len() {
        for j in 0..map[0].len() {
            if map[i][j] == '#' {
                continue;
            }
            let mut tmp_map = map.clone();
            tmp_map[i][j] = 's';
            let i = i as i32;
            let j = j as i32;
            let cnt = _solve(i, j, &tmp_map);
            if cnt > ans {
                ans = cnt;
            }
        }
    }

    return ans;
}

fn main() {
    let h: usize = read();
    let w: usize = read();
    let c_ij: Vec<Vec<char>> = (0..h).map(|_| read::<String>().chars().collect()).collect();

    println!("{}", solve(c_ij));
}


Measured memory_bytes: 4352