# 1258. 행렬찾기
# 행렬을 찾는 함수
def find(mtx, t):
# 행렬의 개수
mtx_cnt = 0
# r x c 정보를 추가하는 리스트
size_info = []
# 모든 좌표에서 검사한다.
for i in range(n):
for j in range(n):
# 이미 방문처리되거나 0인 좌표는 지나친다.
if mtx[i][j] == 'v' or mtx[i][j] == 0:
continue
# 행렬 발견
else:
# 행렬 개수 1개 추가
mtx_cnt += 1
# 행, 열 사이즈
row_size = 0
col_size = 0
for p in range(i, n):
for q in range(j, n):
if p == i:
if type(mtx[p][q]) == int:
if mtx[p][q] > 0:
# 방문처리
mtx[p][q] = 'v'
col_size += 1
# mtx[p][q] == 0
else:
break
else:
if type(mtx[p][q]) == int:
if mtx[p][q] > 0:
# 방문처리
mtx[p][q] = 'v'
else:
break
if mtx[p][j] == 'v':
row_size += 1
else:
break
# 행렬 사이즈 정보 추가
size_info.append((row_size * col_size, row_size, col_size))
# 행렬 사이즈 정렬(행렬 크기가 작은순서로 먼저 정렬 후, 크기가 같으면 행의 크기가 작은순서로 정렬)
size_info.sort(key = lambda x:(x[0],x[1]))
# 최종 답안 리스트
array = [mtx_cnt]
for info in size_info:
s, r, c = info
array.append(r)
array.append(c)
for i in range(len(array)):
array[i] = str(array[i])
ans1 = '#' + str(t) + ' '
ans2 = " ".join(array)
ans = ans1 + ans2
# 답안 출력
print(ans)
# 테스트 케이스 개수가 주어진다.
T = int(input())
# 테스트 케이스
for t in range(1, T+1):
# 행렬의 크기 n이 주어진다.
n = int(input())
# 행렬
matrix = []
for _ in range(n):
matrix.append(list(map(int, input().split())))
# 함수 실행
find(matrix, t)