After a hard-working week Polycarp prefers to have fun. Polycarp's favorite entertainment is drawing snakes. He takes a rectangular checkered sheet of paper of size $n \times m$ (where $n$ is the number of rows, $m$ is the number of columns) and starts to draw snakes in cells.

Polycarp draws snakes with lowercase Latin letters. He always draws the first snake with the symbol 'a', the second snake with the symbol 'b', the third snake with the symbol 'c' and so on. All snakes have their own unique symbol. There are only $26$ letters in the Latin alphabet, Polycarp is very tired and he doesn't want to invent new symbols, so the total number of drawn snakes doesn't exceed $26$.

Since by the end of the week Polycarp is very tired, he draws snakes as straight lines without bends. So each snake is positioned either vertically or horizontally. Width of any snake equals $1$, i.e. each snake has size either $1 \times l$ or $l \times 1$, where $l$ is snake's length. Note that snakes can't bend.

When Polycarp draws a new snake, he can use already occupied cells for drawing the snake. In this situation, he draws the snake "over the top" and overwrites the previous value in the cell.

Recently when Polycarp was at work he found a checkered sheet of paper with Latin letters. He wants to know if it is possible to get this sheet of paper from an empty sheet by drawing some snakes according to the rules described above. If it is possible, he is interested in a way to draw snakes.


-----Input-----

The first line of the input contains one integer $t$ ($1 \le t \le 10^5$) — the number of test cases to solve. Then $t$ test cases follow.

The first line of the test case description contains two integers $n$, $m$ ($1 \le n,m \le 2000$) — length and width of the checkered sheet of paper respectively.

Next $n$ lines of test case description contain $m$ symbols, which are responsible for the content of the corresponding cell on the sheet. It can be either lowercase Latin letter or symbol dot ('.'), which stands for an empty cell.

It is guaranteed that the total area of all sheets in one test doesn't exceed $4\cdot10^6$.


-----Output-----

Print the answer for each test case in the input.

In the first line of the output for a test case print YES if it is possible to draw snakes, so that you can get a sheet of paper from the input. If it is impossible, print NO.

If the answer to this question is positive, then print the way to draw snakes in the following format. In the next line print one integer $k$ ($0 \le k \le 26$) — number of snakes. Then print $k$ lines, in each line print four integers $r_{1,i}$, $c_{1,i}$, $r_{2,i}$ and $c_{2,i}$ — coordinates of extreme cells for the $i$-th snake ($1 \le r_{1,i}, r_{2,i} \le n$, $1 \le c_{1,i}, c_{2,i} \le m$). Snakes should be printed in order of their drawing. If there are multiple solutions, you are allowed to print any of them.

Note that Polycarp starts drawing of snakes with an empty sheet of paper.


-----Examples-----
Input
1
5 6
...a..
..bbb.
...a..
.cccc.
...a..

Output
YES
3
1 4 5 4
2 3 2 5
4 2 4 5

Input
3
3 3
...
...
...
4 4
..c.
adda
bbcb
....
3 5
..b..
aaaaa
..b..

Output
YES
0
YES
4
2 1 2 4
3 1 3 4
1 3 3 3
2 2 2 3
NO

Input
2
3 3
...
.a.
...
2 2
bb
cc

Output
YES
1
2 2 2 2
YES
3
1 1 1 2
1 1 1 2
2 1 2 2

Difficulty: interview

Starter code:

Solutions:
import sys
input = sys.stdin.readline

testcases=int(input())

for testcase in range(testcases):
    n,m=list(map(int,input().split()))
    MAP=[input().strip() for i in range(n)]
    #print(MAP)

    STR=[[] for i in range(26)]

    for i in range(n):
        for j in range(m):
            if MAP[i][j]!=".":
                STR[ord(MAP[i][j])-97].append([i,j])

    #print(STR)

    for s in range(25,-1,-1):
        if STR[s]==[]:
            continue
        
        x,y=STR[s][0]
        z,w=STR[s][-1]
        flag=1
        
        if x==z:
            for k in range(y,w+1):
                if MAP[x][k]>=chr(s+97):
                    continue
                else:
                    flag=0
                    break
                
            for u,v in STR[s]:
                if u==x:
                    continue
                else:
                    flag=0
                    break

        elif y==w:
            for k in range(x,z+1):
                if MAP[k][y]>=chr(s+97):
                    continue
                else:
                    flag=0
                    break
                
            for u,v in STR[s]:
                if v==y:
                    continue
                else:
                    flag=0
                    break

        else:
            flag=0

        if flag==0:
            print("NO")
            break
    else:
        print("YES")

        for s in range(25,-1,-1):
            if STR[s]!=[]:
                ANS=s+1
                ANONE=STR[s][0]
                print(ANS)
                break
        else:
            print(0)
            continue

        for ans in range(ANS):
            if STR[ans]!=[]:
                print(STR[ans][0][0]+1,STR[ans][0][1]+1,STR[ans][-1][0]+1,STR[ans][-1][1]+1)
            else:
                print(ANONE[0]+1,ANONE[1]+1,ANONE[0]+1,ANONE[1]+1)

        

            
                
            
            

        
            


import sys
input = sys.stdin.readline

T = int(input())
for _ in range(T):
    N, M = list(map(int, input().split()))
    mar = [-1] * 26
    mir = [2000] * 26
    mac = [-1] * 26
    mic = [2000] * 26
    
    X = [[-1 if a == "." else ord(a)-97 for a in input()] for i in range(N)]
    R = [[a+1 for a in range(M)] for _ in range(N)]
    D = [[i+1]*M for i in range(N)]
    
    # print(X)
    ma = -1
    for i in range(N):
        for j in range(M):
            k = X[i][j]
            if k >= 0:
                mar[k] = max(mar[k], i)
                mir[k] = min(mir[k], i)
                mac[k] = max(mac[k], j)
                mic[k] = min(mic[k], j)
                ma = max(ma, k)
    f = 0
    ans = 1
    ANS = []
    for k in range(ma+1)[::-1]:
        if f and mar[k] == -1 and mir[k] == 2000:
            ANS.append(ANS[-1])
        elif mar[k] == mir[k]:
            r = mar[k]
            c = mic[k]
            while c <= mac[k]:
                if X[r][c] < k:
                    ans = 0
                    break
                c = R[r][c]
            else:
                ANS.append((r+1, mic[k]+1, r+1, mac[k]+1))
            R[r][mic[k]] = mac[k] + 1
            if ans == 0:
                break
            f = 1
        elif mac[k] == mic[k]:
            c = mac[k]
            r = mir[k]
            while r <= mar[k]:
                if X[r][c] < k:
                    ans = 0
                    break
                r = D[r][c]
            else:
                ANS.append((mir[k]+1, c+1, mar[k]+1, c+1))
            D[mir[k]][c] = mar[k] + 1
            if ans == 0:
                break
            f = 1
        else:
            ans = 0
            break
    if ans == 0:
        print("NO")
    else:
        print("YES")
        print(len(ANS))
        for a in ANS[::-1]:
            print(*a)


import sys
input = sys.stdin.readline
T = int(input())
for _ in range(T):
    N, M = map(int, input().split())
    mar = [-1] * 26
    mir = [2000] * 26
    mac = [-1] * 26
    mic = [2000] * 26
    
    X = [[-1 if a == "." else ord(a)-97 for a in input()] for i in range(N)]
    # print(X)
    ma = -1
    for i in range(N):
        for j in range(M):
            k = X[i][j]
            if k >= 0:
                mar[k] = max(mar[k], i)
                mir[k] = min(mir[k], i)
                mac[k] = max(mac[k], j)
                mic[k] = min(mic[k], j)
                ma = max(ma, k)
    f = 0
    ans = 1
    ANS = []
    for k in range(ma+1)[::-1]:
        if f and mar[k] == -1 and mir[k] == 2000:
            ANS.append(ANS[-1])
        elif mar[k] == mir[k]:
            r = mar[k]
            for c in range(mic[k], mac[k]+1):
                if X[r][c] < k:
                    ans = 0
                    break
            else:
                ANS.append((r+1, mic[k]+1, r+1, mac[k]+1))
            if ans == 0:
                break
            f = 1
        elif mac[k] == mic[k]:
            c = mac[k]
            for r in range(mir[k], mar[k]+1):
                if X[r][c] < k:
                    ans = 0
                    break
            else:
                ANS.append((mir[k]+1, c+1, mar[k]+1, c+1))
            if ans == 0:
                break
            f = 1
        else:
            ans = 0
            break
    if ans == 0:
        print("NO")
    else:
        print("YES")
        print(len(ANS))
        for a in ANS[::-1]:
            print(*a)

import sys
input = iter(sys.stdin.read().splitlines()).__next__

from collections import defaultdict as di

def solve():
    n,m = map(int,input().split())
    B = [input() for _ in range(n)]

    pos = di(list)
    for i in range(n):
        b = B[i]
        for j in range(m):
            pos[b[j]].append((i,j))
    if '.' in pos:
        del pos['.']

    C = [list('.'*m) for _ in range(n)]
    moves = []

    if pos:
        mxx = max(pos)
        for i in range(97,ord(mxx)+1):
            c = chr(i)
            if c not in pos:
                pos[c] = pos[mxx]
            P = pos[c]
            if all(p[0] == P[0][0] for p in P):
                mn = min(p[1] for p in P)
                mx = max(p[1] for p in P)
                i = P[0][0]
                for j in range(mn,mx+1):
                    C[i][j] = c
                moves.append((i+1,mn+1,i+1,mx+1))
            elif all(p[1] == P[0][1] for p in P):
                mn = min(p[0] for p in P)
                mx = max(p[0] for p in P)
                j = P[0][1]
                for i in range(mn,mx+1):
                    C[i][j] = c
                moves.append((mn+1,j+1,mx+1,j+1))
    
    if [''.join(s) for s in C] == B:
        print('YES')
        print(len(moves))
        for m in moves:
            print(*m)
    else:
        print('NO')

def main():
    t = int(input())

    for _ in range(t):
        solve()
main()

import sys
def solve():
    H, W = map(int, sys.stdin.readline().split())
    G = [[ord(s) - 46 for s in sys.stdin.readline().strip()] for _ in range(H)]
    k = 0
    inf = 10**9
    Stbw = [-inf]*77
    Stsw = [inf]*77
    Stbh = [-inf]*77
    Stsh = [inf]*77
    for h, G1 in enumerate(G, 1):
        k = max(k, max(G1))
        for w, g in enumerate(G1, 1):
            if not g:
                continue
            Stbw[g] = max(Stbw[g], w)
            Stsw[g] = min(Stsw[g], w)
            Stbh[g] = max(Stbh[g], h)
            Stsh[g] = min(Stsh[g], h)
    if k == 0:
        return []
    A = []
    for j in range(k, 50, -1):
        if Stbw[j] == -inf and Stbh[j] == -inf:
            A.append(A[-1])
            continue
        bw = (Stbw[j] == Stsw[j])
        bh = (Stbh[j] == Stsh[j])
        if not bw and not bh:
            return False
        if bw:
            w = Stbw[j]- 1
            for h in range(Stsh[j]-1, Stbh[j]):
                if G[h][w] < j:
                    return False
        elif bh:
            h = Stbh[j]- 1
            for w in range(Stsw[j]-1, Stbw[j]):
                if G[h][w] < j:
                    return False
        A.append((Stsh[j], Stsw[j], Stbh[j], Stbw[j]))
    
    return A[::-1]
    
def __starting_point():
    T = int(input())
    for _ in range(T):
        ans = solve()
        if ans is False:
            print('NO')
            continue
        print('YES')
        print(len(ans))
        for a in ans:
            print(*a)
__starting_point()

import sys
input = sys.stdin.readline

def solve():
    H, W = map(int, input().split())
    G = [[ord(s) - 46 for s in input().strip()] for _ in range(H)]
    Gy = list(map(list, zip(*G)))
    k = 0
    St = [None]*77
    for h, G1 in enumerate(G, 1):
        k = max(k, max(G1))
        for w, g in enumerate(G1, 1):
            if not g:
                continue
            if St[g] is None:
                St[g] = (h, w)
            elif type(St[g]) == tuple:
                h1, w1 = St[g]
                if h == h1:
                    St[g] = h
                elif w == w1:
                    St[g] = -w
                else:
                    return False
            else:
                if St[g] == h or St[g] == -w:
                    continue
                return False
    if k == 0:
        return []
    A = []
    for j in range(k, 50, -1):
        if St[j] is None:
            A.append(A[-1])
            continue
        if type(St[j]) == tuple:
            A.append(St[j]*2)
            continue
        x = St[j]
        if x > 0:
            Gh = G[x-1]
            p = None
            e = None
            for ig, g in enumerate(Gh):
                if g == j:
                    p = ig
                    break
            for ig, g in enumerate(Gh[::-1]):
                ig = W - 1 - ig
                if g == j:
                    e = ig
                    break
            for ig in range(p, e + 1):
                if Gh[ig] < j:
                    return False
            A.append((x, p+1, x, e+1))
        else:
            Gw = Gy[-x-1]
            p = None
            e = None
            for ig, g in enumerate(Gw):
                if g == j:
                    p = ig
                    break
            for ig, g in enumerate(Gw[::-1]):
                ig = H - 1 - ig
                if g == j:
                    e = ig
                    break
            for ig in range(p, e + 1):
                if Gw[ig] < j:
                    return False
            A.append((p+1, -x, e+1, -x))
    
    return A[::-1]
    
def __starting_point():
    T = int(input())
    for _ in range(T):
        ans = solve()
        if ans is False:
            print('NO')
            continue
        print('YES')
        print(len(ans))
        for a in ans:
            print(*a)
__starting_point()

import sys
input = sys.stdin.readline

T = int(input())
for _ in range(T):
    n, m = list(map(int, input().split()))
    minx = {}
    maxx = {}
    miny = {}
    maxy = {}
    matrix = []
    for i in range(n):
        matrix.append(list(input().strip()))
    for i in range(n):
        for j in range(m):
            if matrix[i][j]!='.':
                try:
                    minx[matrix[i][j]] = min(minx[matrix[i][j]], j)
                except: minx[matrix[i][j]] = j
                try:
                    maxx[matrix[i][j]] = max(maxx[matrix[i][j]], j)
                except: maxx[matrix[i][j]] = j
                try:
                    miny[matrix[i][j]] = min(miny[matrix[i][j]], i)
                except: miny[matrix[i][j]] = i
                try:
                    maxy[matrix[i][j]] = max(maxy[matrix[i][j]], i)
                except: maxy[matrix[i][j]] = i
    copy = []
    for i in range(n):
        copy.append([])
        for j in range(m):
            copy[-1].append('.')
    for char in range(ord('a'), ord('z')+1):
        char = chr(char)
        try:
            if minx[char]==maxx[char]:
                c = minx[char]
                for r in range(miny[char], maxy[char]+1):
                    copy[r][c] = char
            else:
                r = miny[char]
                for c in range(minx[char], maxx[char]+1):
                    copy[r][c] = char
        except: pass
    if matrix==copy:
        print("YES")
        cnt = -1
        for char in range(ord('z'), ord('a')-1, -1):
            char = chr(char)
            try:
                minx[char]+=0
                break
            except: pass
        else: cnt = 0
        if cnt!=0:
            cnt = ord(char)-ord('a')+1
        print(cnt)
        ans = []
        for char in range(ord('a'), ord('a')+cnt):
            char = chr(char)
            try:
                ans.append((miny[char], minx[char], maxy[char], maxx[char]))
            except: pass
        i = 0
        for char in range(ord('a'), ord('a')+cnt):
            char = chr(char)
            print(ans[i][0]+1, ans[i][1]+1, ans[i][2]+1, ans[i][3]+1)
            try: minx[char]+=0; i+=1
            except: pass
    else:
        print("NO")


import sys
#sys.stdin = open('inE', 'r')
t = int(input())
for ti in range(t):
    n,m = list(map(int, input().split()))
    a = []
    for i in range(n):
        a.append(input())
    top = {}
    bot = {}
    l = {}
    r = {}
    res = True
    for y in range(n):
        for x in range(m):
            c = a[y][x]
            if c != '.':
                if c not in top:
                    top[c] = y
                    bot[c] = y
                    l[c] = x
                    r[c] = x
                else:
                    if top[c] == y:
                        r[c] = x
                        xi = x - 1
                        while xi >= 0 and a[y][xi] != c:
                            if a[y][xi] == '.' or a[y][xi] < c:
                                res = False
                            xi -= 1
                    elif l[c] == x and r[c] == x:
                        bot[c] = y
                        yi = y - 1
                        while yi >= 0 and a[yi][x] != c:
                            if a[yi][x] == '.' or a[yi][x] < c:
                                res = False
                            yi -= 1
                    else:
                        res = False
    if len(top) == 0:
        sys.stdout.write('YES\n')
        sys.stdout.write('0\n')
    elif res:
        mxc = max(top)
        cnt = ord(mxc) & 31
        sys.stdout.write('YES\n')
        sys.stdout.write(str(cnt)+'\n')
        for i in range(cnt):
            ci = chr(ord('a') + i)
            if ci not in top:
                ci = mxc
            sys.stdout.write(f'{top[ci]+1} {l[ci]+1} {bot[ci]+1} {r[ci]+1}\n')
    else:
        sys.stdout.write('NO\n')


from heapq import heappush,heappop,heapify
from collections import deque,defaultdict,Counter
import itertools
from itertools import permutations,combinations,groupby
import sys
import bisect
import string
import math
import time
import random
def S_():
    return input()
def LS():
    return [i for i in input().split()]
def I():
    return int(input())
def MI():
    return map(int,input().split())
def LI():
    return [int(i) for i in input().split()]
def LI_():
    return [int(i)-1 for i in input().split()]
def NI(n):
    return [int(input()) for i in range(n)]
def NI_(n):
    return [int(input())-1 for i in range(n)]
def StoI():
    return [ord(i)-97 for i in input()]
def ItoS(nn):
    return chr(nn+97)
def LtoS(ls):
    return ''.join([chr(i+97) for i in ls])
def GI(V,E,Directed=False,index=0):
    org_inp=[]
    g=[[] for i in range(n)]
    for i in range(E):
        inp=LI()
        org_inp.append(inp)
        if index==0:
            inp[0]-=1
            inp[1]-=1
        if len(inp)==2:
            a,b=inp
            g[a].append(b)
            if not Directed:
                g[b].append(a)
        elif len(inp)==3:
            a,b,c=inp
            aa=(inp[0],inp[2])
            bb=(inp[1],inp[2])
            g[a].append(bb)
            if not Directed:
                g[b].append(aa)
    return g,org_inp
def bit_combination(k,n=2):
    rt=[]
    for tb in range(n**k):
        s=[tb//(n**bt)%n for bt in range(k)]
        rt+=[s]
    return rt
def show(*inp,end='\n'):
    if show_flg:
        print(*inp,end=end)
YN=['Yes','No']
mo=10**9+7
inf=float('inf')
l_alp=string.ascii_lowercase
u_alp=string.ascii_uppercase
ts=time.time()
sys.setrecursionlimit(10**5)
input=lambda: sys.stdin.readline().rstrip()

def ran_input():
    import random
    n=random.randint(4,16)
    rmin,rmax=1,10
    a=[random.randint(rmin,rmax) for _ in range(n)]
    return n,a

show_flg=False
show_flg=True

ans=0

t=I()
for _ in range(t):
    h,w=LI()
    ans=[]
    t=[]
    ng=False
    rs=[[inf,-inf] for i in range(26)]
    cs=[[inf,-inf] for i in range(26)]
    
    for i in range(h):
        s=input()
        t.append(s)
        for j in range(w):
            if s[j]!='.':
                k=ord(s[j])-97
                rs[k][0]=min(rs[k][0],i+1)
                rs[k][1]=max(rs[k][1],i+1)
                cs[k][0]=min(cs[k][0],j+1)
                cs[k][1]=max(cs[k][1],j+1)
    
    ll=-1
    for i in range(26):
        if rs[i][0]!=inf:
            ll=i
    if ll==-1:
        print('YES')
        print(0)
        continue
    for i in range(ll+1)[::-1]:
        if (rs[i][0]!=inf and rs[i][0]!=rs[i][1]) and (cs[i][0]!=inf and cs[i][0]!=cs[i][1]):
            ng=True
            break
        else:
            if rs[i][0]==inf:
                ans.append(lsn)
            else:
                lsn=[rs[i][0],cs[i][0],rs[i][1],cs[i][1]]
                ans.append(lsn)
                for r in range(rs[i][0],rs[i][1]+1):
                    for c in range(cs[i][0],cs[i][1]+1):
                        #show(i,(r-1,c-1),t[r-1][c-1])
                        if ord(t[r-1][c-1])-97<i:
                            ng=True
            #show(i,*rs[i],*cs[i])

    if ng:
        print('NO')
        continue
    else:
        print('YES')
        print(len(ans))
        for i in ans[::-1]:
            print(*i)