#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

enum Loc{
	Top,
	Right,
	Under,
	Left,
};

enum Roll{
	r_0,
	r_90,
	r_180,
	r_270,
};

Roll roll_type[4] = {r_0,r_90,r_180,r_270};

struct Data{
	int data_id;
	Roll roll;
};

struct Info{
	int next_loc;
	bool check[9];
	Data table[3][3];
};

void copyInfo(Info from,Info& to){
	for(int i = 0; i < 9; i++)to.check[i] = from.check[i];
	for(int i = 0; i < 3; i++){
		for(int k = 0; k < 3; k++){
			to.table[i][k].data_id = from.table[i][k].data_id;
			to.table[i][k].roll = from.table[i][k].roll;
		}
	}
}

int N,ans;
char data[9][4];

bool isMatch(char left,char right){

	if(left > right){
		swap(left,right);
	}

	if(left == 'R' && right == 'r'){
		return true;
	}else if(left == 'G' && right == 'g'){
		return true;
	}else if(left == 'B' && right == 'b'){
		return true;
	}else if(left == 'W' && right == 'w'){
		return true;
	}

	return false;
}

char getWord(int data_id,Roll roll,Loc loc){

	switch(roll){
	case r_0:
		switch(loc){
		case Top:
			return data[data_id][Top];
		case Right:
			return data[data_id][Right];
		case Under:
			return data[data_id][Under];
		case Left:
			return data[data_id][Left];
		}
		break;
	case r_90:
		switch(loc){
		case Top:
			return data[data_id][Left];
		case Right:
			return data[data_id][Top];
		case Under:
			return data[data_id][Right];
		case Left:
			return data[data_id][Under];
		}
		break;
	case r_180:
		switch(loc){
		case Top:
			return data[data_id][Under];
		case Right:
			return data[data_id][Left];
		case Under:
			return data[data_id][Top];
		case Left:
			return data[data_id][Right];
		}
		break;
	case r_270:
		switch(loc){
		case Top:
			return data[data_id][Right];
		case Right:
			return data[data_id][Under];
		case Under:
			return data[data_id][Left];
		case Left:
			return data[data_id][Top];
		}
		break;
	}
	return 'X'; //must not reach here
}


void recursive(Info info){

	if(info.next_loc == 9){
		ans++;
		return;
	}

	for(int i = 0; i < 9; i++){
		if(info.check[i] == false){

			switch(info.next_loc){
			case 1:
				for(int k = 0; k < 4; k++){
					if(isMatch(data[info.table[1][1].data_id][Top],getWord(i,roll_type[k],Under))){
						Info new_info;
						copyInfo(info,new_info);
						new_info.check[i] = true;
						new_info.table[0][1].data_id = i;
						new_info.table[0][1].roll = roll_type[k];
						new_info.next_loc = info.next_loc+1;
						recursive(new_info);
					}
				}
				break;
			case 2:
				for(int k = 0; k < 4; k++){
					if(isMatch(data[info.table[1][1].data_id][Right],getWord(i,roll_type[k],Left))){
						Info new_info;
						copyInfo(info,new_info);
						new_info.check[i] = true;
						new_info.table[1][2].data_id = i;
						new_info.table[1][2].roll = roll_type[k];
						new_info.next_loc = info.next_loc+1;
						recursive(new_info);
					}
				}
				break;
			case 3:
				for(int k = 0; k < 4; k++){
					if(isMatch(data[info.table[1][1].data_id][Under],getWord(i,roll_type[k],Top))){
						Info new_info;
						copyInfo(info,new_info);
						new_info.check[i] = true;
						new_info.table[2][1].data_id = i;
						new_info.table[2][1].roll = roll_type[k];
						new_info.next_loc = info.next_loc+1;
						recursive(new_info);
					}
				}
				break;
			case 4:
				for(int k = 0; k < 4; k++){
					if(isMatch(data[info.table[1][1].data_id][Left],getWord(i,roll_type[k],Right))){
						Info new_info;
						copyInfo(info,new_info);
						new_info.check[i] = true;
						new_info.table[1][0].data_id = i;
						new_info.table[1][0].roll = roll_type[k];
						new_info.next_loc = info.next_loc+1;
						recursive(new_info);
					}
				}
				break;
			case 5:
				for(int k = 0; k < 4; k++){
					if(isMatch(getWord(info.table[0][1].data_id,info.table[0][1].roll,Right),getWord(i,roll_type[k],Left)) == true &&
							isMatch(getWord(info.table[1][2].data_id,info.table[1][2].roll,Top),getWord(i,roll_type[k],Under)) == true){
						Info new_info;
						copyInfo(info,new_info);
						new_info.check[i] = true;
						new_info.table[0][2].data_id = i;
						new_info.table[0][2].roll = roll_type[k];
						new_info.next_loc = info.next_loc+1;
						recursive(new_info);
					}
				}
				break;
			case 6:
				for(int k = 0; k < 4; k++){
					if(isMatch(getWord(info.table[1][2].data_id,info.table[1][2].roll,Under),getWord(i,roll_type[k],Top)) == true &&
							isMatch(getWord(info.table[2][1].data_id,info.table[2][1].roll,Right),getWord(i,roll_type[k],Left)) == true){
						Info new_info;
						copyInfo(info,new_info);
						new_info.check[i] = true;
						new_info.table[2][2].data_id = i;
						new_info.table[2][2].roll = roll_type[k];
						new_info.next_loc = info.next_loc+1;
						recursive(new_info);
					}
				}
				break;
			case 7:
				for(int k = 0; k < 4; k++){
					if(isMatch(getWord(info.table[2][1].data_id,info.table[2][1].roll,Left),getWord(i,roll_type[k],Right)) == true &&
							isMatch(getWord(info.table[1][0].data_id,info.table[1][0].roll,Under),getWord(i,roll_type[k],Top)) == true){
						Info new_info;
						copyInfo(info,new_info);
						new_info.check[i] = true;
						new_info.table[2][0].data_id = i;
						new_info.table[2][0].roll = roll_type[k];
						new_info.next_loc = info.next_loc+1;
						recursive(new_info);
					}
				}
				break;
			case 8:
				for(int k = 0; k < 4; k++){
					if(isMatch(getWord(info.table[1][0].data_id,info.table[1][0].roll,Top),getWord(i,roll_type[k],Under)) == true &&
							isMatch(getWord(info.table[0][1].data_id,info.table[0][1].roll,Left),getWord(i,roll_type[k],Right)) == true){
						Info new_info;
						copyInfo(info,new_info);
						new_info.check[i] = true;
						new_info.table[0][0].data_id = i;
						new_info.table[0][0].roll = roll_type[k];
						new_info.next_loc = info.next_loc+1;
						recursive(new_info);
					}
				}
				break;
			}
		}
	}

}

void func(){

	ans = 0;

	char buf[5];

	for(int i = 0; i < 9; i++){
		scanf("%s",buf);

		for(int k = 0; k < 4; k++){
			data[i][k] = buf[k];
		}
	}

	for(int i = 0; i < 9; i++){
		Info info;
		for(int k = 0; k < 9; k++)info.check[k] = false;
		info.table[1][1].data_id = i;
		info.table[1][1].roll = r_0;
		info.check[i] = true;
		info.next_loc = 1;
		recursive(info);
	}

	printf("%d\n",ans*4);
}

int main(){

	scanf("%d",&N);
	for(int i = 0; i < N; i++){
		func();
	}

	return 0;
}

Measured memory_bytes: 2700