#include <cassert>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <bitset>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <utility>
#include <vector>
typedef unsigned int U;
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
using std::cin; using std::cout;
using std::endl; using std::cerr;
using std::bitset; using std::map;
using std::queue; using std::priority_queue;
using std::set; using std::string;
using std::vector;
using std::pair; using std::make_pair;
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
typedef pair<ULL, ULL> puu;
#ifdef DEBUG
#define pass cerr << "[" << __FUNCTION__ << "] : line = " << __LINE__ << endl;
#define display(x) cerr << #x << " = " << x << endl;
#define displaya(a, st, n) { cerr << #a << " = {"; \
      for(int qwq = (st); qwq <= (n); ++qwq) cerr << a[qwq] << (qwq == (n) ? '}' : ',') << (qwq == (n) ? '\n' : ' '); }
#define displayv(a) display(a, 0, (int)(a.size()-1))
#include <ctime>
class MyTimer {
  clock_t st;
public:
  MyTimer() { cerr << std::fixed << std::setprecision(0); reset(); }
  ~MyTimer() { report(); }
  void reset() { st = clock_t(); }
  void report() {  cerr << "Time consumed: " << (clock() - st) * 1e3 / CLOCKS_PER_SEC << "ms" << endl; }
} myTimer;
#else
#define pass ;
#define display(x) ;
#define displaya(a, st, n) {}
#define displayv(a) {}
class MyTimer {
public: void reset() {} void report() {}
} myTimer;
#endif

template<typename T1, typename T2>
inline bool chmin(T1 &a, const T2 &b) { return a > b ? a = b, true : false; }
template<typename T1, typename T2>
inline bool chmax(T1 &a, const T2 &b) { return a < b ? a = b, true : false; }
#ifdef QUICK_READ
char pool[1<<15|1],*it=pool+32768;
#define getchar() (it>=pool+32768?(pool[fread(pool,sizeof(char),1<<15,stdin)]=EOF,*((it=pool)++)):*(it++))
#endif
inline int readint() {
  int a = 0; char c = getchar(), p = 0;
  while(isspace(c)) c = getchar();
  if(c == '-') p = 1, c = getchar();
  while(isdigit(c)) a = a*10 + c - '0', c = getchar();
  return p ? -a : a;
}
inline LL readLL() {
  LL a = 0; char c = getchar(), p = 0;
  while(isspace(c)) c = getchar();
  if(c == '-') p = 1, c = getchar();
  while(isdigit(c)) a = a*10 + c - '0', c = getchar();
  return p ? -a : a;
}

const int maxN = 400 + 5;
const int maxC = 1000 + 23;
int n;
struct Tile {
  int c[4];
  Tile() {}
  int& operator [](const int id) {
    return c[id];
  }
  Tile(int x, int y, int z, int w) {
    c[0] = x; c[1] = y; c[2] = z; c[3] = w;
  }
  friend bool operator < (Tile A, Tile B) {
    for(int i = 0; i < 4; ++i) if(A[i] != B[i]) return A[i] < B[i];
    return false;
  }
  friend bool operator == (Tile A, Tile B) {
    for(int i = 0; i < 4; ++i) if(A[i] != B[i]) return false;
    return true;
  }
  void rotate() {
    int t = c[3];
    for(int i = 3; i > 0; --i) c[i] = c[i - 1];
    c[0] = t;
  }
  Tile normal() {
    Tile r = *this;
    for(int j = 0; j < 4; ++j) {
      rotate(); if(*this < r) r = *this;
    }
    return r;
  }
  string tos() {
  	static char s[100];
  	sprintf(s, "(%d, %d, %d, %d)", c[0], c[1], c[2], c[3]);
  	return string(s);
	}
}a[maxN];

#include <unordered_map>
using std::unordered_map;
class hasher {
public:
	size_t operator() (const Tile &x) const {
		size_t h = 0;
		for(int i = 0; i < 4; ++i) h = h << 10 | x.c[i];
		return h;
	}
};

unordered_map<Tile, int, hasher> M;
void add(Tile x, int val) {
	for(int i = 0; i < 4; ++i) {
		x.rotate(); M[x] += val;
	}
}

LL solve() {
  LL ans = 0;
  for(int i = n - 1; i >= 0; --i) {
    for(int j = i + 1; j < n; ++j) {
      add(a[j], -1);
      for(int t = 0; t < 4; ++t) {
        a[j].rotate();
        Tile ai = a[i], aj = a[j];
        Tile sample[4] = {Tile(aj[2], aj[1], ai[0], ai[3]), Tile(aj[3], aj[2], ai[3], ai[2]),
              Tile(aj[0], aj[3], ai[2], ai[1]), Tile(aj[1], aj[0], ai[1], ai[0])};
        for(int k = 0; k < 4; ++k) sample[k] = sample[k].normal();
        LL prod = 1;
        for(int k = 0; k < 4; ++k) {
        	if(M[sample[k]] == 0) {
        		for(int kk = 0; kk < k; ++kk) add(sample[kk], 1);
        		goto GIVEUP;
					}
          prod *= M[sample[k]]; add(sample[k], -1);
        }
        for(int k = 0; k < 4; ++k) add(sample[k], 1);
        ans += prod;
        GIVEUP: {}
      }
      add(a[j], 1);
    }
    add(a[i], 1);
  }
  return ans;
}

int main() {
  n = readint();
  for(int i = 0; i < n; ++i) for(int j = 0; j < 4; ++j) a[i][j] = readint();
  for(int i = 0; i < n; ++i) a[i] = a[i].normal();
	printf("%lld\n", solve());
  return 0;
}

Measured memory_bytes: 19316