#include<iostream>
#include<fstream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<cctype>
#include<cassert>
#include<cmath>
#include<ctime>
#include<cstdlib>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<iomanip>
#include<utility>
using namespace std;
#define mp make_pair
#define pb push_back
#define X first
#define Y second
#define rg register
#define il inline
#define lch(x) ((x)<<1)
#define rch(x) ((x)<<1^1)
#define eprintf(...) fprintf(stderr,__VA_ARGS__)
#define rep0(i,n) for(register int i=0;i<(n);++i)
#define per0(i,n) for(register int i=(n)-1;i>=0;--i)
#define rep(i,st,ed) for(register int i=(st);i<=(ed);++i)
#define per(i,ed,st) for(register int i=(ed);i>=(st);--i)
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef double dbl;
typedef long double ldb;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<pii,pii> sta;
template<typename T> il T qmin(const T &a,const T &b){return a<b?a:b;}
template<typename T> il T qmax(const T &a,const T &b){return a>b?a:b;}
template<typename T> il void getmin(T &a,const T &b){if(a>b) a=b;}
template<typename T> il void getmax(T &a,const T &b){if(a<b) a=b;}
il void fileio(string s){
	freopen((s+".in").c_str(),"r",stdin);
	freopen((s+".out").c_str(),"w",stdout);
}

const int inf=(int)1e9+7;
const ll linf=(ll)1e17+7;
const int N=405;

map<sta,int> cnt;
int a[N],b[N],c[N],d[N],n;
sta v[N][4];
ll ans;

il sta getsta(const int &a,const int &b,const int &c,const int &d){
	return mp(mp(a,b),mp(c,d));
}

il sta rev(const sta &a){
	return mp(mp(a.Y.Y,a.Y.X),mp(a.X.Y,a.X.X));
}

il bool same(const sta &a,const sta &b){
	if(a==b) return true;
	if(a==mp(mp(b.X.Y,b.Y.X),mp(b.Y.Y,b.X.X))) return true;
	if(a==mp(b.Y,b.X)) return true;
	if(a==mp(mp(b.Y.Y,b.X.X),mp(b.X.Y,b.Y.X))) return true;
	return false;
}

il ll P(int n,int k){
	ll ans=1;
	rep0(i,k) ans*=n-i;
	return ans;
}

int main(){
//	fileio("test");
	scanf("%d",&n);
	rep(i,1,n){
		scanf("%d%d%d%d",a+i,b+i,c+i,d+i);
		++cnt[v[i][0]=getsta(a[i],b[i],c[i],d[i])];
		++cnt[v[i][1]=getsta(b[i],c[i],d[i],a[i])];
		++cnt[v[i][2]=getsta(c[i],d[i],a[i],b[i])];
		++cnt[v[i][3]=getsta(d[i],a[i],b[i],c[i])];
	}
	rep(i,1,n){
		rep0(c,4) --cnt[v[i][c]];
		sta s1=v[i][0],s2;
		rep(j,i+1,n){
			rep0(c,4) --cnt[v[j][c]];
			rep0(c,4){
				s2=rev(v[j][c]);
				sta v[4]={getsta(s1.X.Y,s1.X.X,s2.X.X,s2.X.Y),getsta(s1.Y.X,s1.X.Y,s2.X.Y,s2.Y.X),getsta(s1.Y.Y,s1.Y.X,s2.Y.X,s2.Y.Y),getsta(s1.X.X,s1.Y.Y,s2.Y.Y,s2.X.X)};
				int num[4]={1,1,1,1};
				per(p1,3,1){
					per(p2,p1-1,0){
						if(!same(v[p2],v[p1])) continue;
						num[p2]+=num[p1];
						num[p1]=0;
						break;
					}
				}
				ll dt=1;
				rep0(p,4){
					if(!num[p]) continue;
					int t=cnt[v[p]];
					if(v[p].X==v[p].Y){
						if(v[p].X.X==v[p].X.Y){
							//0 0 0 0
							t/=4;
							if(t<num[p]){dt=0;break;}
							dt*=P(t,num[p])*(1ll<<2*num[p]);
						}else{
							//0 1 0 1
							t/=2;
							if(t<num[p]){dt=0;break;}
							dt*=P(t,num[p])*(1ll<<num[p]);
						}
					}else{
						if(t<num[p]){dt=0;break;}
						dt*=P(t,num[p]);
					}
				}
				ans+=dt;
			}
			rep0(c,4) ++cnt[v[j][c]];
		}
		rep0(c,4) ++cnt[v[i][c]];
	}
	assert(ans%3==0);
	//cerr<<"  ans="<<ans<<endl;
	printf("%lld\n",ans/3);
	return 0;
}


Measured memory_bytes: 20352