import qualified Data.ByteString.Char8 as BS
import Data.Maybe
import           Data.Monoid
import           Control.Monad
import Data.Array
import Data.Array.ST
import Control.Monad.ST
tuplify2 (x:y:_) = (x,y)
tuplify2 _ = undefined


readInt = fst . fromJust . BS.readInt
readIntTuple = tuplify2 . map readInt . BS.words
readIntList = map readInt . BS.words

getInt = readInt <$> BS.getLine
getIntList = readIntList <$> BS.getLine
getIntNList n = map readIntList <$> replicateM (fromIntegral n) BS.getLine
getIntMatrix = map readIntList . BS.lines <$> BS.getContents
getIntTuple = readIntTuple <$> BS.getLine
getIntNTuples n = map readIntTuple <$> replicateM (fromIntegral n) BS.getLine
getIntTuples = map readIntTuple . BS.lines <$> BS.getContents

type Pos = (Int,Int)
type Graph = Array Pos Char
main = do
    [h,w] <- getIntList
    a <- concat <$> replicateM h getLine
    let grid = listArray ((0,0),(h-1,w-1)) a
        init = [(x,y) | x <- [0..w-1],y <- [0..h-1],grid ! (x,y) == '#']
    --print grid
    print $ bfs grid init
    return()

next :: Graph -> Pos -> [Pos]
next g (y,x) = [(ny,nx) | (dy,dx) <- zip [0,1,0,-1] [1,0,-1,0],let ny=y+dy,let nx=x+dx,0 <= ny && ny <= h' && 0 <= nx && nx <= w' && g ! (ny,nx) /= '#']
    where (h',w') = snd $ bounds g


bfs :: Array Pos Char -> [Pos] -> Int
bfs grid init = runST (do
    g <- thaw grid :: ST s (STUArray s Pos Char)
    f g $ zip init $ repeat 0)
    where   f :: STUArray s Pos Char -> [(Pos,Int)] -> ST s Int
            f _ [] = return 0
            f g ((p,d):ps) = do
                curGraph <- freeze g
                let ne = zip (next curGraph p) (repeat (d+1))
                forM_ ne $ \((ny,nx),_) -> writeArray g (ny,nx) '#'
                v <- f g (ps++ne)
                return $ max d v
                