#include <bits/stdc++.h>
using namespace std;

//define
#define int long long
#define UNIQUE(v) v.erase(unique(all(v)), v.end());
#define ZIP(v) sort(all(v)),UNIQUE(v)
#define ADD(a, b) a = (a + b) % mod
#define SUB(a, b) a = (a+mod-b)%mod
#define MUL(a, b) a = (a * b) % mod
#define repi(i,m,n) for(int i = m;i < n;i++)
#define drep(i,n,m) for(int i = n;i >= m;i--)
#define rep(i,n) repi(i,0,n)
#define rrep(i,n) repi(i,1,n+1)
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define all(v) v.begin(),v.end()
#define rall(v) v.rbegin(), v.rend()
#define dmp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define fi first
#define se second

//template
template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p){
  os << p.first << " " << p.second;return os;
}
template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v){
  for (auto it = v.begin();it != v.end();++it){
    if (it != v.begin())os << " ";os << *it;
  }return os;
}
template<typename T, int SIZE>
int array_length(const T (&)[SIZE]){return SIZE;}
template<typename T, int N>
void print(const T (&a)[N], int s = N, int t = -1, bool f = true){
	if(t == -1){rep(i,s){if(i)cout << " ";cout << a[i];}}
	else repi(i,s,t){if(i!=s)cout << " ";cout << a[i];}
	if(f)cout << "\n";
}
template<typename T, int N1, int N2>
void print(const T (&a)[N1][N2], int h = N1, int w = N2){
	rep(i,h){rep(j,w){cout << a[i][j] << " \n"[j==w-1];}}
}

//typedef
typedef pair<int,int> P;
typedef pair<int, P> PP;
typedef pair<P, int> Pi;
typedef vector<int> vi;
typedef deque<int> dq;
const int inf = 1e9+7;
const int INF = 1e18+7;




class UnionFind{
public:
	vector<int> ran, par;
	void init(int n){
		for(int i = 0;i < n;i++){
			par.push_back(i);
			ran.push_back(0);
		}
	}
	
	int find(int x){
		if(par[x] == x)return x;
		return par[x] = find(par[x]);
	}
	
	void unite(int x, int y){
		x = find(par[x]);
		y = find(par[y]);
		if(x == y)return;
		if(ran[x] < ran[y]){
			par[x] = y;
		}else{
			par[y] = x;
			if(par[x] == par[y])ran[x]++;
		}
	}
	
	bool same(int x, int y){
		return find(par[x]) == find(par[y]);
	}
};

template <typename T>class Box;
template <typename T>ostream& operator<<(ostream &, const Box<T> &);
template<typename T>class Box{
public:
	T top;
  T back, left, right, head;
  T bottom;
	T a[6];
	void init(T TOP, T BACK, T LEFT, T RIGHT, T HEAD, T BOTTOM){
		top = TOP;back = BACK;left = LEFT;
		right = RIGHT;head = HEAD;bottom = BOTTOM;
		a[0] = top;a[1] = back;a[2] = left;
		a[3] = right;a[4] = head;a[5] = bottom;
	}
	friend ostream &operator<<<T>(ostream &os, const Box &B);
	bool operator==(const Box& b) const {
		return(top    == b.top   &&
					 back   == b.back  &&
					 left   == b.left  &&
					 right  == b.right &&
					 head   == b.head  &&
					 bottom == b.bottom);
	}
	void rotate(T &d1, T &d2, T &d3, T &d4){
		T tmp = d1;
		d1 = d2;d2 = d3;d3 = d4;
		d4 = tmp;
	}
	void rotate_forward(){rotate(top, head, bottom, back);}
	void rotate_right(){rotate(top, left, bottom, right);}
	void rotate_spin(){rotate(head, right, back, left);}
	friend ostream & operator<< <>(ostream &, const Box<T> & B);
};
template <typename T>
ostream & operator<<(ostream & os, const Box<T> & B){
	os <<  "  " 				<< B.back   << endl;
	os << B.left << " " << B.bottom << " " << B.right << " " << B.top << endl;
	os <<  "  " 				<< B.head   << endl;
	return os;
}

bool same(Box<string> a, Box<string> b){
	rep(i,4){
		a.rotate_forward();
		rep(j,4){
			a.rotate_right();
			rep(k,4){
				a.rotate_spin();
				if(a == b)return true;
			}
		}
	}
	return false;
}

signed main(){
	while(1){
		int n;
		scanf("%lld", &n);
		if(n == 0)break;
		Box<string> B[n];
		UnionFind uf;uf.init(n);
		rep(i,n){
			string str[6];
			rep(j,6)cin >> str[j];
			B[i].init(str[5], str[4], str[3], str[2], str[1], str[0]);
		}
		int ans = 0;
		rep(i,n)rep(j,n){
			if(same(B[i], B[j]))uf.unite(i, j);
		}
		rep(i,n)ans += (uf.find(i) == i);
		printf("%lld\n", n-ans);
	}
	return 0;
}







Measured memory_bytes: 3180