#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;

inline int GetBit(int mask, int num) {
    return (mask >> num) & 1;
}

int cFront[4];
int cBack[4];

inline long long GetId(int c0, int c1, int c2, int c3) {
    return c0 + 1000LL * (c1 + 1000LL * (c2 + 1000LL * c3));
}

inline long long GetLeftId() {
    return GetId(cBack[3], cBack[2], cFront[1], cFront[0]);
}

inline long long GetRightId() {
    return GetId(cFront[3], cFront[2], cBack[1], cBack[0]);
}

inline long long GetUpId() {
    return GetId(cFront[1], cBack[2], cBack[1], cFront[2]);
}

inline long long GetDownId() {
    return GetId(cBack[3], cFront[0], cFront[3], cBack[0]);
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<vector<int>> colors(n, vector<int>(8));
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < 4; ++j) {
            cin >> colors[i][j];
            colors[i][j + 4] = colors[i][j];
        }
    }

    unordered_map<long long, int> colorCount;

    vector<vector<int>> normColors;

    unordered_map<long long, int> colorIds;

    vector<vector<long long>> sides(n, vector<long long>(4));

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < 4; ++j) {
            sides[i][j] = GetId(colors[i][j], colors[i][j + 1], colors[i][j + 2], colors[i][j + 3]);
        }

        for (int j = 0; j < 4; ++j) {
            if (colorIds.find(sides[i][j]) == colorIds.end()) {
                colorIds[sides[i][j]] = (int) normColors.size();
                normColors.push_back(vector<int>());
            }
        }

        for (int j = 0; j < 4; ++j) {
            const int curId = colorIds[sides[i][j]];

            ++colorCount[curId];

            if (normColors[curId].empty()) {
                for (int s = 0; s < 4; ++s) {
                    normColors[curId].push_back(colorIds[sides[i][(j + s) % 4]]);
                }
            }
        }
    }

    long long glResult = 0;
    for (int i = 0; i < n; ++i) {
        for (int t = 0; t < 4; ++t) {
            cFront[t] = colors[i][t];
        }
        for (int t = 0; t < 4; ++t) {
            --colorCount[colorIds[sides[i][t]]];
        }

        for (int j = i + 1; j < n; ++j) {
            for (int t = 0; t < 4; ++t) {
                --colorCount[colorIds[sides[j][t]]];
            }

            for (int dj = 0; dj < 4; ++dj) {
                for (int t = 0; t < 4; ++t) {
                    cBack[t] = colors[j][dj + t];
                }

                long long curIds[4];

                curIds[0] = GetLeftId();
                curIds[1] = GetRightId();
                curIds[2] = GetUpId();
                curIds[3] = GetDownId();

                long long result = 1;

                for (int t = 0; t < 4; ++t) {
                    if (colorIds.find(curIds[t]) == colorIds.end()) {
                        result = 0;
                        continue;
                    }

                    const int id = colorIds[curIds[t]];

                    result *= colorCount[id];

                    for (int x : normColors[id]) {
                        --colorCount[x];
                    }
                }

                for (int t = 0; t < 4; ++t) {
                    if (colorIds.find(curIds[t]) == colorIds.end()) {
                        continue;
                    }

                    const int id = colorIds[curIds[t]];

                    for (int x : normColors[id]) {
                        ++colorCount[x];
                    }
                }

                glResult += result;
            }

            for (int t = 0; t < 4; ++t) {
                ++colorCount[colorIds[sides[j][t]]];
            }
        }
    }

    cout << glResult << endl;

    return 0;
}


Measured memory_bytes: 640