use std::collections::VecDeque;
macro_rules! input {
    (source = $s:expr, $($r:tt)*) => {
        let mut iter = $s.split_whitespace();
        let mut next = || { iter.next().unwrap() };
        input_inner!{ next, $($r)* }
    };
    ($($r:tt)*) => {
        let stdin = std::io::stdin();
        let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock()));
        let mut next = move || -> String{
            bytes
                .by_ref()
                .map(|r| r.unwrap() as char)
                .skip_while(|c| c.is_whitespace())
                .take_while(|c| !c.is_whitespace())
                .collect()
        };
        input_inner!{ next, $($r)* }
    };
}

macro_rules! input_inner {
    ($next:expr) => {};
    ($next:expr, ) => {};
    ($next:expr, $var:ident : $t:tt $($r:tt)*) => {
        let $var = read_value!($next, $t);
        input_inner!{ $next $($r)* }
    };
}

macro_rules! read_value {
    ($next:expr, ( $($t:tt), * )) => {
        ( $(read_value!($nex, $t)), * )
    };

    ($next:expr, [ $t:tt ; $len:expr ]) => {
        (0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>()
    };

    ($next:expr, chars) => {
        read_value!($next, String).chars().collect::<Vec<char>>()
    };

    ($next:expr, usize1) => {
        read_value!($next, usize) - 1
    };

    ($next:expr, $t:ty) => {
        $next().parse::<$t>().expect("Failed to parse")
    }
}

fn bfs(i: usize, j: usize, board: &Vec<Vec<char>>) -> usize {
    let mut count = 0;
    let mut queue = VecDeque::new();
    let mut b = board.clone();
    queue.push_back((i, j, 0));

    while let Some((i, j, c)) = queue.pop_front() {
        count = std::cmp::max(count, c);

        if i > 0 && b[i-1][j] == '.' {
            queue.push_back((i - 1, j, c + 1));
            b[i-1][j] = '#';
        }
        if j > 0 && b[i][j-1] == '.' {
            queue.push_back((i, j - 1, c + 1));
            b[i][j-1] = '#';
        }
        if i < b.len() - 1  && b[i+1][j] == '.' {
            queue.push_back((i + 1, j, c + 1));
            b[i+1][j] = '#';
        }
        if j < b[0].len() - 1 && b[i][j+1] == '.' {
            queue.push_back((i, j + 1, c + 1));
            b[i][j+1] = '#';
        }
    }
    count
}

fn main() {
    input!{
        h: usize,
        w: usize,
        board: [chars; h]
    }

    let mut ans = 0;

    for i in 0..h {
        for j in 0..w {
            if board[i][j] == '#' {
                continue;
            }
            ans = std::cmp::max(ans, bfs(i,j, &board));
        }
    }
    
    println!("{}", ans);
}