#include <bits/stdc++.h>
#define loop(n) for (int ngtkana_is_a_genius = 0; ngtkana_is_a_genius < int(n); ngtkana_is_a_genius++)
#define rep(i, begin, end) for (int i = int(begin); (i) < int(end); i++)
#define all(v) v.begin(), v.end()
#define rand(l, r) std::uniform_int_distribution<>(l, r)(mt)
using lint = long long;
auto mt = std::mt19937_64(std::random_device{}());
auto cmn = [](auto& a, auto b){ if (a > b) {a = b; return true;} return false; };
auto cmx = [](auto& a, auto b){ if (a < b) {a = b; return true;} return false; };
void debug_impl() { std::cerr << std::endl; }
template <typename Head, typename... Tail>
void debug_impl(Head head, Tail... tail) { std::cerr << " " << head; debug_impl(tail...); }
#ifndef STOPIT
#define debug(...)\
  do {\
    std::cerr << std::boolalpha << "[" << #__VA_ARGS__ << "]:";\
    debug_impl(__VA_ARGS__);\
    std::cerr << std::noboolalpha;\
  } while (false)
#else
#define debug(...) 0;
#endif

template < template < typename ... > class Tuple,  typename... Args, std::size_t ... Inds, std::size_t = std::tuple_size< Tuple < Args ... > >::value >
std::istream& tuple_input_impl(std::istream& os, Tuple<Args...>& tuple, std::integer_sequence<std::size_t, Inds...>)
  { (void)std::initializer_list<int>{((void)(os >> std::get< Inds >(tuple)), 0)...}; return os; }
template < template < typename ... > class Tuple,  typename... Args, std::size_t = std::tuple_size< Tuple < Args ... > >::value >
std::istream& operator>> (std::istream& os, Tuple<Args...>& tuple)
  { return tuple_input_impl(os, tuple, std::index_sequence_for<Args...>()); }

template < template < typename ... > class Tuple,  typename... Args, std::size_t ... Inds, std::size_t = std::tuple_size< Tuple < Args ... > >::value >
std::ostream& tuple_output_impl(std::ostream& os, const Tuple<Args...>& tuple, std::integer_sequence<std::size_t, Inds...>)
  { os << "("; (void)std::initializer_list<int>{((void)(os << (Inds > 0 ? "," : "") << std::get< Inds >(tuple)), 0)...}; return os << ")"; }
template < template < typename ... > class Tuple,  typename... Args, std::size_t = std::tuple_size< Tuple < Args ... > >::value >
std::ostream& operator<< (std::ostream& os, const Tuple<Args...>& tuple)
 { return tuple_output_impl(os, tuple, std::index_sequence_for<Args...>()); }

template < typename Container, typename Value = typename Container::value_type, std::enable_if_t<!std::is_same< Container, std::string >::value, std::nullptr_t> = nullptr>
std::istream& operator>> (std::istream& is, Container& v)
  { for (auto & x : v) { is >> x; } return is; }

template < typename Container, typename Value = typename Container::value_type, std::enable_if_t<!std::is_same< Container, std::string >::value, std::nullptr_t> = nullptr >
std::ostream& operator<< (std::ostream& os, Container const& v) {
 os << "{";
  for (auto it = v.begin(); it != v.end(); it++)
    {os << (it != v.begin() ? "," : "") << *it;}
  return os << "}";
}

template <typename T>
auto make_vector_impl(size_t sz, T t) {return std::vector<T>(sz, t);}

template <size_t N, typename T, typename U, std::enable_if_t<N == 1, std::nullptr_t> = nullptr>
auto make_vector(size_t sz, U u) {return make_vector_impl(sz, T(u));}

template <size_t N, typename T, std::enable_if_t<N == 1, std::nullptr_t> = nullptr>
auto make_vector(size_t sz) {return std::vector<T>(sz);}

template <size_t N, typename T, typename... Args, std::enable_if_t<N != 1, std::nullptr_t> = nullptr>
auto make_vector(size_t a, Args... args) {return make_vector_impl(a, make_vector<N - 1, T>(args...));}

template <typename T, typename Size_t>
auto& at(T& t, Size_t i) {return t.at(i);}

template <typename T, typename Size_t, typename... Args>
auto& at(T& t, Size_t i, Args... args) {return at(t.at(i), args...);}

int main() {
  std::cin.tie(0); std::cin.sync_with_stdio(false);
  int four = 4;
  lint kind = 1000;
  auto coeffs = std::vector<lint>{1,kind, kind*kind,kind*kind*kind};
  std::reverse(all(coeffs));
  auto hash = [coeffs] (std::vector< lint > const& v)
    { return std::inner_product(all(v), std::begin(coeffs), 0ll); };
  auto unhash = [four, kind] (lint h) {
    std::vector< lint > ret(four);
    for (lint & x : ret) {
      x = h % kind;
      h /= kind;
    }
    std::reverse(all(ret));
    return ret;
  };
  auto hashes_mul = [&] (std::vector< lint > v) {
    std::vector< lint > h(four);
    rep(i,0,four) {
      h.at(i) = hash(v);
      std::rotate(v.begin(), v.begin()+1, v.end());
    }
    std::sort(all(h));
    h.resize(std::unique(all(h)) - h.begin());
    return std::make_pair(h, four / h.size());
  };

  std::map< lint, lint > map;
  int n; std::cin >> n;
  auto store = make_vector< 2, lint >(n, four);
  for (auto& v : store) {
    std::cin >> v;
    std::vector<lint> hs; lint m; std::tie(hs, m) = hashes_mul(v);
    for (lint h : hs) {
      map[h]++;
    }
  }

  auto ind_mat = std::vector< std::vector< int > >{
    std::vector< int >{ 0, 4, 5, 1 },
    std::vector< int >{ 1, 5, 6, 2 },
    std::vector< int >{ 2, 6, 7, 3 },
    std::vector< int >{ 3, 7, 4, 0 }
  };
  auto cal = [&] (lint top, lint bottom) {
    std::vector< lint > a = unhash(top);
    std::vector< lint > b = unhash(bottom);
    lint bottom_ = hashes_mul(b).first.front();
    std::reverse(all(b));
    for (lint x : b) a.emplace_back(x);
    std::map< std::pair<lint, lint>, lint > want;
    for (auto const& ind_vec: ind_mat) {
      std::vector< lint > color(four);
      std::transform(all(ind_vec), color.begin(), [&a](int i){ return a.at(i); });
      std::vector< lint > hs; lint m; std::tie(hs, m) = hashes_mul(color);
      lint h = hs.front();
      // debug(ind_vec, color, unhash(h), m);
      want[std::make_pair(h, m)]++;
    }
    // debug(want);
    lint ans = 1;
    for (auto&& pair : want) {
      std::pair< lint, lint > key; lint want_; std::tie(key, want_) = pair;
      lint id, mul_ ; std::tie(id, mul_) = key;
      lint stock = [&]{ auto it = map.find(id); return it != map.end() ? it->second : 0ll; }();
      stock -= (id == top);
      stock -= (id == bottom_);
      lint now = 1;
      rep(i,0,want_) {
        now *= stock - i;
        now *= mul_;
      }
      // debug(id, mul_, want_, stock, now);
      ans *= now;
    }
    return ans;
  };
  lint ans = 0;
  rep(i,0,n) rep(j,i+1,n) {
    std::vector< lint > top_vec, bottom_vec; lint m;
    std::tie(top_vec, std::ignore) = hashes_mul(store.at(i));
    std::tie(bottom_vec, m) = hashes_mul(store.at(j));
    for (lint bottom : bottom_vec) {
      lint now = cal(top_vec.front(), bottom);
      // debug(now,m);
      now *= m;
      ans += now;
    }
  }
  // debug(ans);
  assert(ans % 3 == 0);
  ans /= 3;
  std::cout << ans << std::endl;
  return 0;
}

Measured memory_bytes: 384