Little Petya is preparing for the first contact with aliens. He knows that alien spaceships have shapes of non-degenerate triangles and there will be exactly 4 ships. Landing platform for a ship can be made of 3 special columns located at some points of a Cartesian plane such that these 3 points form a triangle equal to the ship with respect to rotations, translations (parallel shifts along some vector) and reflections (symmetries along the edges). The ships can overlap after the landing.

Each column can be used to land more than one ship, for example, if there are two equal ships, we don't need to build 6 columns to land both ships, 3 will be enough. Petya wants to know what minimum number of columns will be enough to land all ships. 

Input

Each of 4 lines will contain 6 integers x1 y1 x2 y2 x3 y3 (0 ≤ x1, y1, x2, y2, x3, y3 ≤ 20), representing 3 points that describe the shape of each of 4 ships. It is guaranteed that 3 points in each line will represent a non-degenerate triangle.

Output

First line should contain minimum number of columns enough to land all spaceships.

Examples

Input

0 0 1 0 1 2
0 0 0 2 2 2
0 0 3 0 1 2
0 0 3 0 2 2


Output

4


Input

0 0 0 1 1 1
0 0 0 2 2 2
0 0 0 5 5 5
0 0 0 17 17 17


Output

9

Note

In the first test case columns can be put in these points: (0, 0), (1, 0), (3, 0), (1, 2). Note that the second ship can land using last 3 columns.

In the second test case following points can be chosen: (0, 0), (0, 1), (1, 0), (0, 2), (2, 0), (0, 5), (5, 0), (0, 17), (17, 0). It is impossible to use less than 9 columns.
#include <bits/stdc++.h>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e100;
struct Point {
  double x, y;
  Point() {}
  Point(double x, double y) : x(x), y(y) {}
  double abs() const { return hypot(x, y); }
  double arg() const { return atan2(y, x); }
  Point operator*(double o) const { return Point(x * o, y * o); }
  Point operator+(const Point& o) const { return Point(x + o.x, y + o.y); }
  Point operator-(const Point& o) const { return Point(x - o.x, y - o.y); }
  bool operator<(const Point& o) const {
    return x < o.x - EPS || (x < o.x + EPS && y < o.y - EPS);
  }
  Point scale(double o) const { return *this * (o / abs()); }
  Point rotl() const { return Point(-y, x); }
  Point rotr() const { return Point(y, -x); }
};
struct Triangle {
  Point p[4];
  double q[3];
  void init() {
    p[3] = p[0];
    for (int i = 0; i < 3; ++i) {
      q[i] = (p[i + 1] - p[i]).abs();
    }
    sort(q, q + 3);
  }
};
void gao(const Point& a, const Point& b, double da, double db,
         vector<Point>& ret, int dump = 0) {
  double sum = (b - a).abs();
  double dif = (da * da - db * db) / sum;
  double ra = (sum + dif) / 2;
  double rb = (sum - dif) / 2;
  double h = da * da - ra * ra;
  if (h < -EPS) {
    return;
  } else {
    h = sqrt(max(0.0, h));
  }
  Point v = (b - a).scale(h);
  ret.push_back(a + (b - a).scale(ra) + v.rotl());
  ret.push_back(a + (b - a).scale(ra) + v.rotr());
  ret.push_back(a + (b - a).scale(rb) + v.rotl());
  ret.push_back(a + (b - a).scale(rb) + v.rotr());
}
int main() {
  int ans;
  double e[4];
  Triangle t[4];
  vector<Point> v;
  for (int i = 0; i < 4; ++i) {
    for (int j = 0; j < 3; ++j) {
      scanf("%lf%lf", &t[i].p[j].x, &t[i].p[j].y);
    }
    t[i].init();
  }
  ans = 9;
  for (int i = 0; i < 81; ++i) {
    for (int j = 0, k = i; j < 4; ++j, k /= 3) {
      e[j] = t[j].q[k % 3];
    }
    if (*max_element(e, e + 4) * 2 - accumulate(e, e + 4, 0.0) < EPS) {
      ans = 8;
      break;
    }
  }
  for (int i = 0; i < 12; ++i) {
    for (int j = (i / 3 + 1) * 3; j < 12; ++j) {
      for (int k = (j / 3 + 1) * 3; k < 12; ++k) {
        Point a(0, 0);
        Point b(t[i / 3].q[i % 3], 0);
        v.clear();
        gao(a, b, t[j / 3].q[j % 3], t[k / 3].q[k % 3], v);
        if (v.empty()) {
          continue;
        }
        Point c = v[0];
        vector<Point> va, vb, vc;
        gao(a, b, t[i / 3].q[(i + 1) % 3], t[i / 3].q[(i + 2) % 3], va);
        gao(a, c, t[j / 3].q[(j + 1) % 3], t[j / 3].q[(j + 2) % 3], vb);
        gao(b, c, t[k / 3].q[(k + 1) % 3], t[k / 3].q[(k + 2) % 3], vc);
        for (const Point& pa : va) {
          for (const Point& pb : vb) {
            for (const Point& pc : vc) {
              set<Point> st = {a, b, c, pa, pb, pc};
              ans = min(ans, (int)st.size() + 2);
              for (int l = 0; l < 12; ++l) {
                if (i / 3 + j / 3 + k / 3 + l / 3 != 6) {
                  continue;
                }
                for (const Point& u : st) {
                  for (const Point& v : st) {
                    if (fabs((u - v).abs() - t[l / 3].q[l % 3]) > EPS) {
                      continue;
                    }
                    vector<Point> vd;
                    gao(u, v, t[l / 3].q[(l + 1) % 3], t[l / 3].q[(l + 2) % 3],
                        vd);
                    for (const Point& pd : vd) {
                      ans = min(ans, (int)st.size() + 1 - (int)st.count(pd));
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  int tmp = 3;
  for (int i = 1; i < 4; ++i) {
    int acc = 2;
    for (int j = 0; j < i; ++j) {
      bool same = true;
      for (int k = 0; k < 3 && same; ++k) {
        same &= fabs(t[i].q[k] - t[j].q[k]) < EPS;
      }
      if (same) {
        acc = 0;
        break;
      }
    }
    for (int j = 0; j < 3 * i && acc > 1; ++j) {
      for (int k = 0; k < 3; ++k) {
        if (fabs(t[j / 3].q[j % 3] - t[i].q[k]) < EPS) {
          acc = 1;
          break;
        }
      }
    }
    tmp += acc;
  }
  ans = min(ans, tmp);
  printf("%d\n", ans);
  return 0;
}
