CodeEff/ECCO huggingface dataset:
# Original solution
import sys

input = sys.stdin.readline

P = 10 ** 9 + 7
Q = 13


def main():
    S = input().rstrip()

    N = len(S)
    dp = [[0] * Q for _ in range(N + 1)]
    dp[0][0] = 1
    for i in range(N):
        base = pow(10, N - 1 - i, Q)
        D = S[i]
        if D == "?":
            for d in range(10):
                n = d * base
                for j in range(Q):
                    next_j = (j + n) % Q
                    dp[i + 1][next_j] += dp[i][j]
                    dp[i + 1][next_j] %= P
        else:
            n = int(D) * base
            for j in range(Q):
                next_j = (j + n) % Q
                dp[i + 1][(j + n) % Q] += dp[i][j]
                dp[i + 1][(j + n) % Q] %= P

    ans = dp[N][5]
    print(ans)


if __name__ == "__main__":
    main()


# Optimized solution
import sys

input = sys.stdin.readline

P = 10 ** 9 + 7
Q = 13


def main():
    S = input().rstrip()

    N = len(S)
    dp = [[0] * Q for _ in range(N + 1)]
    dp[0][0] = 1
    for i in range(N):
        D = S[i]
        if D == "?":
            for d in range(10):
                for j in range(Q):
                    dp[i + 1][(10 * j + d) % Q] += dp[i][j]
        else:
            d = int(D)
            for j in range(Q):
                dp[i + 1][(10 * j + d) % Q] += dp[i][j]

        for j in range(Q):
            dp[i + 1][j] %= P

    ans = dp[N][5]
    print(ans)


if __name__ == "__main__":
    main()
# Original solution
import sys
readline = sys.stdin.readline

conv = {}
for i in range(13):
  conv[i] = (i * 10) % 13

S = readline().rstrip()
N = len(S)
DIV = 10 ** 9 + 7

dp = [[0] * 13 for i in range(N)]

x0 = S[0]
if x0 == "?":
  for i in range(10):
    dp[0][i] = 1
else:
  dp[0][int(x0)] = 1
  
for i in range(1, N):
  x = S[i]
  if x == "?":
    for j in range(13):
      for k in range(10):
        dp[i][(conv[j] + k) % 13] += dp[i - 1][j]
        dp[i][(conv[j] + k) % 13] %= DIV
  else:
    for j in range(13):
      dp[i][(conv[j] + int(x)) % 13] += dp[i - 1][j]
      dp[i][(conv[j] + int(x)) % 13] %= DIV

print((dp[-1][5]))

# Optimized solution
import sys
readline = sys.stdin.readline

S = readline().rstrip()
N = len(S)
DIV = 10 ** 9 + 7

dp = [[0] * 13 for i in range(N)]

x0 = S[0]
if x0 == "?":
  for i in range(10):
    dp[0][i] = 1
else:
  dp[0][int(x0)] = 1
  
for i in range(1, N):
  x = S[i]
  if x == "?":
    for j in range(13):
      for k in range(10):
        ind = (j * 10 + k) % 13
        dp[i][ind] += dp[i - 1][j]
        dp[i][ind] %= DIV
  else:
    for j in range(13):
      ind = (j * 10 + int(x)) % 13
      dp[i][ind] += dp[i - 1][j]
      dp[i][ind] %= DIV

print((dp[-1][5]))
# Original solution
import sys
readline = sys.stdin.readline
MOD = 10 ** 9 + 7

def main():
    S = readline().rstrip()
    N = 13
    dp = [0] * 13  # dp[k]: 13で割った余りがkのパターン数
    dp[0] = 1
    
    mul = 1
    for i in range(len(S)-1, -1, -1):
        next_dp = [0] * N
        s = S[i]
        if s == '?':
            for k in range(10):
                for j in range(N):
                    next_dp[(k * mul + j) % N] += dp[j]
                    next_dp[(k * mul + j) % N] %= MOD
        else:
            k = int(s)
            for j in range(N):
                next_dp[(k * mul + j) % N] += dp[j]
                next_dp[(k * mul + j) % N] %= MOD
        mul *= 10
        mul %= N
        dp = next_dp

    print((dp[5]))

if __name__ == '__main__':
    main()

# Optimized solution
import sys
readline = sys.stdin.readline
MOD = 10 ** 9 + 7

def main():
    S = readline().rstrip()
    N = 13
    dp = [0] * 13  # dp[k]: 13で割った余りがkのパターン数
    dp[0] = 1
    
    mul = 1
    for s in S[::-1]:
        next_dp = [0] * N
        if s == '?':
            for k in range(10):
                for j in range(N):
                    next_dp[(k * mul + j) % N] += dp[j]
                    next_dp[(k * mul + j) % N] %= MOD
        else:
            k = int(s)
            for j in range(N):
                next_dp[(k * mul + j) % N] += dp[j]
                next_dp[(k * mul + j) % N] %= MOD
        mul *= 10
        mul %= N
        dp = next_dp

    print((dp[5]))

if __name__ == '__main__':
    main()
# Original solution
import sys,heapq,math,resource
from collections import deque,defaultdict
printn = lambda x: sys.stdout.write(x)
inn = lambda : int(eval(input()))
inl   = lambda: list(map(int, input().split()))
inm   = lambda:      list(map(int, input().split()))
DBG = True # and False
R = 10**9 + 7

def ddprint(x):
  if DBG:
    print(x)

def setrlim():
  sys.setrecursionlimit(250000)
  soft,hard = resource.getrlimit(RLIMIT_STACK)
  # setrlimit works on ubuntu (and atcoder), but not on WSL
  #resource.setrlimit(RLIMIT_STACK, (128*1024*1024,hard))

rem = [1,10,9,12,3,4]
s = input().strip()
sr = s[::-1]
n = len(s)
dp = [ [0]*13 for i in range(n) ]
if sr[0]=='?':
    for j in range(10):
        dp[0][j] = 1
else:
    j = int(sr[0])
    dp[0][j] = 1

for i in range(1,n):
    r = rem[i%6]
    if sr[i]=='?':
        for j in range(10):
            for k in range(13):
                dp[i][(k+j*r)%13] = (dp[i][(k+j*r)%13] + dp[i-1][k])%R
    else:
        j = int(sr[i])
        for k in range(13):
                dp[i][(k+j*r)%13] = (dp[i][(k+j*r)%13] + dp[i-1][k])%R

print((dp[n-1][5]))


# Optimized solution
#printn = lambda x: sys.stdout.write(x)
inn = lambda : int(eval(input()))
inl   = lambda: list(map(int, input().split()))
inm   = lambda:      list(map(int, input().split()))
DBG = True # and False
R = 10**9 + 7

def ddprint(x):
  if DBG:
    print(x)


rem = [1,10,9,12,3,4]
s = input().strip()
sr = s[::-1]
n = len(s)
dp = [ [0]*13 for i in range(n) ]
if sr[0]=='?':
    for j in range(10):
        dp[0][j] = 1
else:
    j = int(sr[0])
    dp[0][j] = 1

for i in range(1,n):
    r = rem[i%6]
    if sr[i]=='?':
        for j in range(10):
            for k in range(13):
                dp[i][(k+j*r)%13] = (dp[i][(k+j*r)%13] + dp[i-1][k])%R
    else:
        j = int(sr[i])
        for k in range(13):
                dp[i][(k+j*r)%13] = (dp[i][(k+j*r)%13] + dp[i-1][k])%R

print((dp[n-1][5]))
# Original solution
s = list(input().rstrip())
n = len(s)
dp = [[0] * 13 for _ in range(n + 1)]
dp[0][0] = 1

for i in range(n):
    c = -1 if s[i] == '?' else int(s[i])
    for j in range(10):
        if c != -1 and c != j:
            continue
        for ki in range(13):
            dp[i + 1][(ki * 10 + j) % 13] += dp[i][ki]

print((dp[n][5] % (10**9 + 7)))


# Optimized solution
s = list(input().rstrip())
n = len(s)
dp = [[0] * 13 for _ in range(n + 1)]
dp[0][0] = 1

for i in range(n):
    c = -1 if s[i] == '?' else int(s[i])
    for j in range(10):
        if c != -1 and c != j:
            continue
        for ki in range(13):
            dp[i + 1][(ki * 10 + j) % 13] += dp[i][ki]
        for j in range(13):
            dp[i + 1][j] %= 10 ** 9 + 7
print((dp[n][5]))
# Original solution
from sys import exit, stderr, stdin
input = stdin.readline
# setrecursionlimit(10**7)


# def debug(var, name="hoge"):
#     print(name +":" + str(type(var)) + " = " + repr(var), file=stderr)
#     return


def main():
    MOD = 10**9 + 7
    S = list(input()[:-1])
    L = len(S)
    modsum = 0
    # 余り
    memo_prev = [0 for _ in range(13)]
    memo_prev[0] = 1
    memo = [0 for _ in range(13)]

    for i in range(L):
        memo = [0 for _ in range(13)]
        # 数字なら以前までの余りにたす
        if S[i].isnumeric():
            for m in range(13):
                cur = (10*m+int(S[i]))%13
                memo[cur] += memo_prev[m]
        # ?なら1~10の余りのケース全てをためす
        else:
            for n in range(10):
                for m in range(13):
                    cur = (10*m+n)%13
                    memo[cur] += memo_prev[m]
                    memo[cur] %= MOD
        memo_prev = memo.copy()
    print((memo[5]))


if __name__ == "__main__":
    main()


# Optimized solution
from sys import exit, stderr, stdin
input = stdin.readline


def main():
    MOD = 10**9 + 7
    S = input()[:-1]
    L = len(S)
    # 余り
    memo = [0 for _ in range(13)]
    memo[0] = 1

    for i in range(L):
        memo_prev = [x for x in memo]
        memo = [0 for _ in range(13)]
        # 数字なら以前までの余りにたす
        if S[i].isnumeric():
            n = int(S[i])
            for m in range(13):
                cur = (10*m+n)%13
                memo[cur] += memo_prev[m]
        # ?なら1~10の余りのケース全てをためす
        else:
            for n in range(10):
                for m in range(13):
                    cur = (10*m+n)%13
                    memo[cur] += memo_prev[m]
            for m in range(13):
                memo[m] %= MOD
    print((memo[5]))


if __name__ == "__main__":
    main()
# Original solution
mod=10**9+7
s=input()[::-1]
l=len(s)
dp=[[0]*13 for i in range(l+1)]
dp[0][0]=1
for i in range(l):
    s_sub=s[i]
    if s_sub=="?":
        for j in range(13):
            for k in range(10):
                dp[i+1][(j+k*(10**i))%13]+=dp[i][j]
                dp[i+1][(j+k*(10**i))%13]%=mod
    else:
        k=int(s_sub)
        for j in range(13):
            dp[i+1][(j+k*(10**i))%13]+=dp[i][j]
            dp[i+1][(j+k*(10**i))%13]%=mod
print((dp[l][5]%mod))


# Optimized solution
mod=10**9+7
s=input()[::-1]
l=len(s)
dp=[[0]*13 for i in range(l+1)]
dp[0][0]=1
#累乗が大きすぎるので前計算
p=[0]*l
p[0]=1
for i in range(l-1):
    p[i+1]=(p[i]*10)%13
for i in range(l):
    s_sub=s[i]
    if s_sub=="?":
        for j in range(13):
            for k in range(10):
                dp[i+1][(j+k*p[i])%13]+=dp[i][j]
                dp[i+1][(j+k*p[i])%13]%=mod
    else:
        k=int(s_sub)
        for j in range(13):
            dp[i+1][(j+k*p[i])%13]+=dp[i][j]
            dp[i+1][(j+k*p[i])%13]%=mod
print((dp[l][5]))
# Original solution
n=int(eval(input()));a,b,c,p=1,1,n,n-1
for i in range(n-1):
 p+=a-1;a,b,c=b,c,((n-1)**2+p+c)%(10**9+7)
print(c)

# Optimized solution
n=int(eval(input()))-1;a,b,c,p=1,1,n+1,n
for _ in[0]*n:p+=a-1;a,b,c=b,c,(n*n+p+c)%(10**9+7)
print(c)
# Original solution
for _ in range(int(eval(input()))):
    p,q=list(map(int,input().split()))
    c=0
    for i in range(143):
        for j in range(143):
            if (i>0 or j>0)and(j*p+i*q)%(j*j+i*i)==0 and (j*q-i*p)%(j*j+i*i)==0:c+=1
    print(('P' if c<5 else 'C'))

# Optimized solution
for _ in range(int(eval(input()))):
    p,q=list(map(int,input().split()))
    c=0
    for i in range(142):
        for j in range(142):
            if (i>0 or j>0)and(j*p+i*q)%(j*j+i*i)==0 and (j*q-i*p)%(j*j+i*i)==0:c+=1
    print(('P' if c<5 else 'C'))
# Original solution
import sys
import itertools
# import numpy as np
import time
import math
 
sys.setrecursionlimit(10 ** 7)
 
from collections import defaultdict
 
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
 
 
from functools import reduce
# from math import *
from fractions import *
H, W = list(map(int, readline().split()))
S = [0 for i in range(H)]
for i in range(H):
    S[i] = readline().decode().strip()

from collections import deque
def bfs(start, H, W):
    visited = [False] * (H * W)
    q = deque([])
    q.append((start[0], start[1], 0))
    max_dist = 0
    while q:
        (i, j, dist) = q.popleft()
        max_dist = max(dist, max_dist)
        visited[i * W + j] = True 
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                if dx * dy != 0 or dx == dy:
                    continue
                if i + dy < 0 or i + dy >= H or j + dx < 0 or j + dx >= W:
                    continue
                if S[i + dy][j + dx] == '#':
                    continue
                if visited[(i + dy) * W + j + dx]:
                    continue
                q.append((i + dy, j + dx, dist + 1))
    return max_dist

ans = 0
for i in range(H):
    for j in range(W):
        if S[i][j] == '#':
            continue
        start = (i, j)
        ans = max(ans, bfs(start, H, W))
print(ans)


# Optimized solution
import sys
import itertools
# import numpy as np
import time
import math
 
sys.setrecursionlimit(10 ** 7)
 
from collections import defaultdict
 
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
 
 
from functools import reduce
# from math import *
from fractions import *
H, W = list(map(int, readline().split()))
S = [0 for i in range(H)]
for i in range(H):
    S[i] = readline().decode().strip()

from collections import deque
def bfs(start, H, W):
    INF = 10 ** 9
    dist = [INF] * (H * W)
    q = deque([start])
    dist[start[0] * W + start[1]] = 0
    while q:
        (i, j) = q.popleft()
        d = dist[i * W + j]
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                if dx * dy != 0:
                    continue
                if dx == dy:
                    continue
                if i + dy < 0 or i + dy >= H or j + dx < 0 or j + dx >= W:
                    continue
                if S[i + dy][j + dx] == '#':
                    continue
                if dist[(i + dy) * W + j + dx] != INF:
                    continue
                dist[(i + dy) * W + j + dx] = d + 1
                q.append((i + dy, j + dx))
    return max(x for x in dist if x < INF)

ans = 0
for i in range(H):
    for j in range(W):
        if S[i][j] == '#':
            continue
        start = (i, j)
        ans = max(ans, bfs(start, H, W))
print(ans)
# Original solution
import sys
import itertools
# import numpy as np
import time
import math
 
sys.setrecursionlimit(10 ** 7)
 
from collections import defaultdict
 
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
 
 
from functools import reduce
# from math import *
from fractions import *
H, W = list(map(int, readline().split()))
S = [0 for i in range(H)]
for i in range(H):
    S[i] = readline().decode().strip()

from collections import deque
def bfs(start, H, W):
    INF = 10 ** 9
    visited = [False] * (H * W)
    q = deque([(start[0], start[1], 0)])
    max_d = 0
    while q:
        (i, j, d) = q.popleft()
        max_d = max(max_d, d)
        visited[i * W + j] = True
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                if dx * dy != 0:
                    continue
                if dx == dy:
                    continue
                if i + dy < 0 or i + dy >= H or j + dx < 0 or j + dx >= W:
                    continue
                if S[i + dy][j + dx] == '#':
                    continue
                if visited[(i + dy) * W + j + dx]:
                    continue
                q.append((i + dy, j + dx, d + 1))
    return max_d

ans = 0
for i in range(H):
    for j in range(W):
        if S[i][j] == '#':
            continue
        start = (i, j)
        ans = max(ans, bfs(start, H, W))
print(ans)


# Optimized solution
import sys
import itertools
# import numpy as np
import time
import math
 
sys.setrecursionlimit(10 ** 7)
 
from collections import defaultdict
 
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
 
 
from functools import reduce
# from math import *
from fractions import *
H, W = list(map(int, readline().split()))
S = [0 for i in range(H)]
for i in range(H):
    S[i] = readline().decode().strip()
 
from collections import deque
def bfs(start, H, W):
    INF = 10 ** 9
    dist = [INF] * (H * W)
    q = deque([start])
    dist[start[0] * W + start[1]] = 0
    max_d = 0
    while q:
        (i, j) = q.popleft()
        d = dist[i * W + j]
        max_d = max(d, max_d)
        for dy in range(-1, 2):
            for dx in range(-1, 2):
                if dx * dy != 0:
                    continue
                if dx == dy:
                    continue
                if i + dy < 0 or i + dy >= H or j + dx < 0 or j + dx >= W:
                    continue
                if S[i + dy][j + dx] == '#':
                    continue
                if dist[(i + dy) * W + j + dx] != INF:
                    continue
                dist[(i + dy) * W + j + dx] = d + 1
                q.append((i + dy, j + dx))
    return max_d
 
ans = 0
for i in range(H):
    for j in range(W):
        if S[i][j] == '#':
            continue
        start = (i, j)
        ans = max(ans, bfs(start, H, W))
print(ans)
# Original solution
from itertools import product


def solve(string):
    h, w, *s = string.split()
    h, w = list(map(int, [h, w]))
    s = ["#" * (w + 2)] + ["#" + _s + "#" for _s in s] + ["#" * (w + 2)]
    ans = 0
    d = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    for _h, _w in product(list(range(1, h + 1)), list(range(1, w + 1))):
        if s[_h][_w] == "#":
            continue
        q = list()
        for x, y in d:
            if s[_h + x][_w + y] == ".":
                q.append((_h + x, _w + y, _h, _w))
        if len(q) > 2:
            continue
        c = [[h * w] * (w + 2) for _ in range(h + 2)]
        c[_h][_w] = 0
        while q:
            cx, cy, px, py = q.pop()
            if c[px][py] + 1 >= c[cx][cy]:
                continue
            c[cx][cy] = c[px][py] + 1
            for x, y in d:
                if s[cx + x][cy + y] == ".":
                    q.append((cx + x, cy + y, cx, cy))
        ans = max(
            ans,
            *(c[i][j] * (s[i][j] == ".") for i, j in product(list(range(1, h + 1)), list(range(1, w + 1)))))
    return str(ans)


if __name__ == '__main__':
    import sys
    print((solve(sys.stdin.read().strip())))


# Optimized solution
from itertools import product


def solve(string):
    h, w, *s = string.split()
    h, w = list(map(int, [h, w]))
    s = ["#" * (w + 2)] + ["#" + _s + "#" for _s in s] + ["#" * (w + 2)]
    ans = 0
    d = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    for _h, _w in product(list(range(1, h + 1)), list(range(1, w + 1))):
        if s[_h][_w] == "#":
            continue
        q = list()
        for x, y in d:
            if s[_h + x][_w + y] == ".":
                q.append((_h + x, _w + y, _h, _w))
        if len(q) > 2:
            continue
        c = [[h * w] * (w + 2) for _ in range(h + 2)]
        c[_h][_w] = 0
        while q:
            cx, cy, px, py = q.pop()
            if c[px][py] + 1 >= c[cx][cy]:
                continue
            c[cx][cy] = c[px][py] + 1
            for x, y in d:
                if s[cx + x][cy + y] == ".":
                    q.append((cx + x, cy + y, cx, cy))
        for i, j in product(list(range(1, h + 1)), list(range(1, w + 1))):
            ans = max(ans, c[i][j] * (s[i][j] == "."))
    return str(ans)


if __name__ == '__main__':
    import sys
    print((solve(sys.stdin.read().strip())))
# Original solution
# D - Maze Master
from collections import deque, defaultdict

INF = 1 << 30
MOD = 10 ** 9 + 7
dxy = [(-1, 0), (0, -1), (0, 1), (1, 0)]


def bfs(sx: int, sy: int):
    queue = deque([(sx, sy)])
    dist = defaultdict(lambda: INF)
    dist[sx * MOD + sy] = 0
    while queue:
        x, y = queue.popleft()
        for dx, dy in dxy:
            nx, ny = x + dx, y + dy
            if S[nx][ny] == "." and dist[x * MOD + y] + 1 < dist[nx * MOD + ny]:
                dist[nx * MOD + ny] = dist[x * MOD + y] + 1
                queue.append((nx, ny))
    return max(dist.values())


def main():
    global S
    H, W, *S = open(0).read().split()
    H, W = int(H) + 2, int(W) + 2
    S = ["#" * W] + ["#" + s + "#" for s in S] + ["#" * W]  # put sentinels
    ans = max(bfs(i, j) for i, s in enumerate(S) for j, c in enumerate(s) if c == ".")
    print(ans)


if __name__ == "__main__":
    main()


# Optimized solution
# D - Maze Master
from collections import deque, defaultdict

INF = 1 << 30
MOD = 10 ** 9 + 7
dxy = [(-1, 0), (0, -1), (0, 1), (1, 0)]


def bfs(sx: int, sy: int):
    queue = deque([(sx, sy)])
    dist = defaultdict(lambda: INF)
    dist[sx * MOD + sy] = 0
    while queue:
        x, y = queue.popleft()
        for dx, dy in dxy:
            nx, ny = x + dx, y + dy
            if S[nx][ny] == ".":
                if nx * MOD + ny not in dist:
                    dist[nx * MOD + ny] = dist[x * MOD + y] + 1
                    queue.append((nx, ny))
    return max(dist.values())


def main():
    global S
    H, W, *S = open(0).read().split()
    H, W = int(H) + 2, int(W) + 2
    S = ["#" * W] + ["#" + s + "#" for s in S] + ["#" * W]  # put sentinels
    ans = max(bfs(i, j) for i, s in enumerate(S) for j, c in enumerate(s) if c == ".")
    print(ans)


if __name__ == "__main__":
    main()
# Original solution
# D - Maze Master
from collections import deque

MOD = 10 ** 9 + 7
dxy = [(-1, 0), (0, -1), (0, 1), (1, 0)]


def bfs(sx: int, sy: int):
    queue = deque([(sx, sy)])
    dist = {sx * MOD + sy: 0}
    while queue:
        x, y = queue.popleft()
        for dx, dy in dxy:
            nx, ny = x + dx, y + dy
            if S[nx][ny] == ".":
                if nx * MOD + ny not in dist:
                    dist[nx * MOD + ny] = dist[x * MOD + y] + 1
                    queue.append((nx, ny))
    return max(dist.values())


def main():
    global S
    H, W, *S = open(0).read().split()
    H, W = int(H) + 2, int(W) + 2
    S = ["#" * W] + ["#" + s + "#" for s in S] + ["#" * W]  # put sentinels
    ans = max(bfs(i, j) for i, s in enumerate(S) for j, c in enumerate(s) if c == ".")
    print(ans)


if __name__ == "__main__":
    main()


# Optimized solution
# D - Maze Master
from collections import deque


def bfs(start: int):
    queue = deque([start])
    dist = {start: 0}
    while queue:
        x = queue.popleft()
        for nx in (x + 1, x - 1, x + W, x - W):
            if maze[nx] and nx not in dist:
                dist[nx] = dist[x] + 1
                queue.append(nx)
    return max(dist.values())


def main():
    global H, W, maze
    H, W, *S = open(0).read().split()
    H, W = int(H) + 2, int(W) + 2
    maze = [0] * W  # flatten S and put sentinels
    for s in S:
        maze += [0] + [c == "." for c in s] + [0]
    maze += [0] * W
    ans = max(bfs(i) for i, x in enumerate(maze) if x)
    print(ans)


if __name__ == "__main__":
    main()
# Original solution
# D - Maze Master
from collections import deque


def bfs(start: int):
    queue = deque([start])
    dist = {start: 0}
    while queue:
        x = queue.popleft()
        for nx in (x + 1, x - 1, x + W, x - W):
            if maze[nx] == "." and nx not in dist:
                dist[nx] = dist[x] + 1
                queue.append(nx)
    return max(dist.values())


def main():
    global W, maze
    H, W = list(map(int, input().split()))
    H, W = H + 2, W + 2
    maze = "#" * W
    for _ in range(H - 2):
        maze += "#" + input().rstrip() + "#"
    maze += "#" * W
    ans = max(bfs(i) for i, x in enumerate(maze) if x == ".")
    print(ans)


if __name__ == "__main__":
    main()


# Optimized solution
# D - Maze Master
from collections import deque


def bfs(start: int):
    queue = deque([start])
    dist = [0] * (H * W)
    dist[start] = 1
    while queue:
        x = queue.popleft()
        for nx in (x + 1, x - 1, x + W, x - W):
            if maze[nx] == "." and not dist[nx]:
                dist[nx] = dist[x] + 1
                queue.append(nx)
    return max(dist) - 1


def main():
    global H, W, maze
    H, W = list(map(int, input().split()))
    H, W = H + 2, W + 2
    maze = "#" * W
    for _ in range(H - 2):
        maze += "#" + input().rstrip() + "#"
    maze += "#" * W
    ans = max(bfs(i) for i, c in enumerate(maze) if c == ".")
    print(ans)


if __name__ == "__main__":
    main()