#define _CRT_SECURE_NO_WARNINGS
#include <iterator>
#include <set>
#include <queue>
#include <iostream>
#include <sstream>
#include <stack>
#include <deque>
#include <map>
#include <cmath>
#include <memory.h>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <utility>
#include <time.h>

using namespace std;

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define RFOR(i,b,a) for(int i=(b)-1;i>=(a);--i)
#define FILL(A,val) memset(A,val,sizeof(A))
#define ITER(it,a) for(__typeof(a.begin()) it=a.begin();it!=a.end();++it)
#define DBG1(a) cerr<<#a<<" = "<<(a)<<"\n"
#define DBG2(a,b) cerr<<#a<<"="<<(a)<<", "<<#b<<"="<<(b)<<"\n"

#define ALL(V) V.begin(),V.end()
#define SZ(V) (int)V.size()
#define PB push_back
#define MP make_pair
#define y1 frgrwegreg

typedef long long LL;
typedef unsigned long long ULL;
typedef vector<int> VI;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;

const double PI = acos(-1.0);
const int MOD = 1000 * 1000 * 1000 + 7;
const int MAX = 100017;

struct G
{
	int a[4];
	int db;

	G()
	{
		db = 1;
	}

	bool less(G t)
	{
		return MP(MP(a[0],a[1]),MP(a[2],a[3])) > MP(MP(t.a[0],t.a[1]),MP(t.a[2],t.a[3]));
	}

	bool equals(G t)
	{
		return MP(MP(a[0],a[1]),MP(a[2],a[3])) == MP(MP(t.a[0],t.a[1]),MP(t.a[2],t.a[3]));
	}

	void norm()
	{
		int b[4];
		FOR (i,0,4) b[i] = a[i];
		FOR (e,1,4)
		if (MP(MP(b[(0+e)%4], b[(1+e)%4]), MP(b[(2+e)%4], b[(3+e)%4])) < MP(MP(a[0],a[1]),MP(a[2],a[3])))
		{
			FOR (i,0,4) a[i] = b[(i+e)%4];
		}
		db = 1;
		if (a[0] == a[2] && a[1] == a[3])
		{
			db*=2;
			if (a[0] == a[1]) db*=2;
		}
		//cout << "*" << db << endl;
	}
} W[1000];
int n;
LL ans = 0;

int main()
{
	//freopen("C.in", "r", stdin);
	//freopen("out.txt", "w", stdout);
	//ios::sync_with_stdio(0); cin.tie(0);

	cin >> n;
	FOR (i,0,n)
	{
		FOR (j,0,4) cin >> W[i].a[j];
		W[i].norm();
		//FOR (j,0,4) cout << W[i].a[j]<<" ";
		//cout << endl;
	}
	FOR (fr,0,n)
	FOR (tl,fr+1,n)
	FOR (Q,0,4)
	{
		G ms[4];
		ms[0].a[0] = W[fr].a[0];
		ms[0].a[3] = W[fr].a[1];
		ms[1].a[0] = W[fr].a[1];
		ms[1].a[3] = W[fr].a[2];
		ms[2].a[0] = W[fr].a[2];
		ms[2].a[3] = W[fr].a[3];
		ms[3].a[0] = W[fr].a[3];
		ms[3].a[3] = W[fr].a[0];

		ms[0].a[2] = W[tl].a[(4-1+Q)%4];
		ms[0].a[1] = W[tl].a[(4-0+Q)%4];
		ms[1].a[2] = W[tl].a[(4-2+Q)%4];
		ms[1].a[1] = W[tl].a[(4-1+Q)%4];
		ms[2].a[2] = W[tl].a[(4-3+Q)%4];
		ms[2].a[1] = W[tl].a[(4-2+Q)%4];
		ms[3].a[2] = W[tl].a[(4-0+Q)%4];
		ms[3].a[1] = W[tl].a[(4-3+Q)%4];
		ms[0].norm(); ms[1].norm();
		ms[2].norm(); ms[3].norm();
		/*cout << fr<<" "<<tl<<endl;
		FOR (z,0,4)
		{
			FOR (zz,0,4)
			cout << ms[z].a[zz]<<" ";
			cout << endl;
		}*/
		int NUM[4] = {0};
		FOR (k,fr+1,n)
		{
			if (k == tl) continue;
			FOR (TYPE,0,4)
			{
				bool ok = 1;
				FOR (QWE,0,4)
				{
					if (W[k].a[QWE] != ms[TYPE].a[QWE])
						ok = 0;
				}
				if (ok) NUM[TYPE]++;
			}
		}
		LL QSW = 1;
		FOR (F,0,4)
		{
			int R = 0;
			FOR (D,0,F)
			{
				if (ms[D].equals(ms[F])) R++;
			}
			QSW *= (NUM[F]-R)*ms[F].db;
			//cout << "<<"<<NUM[F]<<" ";
		}
		//cout << QSW<<"\n";
		ans += QSW;
		/*if (QSW)
		{
			cout << QSW << endl;
			FOR (i,0,4) cout << NUM[i]<<" ";
			cout << endl;
		}*/
	}
	cout << ans;
	return 0;
}


Measured memory_bytes: 256