use std::io::Write;

#[allow(unused)]
macro_rules! debug {
    ($($format:tt)*) => (write!(std::io::stderr(), $($format)*).unwrap());
}
#[allow(unused)]
macro_rules! debugln {
    ($($format:tt)*) => (writeln!(std::io::stderr(), $($format)*).unwrap());
}

fn main() {
    let (h, w): (usize, usize) = {
        let mut s = String::new();
        std::io::stdin().read_line(&mut s).unwrap();
        let s = s.trim_right().to_owned();
        let mut ws = s.split_whitespace();
        let a = ws.next().unwrap().parse().unwrap();
        let b = ws.next().unwrap().parse().unwrap();
        (a, b)
    };

    let maze: Vec<Vec<char>> = {
        let mut v = Vec::new();
        for _ in 0..h {
            let v_i = {
                let mut s = String::new();
                std::io::stdin().read_line(&mut s).unwrap();
                let s = s.trim_right().to_owned();
                s.chars().collect()
            };
            v.push(v_i)
        }
        v
    };

    const ROAD: char = '.';
    const WALL: char = '#';

    let mut index = 0;
    let mut coord_to_index = vec![vec![0; w]; h];
    for i in 0..h {
        for j in 0..w {
            if maze[i][j] == ROAD {
                coord_to_index[i][j] = index;
                index += 1;
            }
        }
    }
    // for i in 0..h {
    //     debugln!("{:?}", coord_to_index[i]);
    // }

    let num_node = index;
    // debugln!("num_node: {}", num_node);

    let mut graph: Vec<Vec<usize>> = vec![vec![0; num_node]; num_node];
    for i in 0..h {
        for j in 0..w {
            if maze[i][j] != ROAD {
                continue;
            }

            if i + 1 < h && maze[i + 1][j] == ROAD {
                let from = coord_to_index[i][j];
                let to = coord_to_index[i + 1][j];
                graph[from][to] = 1;
            }
            if j + 1 < w && maze[i][j + 1] == ROAD {
                let from = coord_to_index[i][j];
                let to = coord_to_index[i][j + 1];
                graph[from][to] = 1;
            }
            if i >= 1 && maze[i - 1][j] == ROAD {
                let from = coord_to_index[i][j];
                let to = coord_to_index[i - 1][j];
                graph[from][to] = 1;
            }
            if j >= 1 && maze[i][j - 1] == ROAD {
                let from = coord_to_index[i][j];
                let to = coord_to_index[i][j - 1];
                graph[from][to] = 1;
            }

            // debugln!("");
            // for i in 0..num_node {
            //     debugln!("{:?}", graph[i]);
            // }
        }
    }

    // for i in 0..num_node {
    //     debugln!("{:?}", graph[i]);
    // }

    let ans = graph_diameter(&graph);
    println!("{}", ans);
}

// Warshall-Floyd法
#[allow(unused)]
fn warshall_floyd(graph_mat: &[Vec<usize>]) -> Vec<Vec<usize>> {
    let n = graph_mat.len();

    let mut d = vec![vec![std::usize::MAX >> 2; n]; n];
    for i in 0..n {
        for j in 0..n {
            if graph_mat[i][j] == 1 {
                d[i][j] = 1;
            }
        }
    }
    for i in 0..n {
        d[i][i] = 0;
    }

    for k in 0..n {
        for i in 0..n {
            for j in 0..n {
                if d[i][j] > d[i][k] + d[k][j] {
                    d[i][j] = d[i][k] + d[k][j];
                }
            }
        }
    }

    d
}

// グラフの直径
#[allow(unused)]
fn graph_diameter(graph_mat: &[Vec<usize>]) -> usize {
    let d_mat = warshall_floyd(&graph_mat);
    let mut diameter = 0;
    for v in d_mat {
        for d in v {
            if d > diameter {
                diameter = d;
            }
        }
    }

    diameter
}


Measured memory_bytes: 6396