#include<bits/stdc++.h>
using namespace std;
#define ll  long long
#define ull unsigned long long int
#define inf INT_MAX
#define SINF 1e18
#define pb push_back
#define mp make_pair
#define mod 1000000007
#define PI 3.1415926535897932384626433832795

/////////Quick Functions start////////////////////////////////
bool comp(int a, int b){
	return a>b;
}

int gcd(int a, int b){
	if (b == 0) return a;
	return gcd(b, a % b);
}

bool isPrime(int n){
    // 6k+i (i=-1,0,1,2,3....)
	if (n <= 1)return false; 
	if (n <= 3)return true; 
	if (n%2 == 0 || n%3 == 0) return false; 
	for (int i=5; i*i<=n; i=i+6) {
	    if (n%i == 0 || n%(i+2) == 0) 
	       {return false;}
	}
	return true; 
}

void primeFactors(int n){
	while (n % 2 == 0){cout << 2 << " ";n = n/2;}
	for (int i = 3; i <= sqrt(n); i = i + 2){
	    while (n % i == 0){  
	        cout << i << " ";
	        n = n/i;  
	    }  
	}   
	if (n > 2){cout << n << " ";} 
}

void printDivisors(int n){
	for (int i=1; i<=sqrt(n); i++) { 
	    if (n%i == 0){
	        if (n/i == i) 
	            printf("%d ", i); 
	        else
	            printf("%d %d ", i, n/i);
	    } 
	} 
} 

void BellmanFord(int graph[][3],int V,int E,int src) { 
	int dis[V]; 
	for(int i = 0; i < V; i++)dis[i]=INT_MAX; 
	dis[src] = 0; 
	for(int i = 0; i < V - 1; i++) { 
	    for (int j = 0; j < E; j++) { 
	        if (dis[graph[j][0]] + graph[j][2]<dis[graph[j][1]]) 
	            dis[graph[j][1]]=dis[graph[j][0]]+graph[j][2]; 
	    } 
	}bool flag=true;
	for(int i = 0; i < E; i++){ 
	    int x = graph[i][0],y = graph[i][1],weight = graph[i][2];
	    if (dis[x] != INT_MAX &&dis[x] + weight < dis[y]){flag=false;break;}
	}
	/* Check for negative cycle else return the required distance */
	// if(!flag){}
	// else{}
}

// stack<int> s; /*enable before using topo sort*/
void topoSort(int n,int m,vector<vector<bool>> &e, vector<bool> &visited,int x){
	visited[x]=true;
	for(int i=n-1;i>=0;i--){
	    if(e[x][i] and !visited[i]){
	        topoSort(n,m,e,visited,i);
	    }
	}
	// s.push(x); /*enable stack first*/
	return ;
}

void convertGraphToTree(int x,vector<vector<int>> &v,vector<bool> &visited,vector<vector<int>> &newedges){
	visited[x]=true;
	for(int i=0;i<v[x].size();i++){
		if(!visited[v[x][i]]){
			newedges[x].pb(v[x][i]);
			convertGraphToTree(v[x][i],v,visited,newedges);
		}
	}
	return;
}

int subtreeCount(int x,vector<vector<int>> &v,vector<bool> &visited,vector<int> &count){
	visited[x]=true;
	int ans=1;
	for(int i=0;i<v[x].size();i++){
		if(!visited[v[x][i]]){
			ans+=subtreeCount(v[x][i],v,visited,count);
		}
	}
	count[x]=ans;
	return ans;
}


void create_sparse_table(int n,vector<int> &v){
	// k=log2(n) -> n=size of the input array (for as large as 10^7, k is at max 25)
	int k=(int)log2(n*1.0);
	vector<vector<int>> st(n+1, vector<int> (k+1,0));
	for (int i = 0; i < n; i++)
		st[i][0] = v[i];

	for (int j = 1; j <= k; j++){
		for (int i = 0; i + (1 << j) <= n; i++)
			st[i][j] = min(st[i][j-1], st[i + (1 << (j - 1))][j - 1]);
	}
	return;
}

//////////////Quick Functions End/////////////////////////////

void helper(int n,vector<vector<int>> &a){
	vector<vector<vector<int>>> v(10,vector<vector<int>>(n,vector<int>()));
	vector<int> ans(10,-1);
	for(int k=0;k<=9;k++){
		int count=0;
		for(int i=0;i<n;i++){
			bool check=false;int y=-1;
			for(int j=0;j<n;j++){
				if(a[i][j]==k and !check){
					check=true;v[k][i].pb(j);
					count+=1;
				}
				else if(a[i][j]==k and check){
					y=j;
					count+=1;
				}
				// if(a[i][j]==k and k==0){cout<<i<<" "<<j<<endl;}
			}
			if(check and y!=-1){v[k][i].pb(y);}
		}
		// cout<<k<<" "<<count<<endl;
		if(count<2){ans[k]=0;}
	}
	for(int k=0;k<=9;k++){
		if(ans[k]!=-1){continue;}
		int area=0;
		for(int i=0;i<n;i++){
			for(int temp=0;temp<v[k][i].size();temp++){
				int x=i,y=v[k][i][temp];
				for(int j=0;j<n;j++){
					if(x==j){continue;}
					for(int p=0;p<v[k][j].size();p++){
						if(y==v[k][j][p]){area=max(area,abs(x-j)*max(abs(n-1-y),y));}
						else{
							area=max(area,abs(x-j)*abs(y-v[k][j][p]));
							area=max(area,abs(y-v[k][j][p])*max(abs(n-1-x),x));
							area=max(area,abs(y-v[k][j][p])*max(abs(n-1-j),j));
							area=max(area,abs(x-j)*max(abs(n-1-y),y));
							area=max(area,abs(x-j)*max(abs(n-1-v[k][j][p]),v[k][j][p]));
						}
					}
				}
			}
			if(v[k][i].size()==2){
				area=max(area,abs(v[k][i][0]-v[k][i][1])*max(i,abs(n-1-i)));
			}
		}
		ans[k]=area;
	}
	for(int i=0;i<=9;i++){
		cout<<ans[i]<<" ";
	}
	cout<<endl;
	return;
}

int main(){
	/////////////
	#ifndef ONLINE_JUDGE
	freopen("inputf.in","r",stdin);
	freopen("outputf.in","w",stdout);
	#endif
	/////////////
	ios_base::sync_with_stdio(false); 
    cin.tie(NULL);
    /////////////
	int t;
	cin>>t;
	while(t--){
		int n;cin>>n;
		vector<vector<int>> a(n,vector<int>(n,0));
		for(int i=0;i<n;i++){
			string s;cin>>s;
			for(int j=0;j<s.size();j++){
				a[i][j]=s[j]-'0';
			}
		}
		helper(n,a);
		// if(ans){cout<<"YES"<<endl;}
		// else{cout<<"NO"<<endl;}
	}
	return 0;
}
