use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();
    
    let mut input = buffer.trim().split_whitespace();
    let h = input.next().unwrap().to_string().parse::<usize>().unwrap();
    let w = input.next().unwrap().to_string().parse::<usize>().unwrap();

    let mut maze = vec!(vec!(None; w); h);
    let mut counter = 0;
    for y in 0..h {
        let mut buffer = String::new();
        io::stdin().read_line(&mut buffer).unwrap();
        let line: Vec<char> = buffer.trim().chars().collect();
        for x in 0..w {
            if line[x] == (".").parse().unwrap() {
                maze[y][x] = Some(counter);
                counter += 1;
            }
        }
    }

    let mut graph = vec!(vec!(std::usize::MAX / 2; counter); counter);
    for y in 0..h {
        for x in 0..w {
            if let Some(c) = maze[y][x] {
                for mov in &[(-0isize, 0), (1, 0), (0, 1), (0, -1isize)] {
                    let (mx, my) = mov;
                    let (nx, ny) =(x as isize+mx, y as isize+my);
                    if ny < 0 || nx < 0 || ny > h as isize-1 || nx > w as isize-1 { continue; }
                    let (nx, ny) = (nx as usize, ny as usize);
                    if let Some(oc) = maze[ny][nx] {
                        graph[c][oc] = 1;
                        graph[oc][c] = 1;
                    }
                }
            }
        }
    }

    for y in 0..counter {
        graph[y][y] = 0;
    }

    for m in 0..counter {
        for i in 0..counter {
            for j in 0..counter {
                graph[i][j] = std::cmp::min(graph[i][j], graph[i][m] + graph[m][j]);
            }
        }
    }
    println!("{}", graph.iter().map(|v| v.iter().max().unwrap()).max().unwrap());
}
