CodeEff/ECCO huggingface dataset:
# Original solution
class UnionFind:
    def __init__(self, n):
        self.n = n
        self.par = [-1 for _ in range(n)]
        #マイナスが根を表す
        #数字はグループのノード数（サイズ）を表す
        #初期状態では、全てのノードが根で、サイズは1
 
    def same(self, x, y):
        return self.root(x)==self.root(y)
 
    def root(self, x):
        if self.par[x]<0:
            return x
        self.par[x] = self.root(self.par[x])
        #再帰的に根を求め、根に直接繋いで高速化（辺の縮約）
        return self.par[x]
 
    def unite(self,x,y):
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return
 
        if self.par[x] > self.par[y]:
            x,y = y,x
            #木のバランスに偏りが生じると計算量が増えるので、
            #サイズが小さいグループを大きいグループの下に繋げる
 
        self.par[x] += self.par[y]
        #下に繋ぐグループのサイズを上のグループに加算
        self.par[y] = x
        #親を更新
 
    def size(self,x):
        return -self.par[self.root(x)]

n, m = list(map(int, input().split()))
ab = [list(map(int, input().split())) for _ in range(m)]

ab.reverse()
uf = UnionFind(n)

res = []
tmp = n * (n - 1) // 2
#全く繋がっていない状態からスタート（逆算していく方が簡単）
for a,b in ab:
    res.append(tmp)
    a -= 1
    b -= 1
    if uf.same(a,b):
        continue
 
    sa = uf.size(a)
    sb = uf.size(b)
    tmp -= sa * sb
    #aとbを繋げることで、aグループのサイズ * bグループのサイズの島の組が新たに行き来可能となる
    uf.unite(a,b)

res.reverse()
#本来の順番に戻す
for r in res:
    print(r)

# Optimized solution
n, m = list(map(int, input().split()))
AB = [[int(i) for i in input().split()] for i in range(m)]

class UnionFind:
    def __init__(self, n):
        self.n = n
        self.par = [-1 for _ in range(n)]
 
    def same(self, x, y):
        return self.root(x)==self.root(y)
 
    def root(self, x):
        if self.par[x]<0:
            return x
        self.par[x] = self.root(self.par[x])
        return self.par[x]
 
    def unite(self,x,y):
        x = self.root(x)
        y = self.root(y)
        if x == y:
            return
 
        if self.par[x] > self.par[y]:
            x,y = y,x
 
        self.par[x] += self.par[y]
        self.par[y] = x
 
    def size(self,x):
        return -self.par[self.root(x)]
    
uf = UnionFind(n)

C = []
tmp = n * (n - 1) // 2
for i in range(m - 1, -1, -1):
    C.append(tmp)
    a, b = AB[i]
    a -= 1
    b -= 1
    if uf.same(a, b):
        continue
    else:
        tmp -= uf.size(a) * uf.size(b)
        uf.unite(a, b)
    #print(C)
    
C.reverse()
for c in C:
    print(c)
# Original solution
N,M=list(map(int,input().split()))
AB=[[0,0] for i in range(M)]
for i in range(M):
    AB[i][0],AB[i][1]=list(map(int,input().split()))
par=[i for i in range(N+1)]
rank=[1 for i in range(N+1)]
def Union_Find_find(x):
    global par
    if par[x]==x:
        return x
    else:
        return Union_Find_find(par[x])
def Union_Find_unite(x,y):
    global par
    x=Union_Find_find(x)
    y=Union_Find_find(y)
    if x!=y:
        par[y]=x
        rank[x]=rank[x]+rank[y]
        rank[y]=1
        for p in range(len(par)):
            if par[p]==y:
                par[p]=x
def Union_Find_same(x,y):
    global par
    return Union_Find_find(x)==Union_Find_find(y)

def ncr(n):
    return n*(n-1)//2
res=[]
res.append(ncr(N))
for i in reversed(list(range(M))):
    A,B=AB[i][0],AB[i][1]
    if res[-1]!=0:
        if not(Union_Find_same(A,B)):
            res.append(res[-1]-rank[par[A]]*rank[par[B]])
            Union_Find_unite(A,B)
        else:
            res.append(res[-1])
    if res[-1]==0:
        res.append(0)
for i in reversed(list(range(M))):
    print((res[i]))


# Optimized solution
N,M=list(map(int,input().split()))
AB=[[0,0] for i in range(M)]
for i in range(M):
    AB[i][0],AB[i][1]=list(map(int,input().split()))
par=[i for i in range(N+1)]
rank=[1 for i in range(N+1)]
hight=[1 for i in range(N+1)]
def Union_Find_find(x):
    global par,rank,hight
    if par[x]==x:
        return x
    else:
        return Union_Find_find(par[x])
def Union_Find_unite(x,y):
    global par,rank,hight
    x=Union_Find_find(x)
    y=Union_Find_find(y)
    if x!=y:
        if hight[x]>hight[y]:
            par[y]=x
            rank[x]=rank[x]+rank[y]
            rank[y]=rank[x]
        else:
            par[x]=y
            rank[x]=rank[x]+rank[y]
            rank[y]=rank[x]
            if hight[x]==hight[y]:
                hight[y]+=1
def Union_Find_same(x,y):
    global par,rank,hight
    return Union_Find_find(x)==Union_Find_find(y)
def ncr(n):
    return n*(n-1)//2
res=[]
res.append(ncr(N))
for i in reversed(list(range(M))):
    A,B=AB[i][0],AB[i][1]
    if res[-1]!=0:
        if Union_Find_same(A,B):
            res.append(res[-1])
        else:
            res.append(res[-1]-rank[Union_Find_find(A)]*rank[Union_Find_find(B)])
            Union_Find_unite(A,B)
    else:
        res.append(0)
for i in reversed(list(range(M))):
    print((res[i]))
# Original solution
import sys
sys.setrecursionlimit(99999)

def find_index_by_value(a, val):
    for i, items in enumerate(a):
        if val in items:
            return i
    return -1


def num_reachable(n):
    return n * (n - 1) // 2


n, m = list(map(int, input().split()))
edges = []

for _ in range(m):
    a, b = list(map(int, input().split()))
    edges.append((a, b))

size = [1 for _ in range(n + 1)]
group = [i for i in range(n + 1)]

find_group = lambda x: x if x == group[x] else find_group(group[x])

ans = []
not_reachable = n * (n - 1) // 2
reachable_node = []
ans.append(not_reachable)

count = not_reachable
reachable = 0
for _ in range(m - 1):
    a, b = edges.pop()
    if count > 0:
        ra = find_group(a)
        rb = find_group(b)
        if rb != ra:
            s_ra = size[ra]
            s_rb = size[rb]
            new_size = s_ra + s_rb
            reachable += num_reachable(new_size) - num_reachable(s_ra) - num_reachable(s_rb)
            size[ra] = new_size
            group[rb] = ra
        count = not_reachable - reachable
    ans.append(count)

for _ in range(len(ans)):
    print((ans.pop()))




# Optimized solution
def find_index_by_value(a, val):
    for i, items in enumerate(a):
        if val in items:
            return i
    return -1


def num_reachable(n):
    return n * (n - 1) // 2


n, m = list(map(int, input().split()))
edges = []

for _ in range(m):
    a, b = list(map(int, input().split()))
    edges.append((a, b))

size = [1 for _ in range(n + 1)]
group = [i for i in range(n + 1)]


def find_group(x):
    c = []
    p = x
    while True:
        pp = group[p]
        if pp == p:
            break
        else:
            c.append(p)
            p = pp
    for i in c:
        group[i] = pp
    return pp

# find_group = lambda x: x if x == group[x] else find_group(group[x])

ans = []
not_reachable = n * (n - 1) // 2
reachable_node = []
ans.append(not_reachable)

count = not_reachable
reachable = 0
for _ in range(m - 1):
    a, b = edges.pop()
    if count > 0:
        ra = find_group(a)
        rb = find_group(b)
        if rb != ra:
            s_ra = size[ra]
            s_rb = size[rb]
            new_size = s_ra + s_rb
            reachable += num_reachable(new_size) - num_reachable(s_ra) - num_reachable(s_rb)
            size[ra] = new_size
            group[rb] = ra
        count = not_reachable - reachable
    ans.append(count)

for _ in range(len(ans)):
    print((ans.pop()))
# Original solution
import sys
input = sys.stdin.readline

def comb(n,r):
    r = min(r,n-r)
    result = 1
    for i in range(n-r+1,n+1):
        result *= i
    for i in range(1,r+1):
        result //= i
    return result

class Unionfind:

    __slots__ = ['nodes']

    def __init__(self, n):
        self.nodes = [-1]*n

    def root(self, x):
        if self.nodes[x] < 0:
            return x
        else:
            root_x = self.root(self.nodes[x])
            self.nodes[x] = root_x
            return root_x

    def unite(self, x, y):
        x = self.root(x); y = self.root(y)
        if x == y:
            return
        rank_x = -self.nodes[x]; rank_y = -self.nodes[y]
        if rank_x < rank_y:
            x, y = y, x
        self.nodes[x] += self.nodes[y]
        self.nodes[y] = x

    def same(self, x, y):
        return self.root(x) == self.root(y)

    def rank(self, x):
        return -self.nodes[self.root(x)]

N,M = list(map(int,input().split()))
info = [list(map(int,input().split())) for i in range(M)]
uf = Unionfind(N)
ans_list = [comb(N,2)]
ans = comb(N,2)
for A,B in info[:0:-1]:
    A -= 1; B -= 1
    if not uf.same(A,B):
        ans -= uf.rank(A) * uf.rank(B)
    uf.unite(A,B)
    ans_list.append(ans)
 
for e in ans_list[::-1]:
    print(e)

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

# 組み合わせ　n_C_r
def comb(n,r):
    r = min(r,n-r)
    result = 1
    for i in range(n-r+1,n+1):
        result *= i
    for i in range(1,r+1):
        result //= i
    return result

class Unionfind:

    __slots__ = ['nodes','size']

    def __init__(self, n):
        self.nodes = list(range(n))
        self.size = [1]*n

    def root(self, x):
        if self.nodes[x] == x:
            return x
        else:
            root_x = self.root(self.nodes[x])
            self.nodes[x] = root_x
            return root_x

    def unite(self, x, y):
        x = self.root(x); y = self.root(y)
        if x == y:
            return
        if self.size[x] < self.size[y]:
            x, y = y, x
        self.size[x] += self.size[y]
        self.nodes[y] = x

    def same(self, x, y):
        return self.root(x) == self.root(y)

N,M = list(map(int,input().split()))
info = [[int(e)-1 for e in input().split()] for _ in range(M)]

uf = Unionfind(N)
out = []
ans = comb(N,2)
out.append(ans)
for A,B in info[::-1]:
    if not uf.same(A,B):
        ans -= uf.size[uf.root(A)] * uf.size[uf.root(B)]
    uf.unite(A,B)
    out.append(ans)

for q in out[-2::-1]:
    print(q)
# Original solution
from sys import stdin
def input():
    return stdin.readline()[:-1]
#おまじない。

n,m=list(map(int,input().split()))
AB=[list(map(int,input().split())) for i in range(m)]
from itertools import combinations
#union-find召喚
par=[-1]*n
def find(x):
    if par[x]<0:
        return x
    else:
        par[x]=find(par[x])
        return par[x] #ここ覚えていなかった
def unite(x,y):
    x=find(x)
    y=find(y)
    if x==y:
        False
    else:
        if par[x]>par[y]:#sizeの大きいほうがxにしたい
            x,y=y,x
        par[x]+=par[y]
        par[y]=x
        return True
def same(x,y):
    return find(x)==find(y)
def size(x):
    return -par[find(x)]
comb=list(combinations(list(range(n)),2))
ans=[]

for i in range(m):
    count=0
    num=m-i-1
    unite(AB[num][0]-1,AB[num][1]-1)
    for kumiawase in comb:
        if same(kumiawase[0],kumiawase[1]):
            count+=1
    ans.append(count)
ans=list(reversed(ans))
for i in range(len(ans)-1):
    print((ans[0]-ans[i+1]))
print((ans[0]))

# Optimized solution
n, m = map(int, input().split())

par = [-1] * (n + 1)


def find(x):
    if par[x] < 0:
        return x
    else:
        par[x] = find(par[x])
        return par[x]


def size(x):
    X = find(x)
    return -par[X]


def unite(x, y):
    if find(x) == find(y):
        return False
    X = find(x)
    Y = find(y)
    if size(X) < size(Y):
        x, y = y, x
        X = find(x)
        Y = find(y)
    par[X] += par[Y]
    par[Y] = X
    return True


def is_same(x, y):
    return find(x) == find(y)


def calc(a):
    return a * (a - 1) // 2


goukei = calc(n)
ans = [-1] * (m + 1)
ans[-1] = calc(n)
cnt = 0
AB = [list(map(int, input().split())) for _ in range(m)]
for i in range(m - 1, -1, -1):
    a, b = AB[i]
    if is_same(a, b):
        ans[i] = goukei - cnt
    else:
        A = size(a)
        B = size(b)
        cnt += calc(A + B) - calc(A) - calc(B)
        unite(a, b)
        ans[i] = goukei - cnt
print(*ans[1::], sep="\n")
# Original solution
class UF_tree:
    def __init__(self, n):
        self.root = [-1] * (n + 1)  # -1ならそのノードが根,で絶対値が木の要素数
        self.rank = [0] * (n + 1)

    def find(self, x):  # xの根となる要素番号を返す
        if self.root[x] < 0:
            return x
        else:
            self.root[x] = self.find(self.root[x])
            return self.root[x]

    def isSame(self, x, y):
        return self.find(x) == self.find(y)

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        elif self.rank[x] < self.rank[y]:
            self.root[y] += self.root[x]
            self.root[x] = y
        else:
            self.root[x] += self.root[y]
            self.root[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

    def getNodeLen(self, x):
        return -self.root[self.find(x)]


n, m = map(int, input().split())
bridge = [list(map(int, input().split())) for _ in range(m)]
bridge = bridge[::-1]

uf = UF_tree(n)
ans = [0] * (m + 1)
ans[0] = n * (n - 1) // 2

for i in range(m):
    x, y = bridge[i]
    if uf.isSame(x, y):
        ans[i + 1] = ans[i]
        continue

    tmp = uf.getNodeLen(x) * uf.getNodeLen(y)
    uf.unite(x, y)
    ans[i + 1] = ans[i] - tmp

ans = ans[::-1][1:]
print(*ans, sep="\n")


# Optimized solution
import sys
input = sys.stdin.buffer.readline
sys.setrecursionlimit(10 ** 7)


class UF_tree:
    def __init__(self, n):
        self.root = [-1] * (n + 1)  # -1ならそのノードが根,で絶対値が木の要素数
        self.rank = [0] * (n + 1)

    def find(self, x):  # xの根となる要素番号を返す
        if self.root[x] < 0:
            return x
        else:
            self.root[x] = self.find(self.root[x])
            return self.root[x]

    def isSame(self, x, y):
        return self.find(x) == self.find(y)

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        elif self.rank[x] < self.rank[y]:
            self.root[y] += self.root[x]
            self.root[x] = y
        else:
            self.root[x] += self.root[y]
            self.root[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1

    def getNodeLen(self, x):
        return -self.root[self.find(x)]


if __name__ == "__main__":
    N, M = map(int, input().split())
    AB = tuple(tuple(map(int, input().split())) for _ in range(M))
    score = N * (N - 1) // 2

    ans = [score]
    uf = UF_tree(N)
    for a, b in AB[::-1]:
        if uf.isSame(a, b):
            ans.append(score)
            continue
        x = uf.getNodeLen(a)
        y = uf.getNodeLen(b)
        uf.unite(a, b)
        score -= x * y
        ans.append(score)
    ans.reverse()
    print(*ans[1:], sep="\n")
# Original solution
S = input()[:: -1]
mod = 10 ** 9 + 7
dp = [[0 for _ in range(13)] for _ in range(len(S) + 1)]

if S[0] == "?":
    for k in range(10):
        dp[1][k % 13] += 1
else:
    dp[1][int(S[0]) % 13] += 1

tmp = 1
for i in range(2, len(S) + 1):
    tmp *= 10 
    for j in range(13):
        if dp[i - 1][j] > 0:
            if S[i - 1] == "?":
                for k in range(10):
                    dp[i][(tmp * k + j) % 13] += dp[i - 1][j]
            else:
                dp[i][(tmp * int(S[i - 1]) + j) % 13] += dp[i - 1][j]

print((dp[len(S)][5] % mod))

# Optimized solution
S = input()[:: -1]
mod = 10 ** 9 + 7
dp = [[0 for _ in range(13)] for _ in range(len(S) + 1)]

if S[0] == "?":
    for k in range(10):
        dp[1][k % 13] += 1
else:
    dp[1][int(S[0]) % 13] += 1

tmp = 1
for i in range(2, len(S) + 1):
    tmp *= 10
    tmp %= 13
    for j in range(13):
        if dp[i - 1][j] > 0:
            if S[i - 1] == "?":
                for k in range(10):
                    dp[i][(tmp * k + j) % 13] += dp[i - 1][j] % mod
            else:
                dp[i][(tmp * int(S[i - 1]) + j) % 13] += dp[i - 1][j] % mod

print((dp[len(S)][5] % mod))
# Original solution
import sys

mod = 10**9 + 7
S = sys.stdin.readline().strip()

S = S[::-1]
ls = len(S)
dp = [0] * 13
dp[0] = 1
for i in range(ls):
    ndp = [0] * 13
    # print("S", S[i])
    for j in range(13):
        if S[i] == "?":
            for k in range(10):
                r = k * pow(10, i, 13) + j
                r %= 13
                ndp[r] += dp[j]
                ndp[r] %= mod

        else:
            n = int(S[i])
            r = n * pow(10, i, 13) + j
            r %= 13
            ndp[r] += dp[j]
            ndp[r] %= mod

    # print(ndp)
    dp = ndp

print((dp[5]))

# Optimized solution
import sys

mod = 10**9 + 7
S = sys.stdin.readline().strip()

S = S[::-1]
ls = len(S)
dp = [0] * 13
dp[0] = 1
for i in range(ls):
    ndp = [0] * 13
    # print("S", S[i])
    for j in range(13):
        if dp[j] == 0:
            continue
        digit = pow(10, i, 13)
        if S[i] == "?":
            for k in range(10):
                r = k * digit + j
                r %= 13
                ndp[r] += dp[j]
                ndp[r] %= mod

        else:
            n = int(S[i])
            r = n * digit + j
            r %= 13
            ndp[r] += dp[j]
            ndp[r] %= mod

    # print(ndp)
    dp = ndp

print((dp[5]))
# Original solution
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10**7)
from collections import Counter, deque
#from collections import defaultdict
from itertools import combinations, permutations, accumulate, groupby, product
from bisect import bisect_left,bisect_right
from heapq import heapify, heappop, heappush
from math import floor, ceil,pi
#from operator import itemgetter
def I(): return int(eval(input()))
def MI(): return list(map(int, input().split()))
def LI(): return list(map(int, input().split()))
def LI2(): return [int(eval(input())) for i in range(n)]
def MXI(): return [LI()for i in range(n)]
inf = 10**17
mod = 10**9 + 7

s=input().rstrip()
l=len(s)
dp=[[0 for i in range(13)] for i in  range(l)]
#dp[0]=[1 for i in range(13)]
i=0
u=s[0]
if u!="?":
    k=(int(u)*10**(l-1))%13
    dp[0][k]+=1
else:
    for g in range(10):
        k=(g*10**(l-1))%13
        dp[0][k]+=1
#print(dp)
for i in range(l-1):
    u=s[i+1]
    t=(10**(l-i-2))%13
    for j in range(13):
        if u!="?":
            k=(j+int(u)*t)%13
            dp[i+1][k]+=dp[i][j]
        
        else:
            for g in range(10):
                k=(j+g*t)%13
                dp[i+1][k]+=dp[i][j]
    
                
            
#print(dp)
print((dp[l-1][5]%mod))
        

# Optimized solution
import sys,math,copy

def main():
    # import numpy as np
    input = sys.stdin.readline
    S = ''.join(reversed(input().strip()))

    # dp = np.zeros((13), dtype=int)
    # dp_ = np.zeros((13), dtype=int)
    dp = [0] * 13
    dp_ = [0] * 13
    mod13_list = [i % 13 for i in range(12 ** 2 + 1)]
    list10 = list(range(10))
    list13 = list(range(13))
    divisor = 10 ** 9 + 7
    dp_[0] = 1
    mul = 1
    for i in range(len(S)):
        s = S[i]
        if s == '?':
            for d in list10:
                m = mod13_list[(d * mul)]
                for pm in list13:
                    dp[mod13_list[(pm+m)]] += dp_[pm]

        else:
            si = int(s)
            m = mod13_list[(si * mul)]
            for pm in list13:
                dp[mod13_list[(pm+m)]] = dp_[pm]

        # dp_ = dp % divisor
        # dp = dp * 0 # np.zeros((13), dtype=int)
        for j in list13:
            dp_[j] = dp[j] % divisor
            dp[j] = 0
        mul = mod13_list[(mul * 10)]
    print((dp_[5]))

if __name__ == '__main__':
    main()
# Original solution

mod = 10 ** 9 + 7
S = input()[::-1]
W = [1, 10, 9, 12, 3, 4]

dp = [[0] * 13 for _ in range(len(S))]

for i, s in enumerate(S):
    if i == 0:
        if s == "?":
            for j in range(10):
                dp[0][j] = 1
        else:
            dp[0][int(s)] = 1
        continue

    if s == "?":
        for n in range(10):
            r = (n * W[i % 6]) % 13
            for j in range(13):
                dp[i][(j + r) % 13] = (dp[i][(j + r) % 13] + dp[i - 1][j]) % mod

    else:
        n = int(s)
        r = (n * W[i % 6]) % 13
        for j in range(13):
            dp[i][(j + r) % 13] = (dp[i][(j + r) % 13] + dp[i - 1][j]) % mod

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


# Optimized solution

mod = 10 ** 9 + 7
S = input()[::-1]
W = [1, 10, 9, 12, 3, 4]

dp = [[0] * 13 for _ in range(len(S))]

for i, s in enumerate(S):
    if i == 0:
        if s == "?":
            for j in range(10):
                dp[0][j] = 1
        else:
            dp[0][int(s)] = 1
        continue

    w = W[i % 6]
    if s == "?":
        for n in range(10):
            r = (n * w) % 13
            for j in range(13):
                dp[i][(j + r) % 13] = (dp[i][(j + r) % 13] + dp[i - 1][j]) % mod

    else:
        n = int(s)
        r = (n * w) % 13
        for j in range(13):
            dp[i][(j + r) % 13] = (dp[i][(j + r) % 13] + dp[i - 1][j]) % mod

print((dp[len(S) - 1][5]))
# Original solution
# import sys


# fin = sys.stdin.readline
MOD = 10 ** 9 + 7
S = input()[::-1]
dp = [[0] * 13 for _ in range(len(S) + 1)]
dp[0][0] = 1
for i, c in enumerate(S, start=1):
    base = 10 ** (i - 1) % 13
    if c != '?':
        d = int(c) * base % 13
        for r in range(13):
            c = (d + r) % 13
            dp[i][c] += dp[i - 1][r]
            dp[i][c] %= MOD
    else:
        for d in range(10):
            d = d * base % 13
            for r in range(13):
                c = (d + r) % 13
                dp[i][c] += dp[i - 1][r]
                dp[i][c] %= MOD
print((dp[-1][5]))


# Optimized solution
# import sys


# fin = sys.stdin.readline
MOD = 10 ** 9 + 7
S = input()[::-1]
dp = [[0] * 13 for _ in range(len(S) + 1)]
dp[0][0] = 1
for i, c in enumerate(S, start=1):
    base = pow(10, i - 1, 13)
    if c != '?':
        d = int(c) * base % 13
        for r in range(13):
            c = (d + r) % 13
            dp[i][c] += dp[i - 1][r]
            dp[i][c] %= MOD
    else:
        for d in range(10):
            d = d * base % 13
            for r in range(13):
                c = (d + r) % 13
                dp[i][c] += dp[i - 1][r]
                dp[i][c] %= MOD
print((dp[-1][5]))
# Original solution
# import sys


# fin = sys.stdin.readline
MOD = 10 ** 9 + 7
S = input()[::-1]
dp = [[0] * 13 for _ in range(len(S) + 1)]
dp[0][0] = 1
base = 1
for i, c in enumerate(S, start=1):
    if c != '?':
        d = int(c) * base % 13
        for r in range(13):
            c = (d + r) % 13
            dp[i][c] += dp[i - 1][r]
            dp[i][c] %= MOD
    else:
        for d in range(10):
            d = d * base % 13
            for r in range(13):
                c = (d + r) % 13
                dp[i][c] += dp[i - 1][r]
                dp[i][c] %= MOD
    base = base * 10 % 13
print((dp[-1][5]))


# Optimized solution
import sys


fin = sys.stdin.readline
MOD = 10 ** 9 + 7
S = fin().rstrip("\n")[::-1]
dp = [[0] * 13 for _ in range(len(S) + 1)]
dp[0][0] = 1
base = 1
for i, c in enumerate(S, start=1):
    if c != '?':
        d = int(c) * base % 13
        for r in range(13):
            c = (d + r) % 13
            dp[i][c] += dp[i - 1][r]
            dp[i][c] %= MOD
    else:
        for d in range(10):
            d = d * base % 13
            for r in range(13):
                c = (d + r) % 13
                dp[i][c] += dp[i - 1][r]
                dp[i][c] %= MOD
    base = base * 10 % 13
print((dp[-1][5]))
# Original solution
# standart input
# n = int(input())
# a = list(map(int, input().split()))

N = 13
MOD = 10 ** 9 + 7

s = input()[::-1]

dp = [0 for i in range(N)]
nextdp = [0 for i in range(N)]
zeros = [0 for i in range(N)]
dp[0] = 1

for i, si in enumerate(s):
    nextdp = zeros[:]
    r = 10 ** i % N

    for j in range(10):
        jj = j
        if si == "?":
            pass
            # c = (j * 10 ** i) % N
        elif j == 0:
            jj = int(si)
        else:
            break

        for k in range(N):
            l = (k + r * jj) % N
            nextdp[l] = (nextdp[l] + dp[k]) % MOD

    dp = nextdp[:]

print((dp[5]))


# Optimized solution
# standart input
# n = int(input())
# a = list(map(int, input().split()))

N = 13
MOD = 10 ** 9 + 7

s = input()[::-1]

dp = [0 for i in range(N)]
nextdp = [0 for i in range(N)]
zeros = [0 for i in range(N)]
dp[0] = 1

r = 1
for i, si in enumerate(s):
    nextdp = zeros[:]

    for j in range(10):
        jj = j
        if si == "?":
            pass
            # c = (j * 10 ** i) % N
        elif j == 0:
            jj = int(si)
        else:
            break

        for k in range(N):
            l = (k + r * jj) % N
            nextdp[l] = (nextdp[l] + dp[k]) % MOD

    dp = nextdp
    r = r * 10 % N

print((dp[5]))