Problem: Bob Bubblestrong just got a new job as security guard. Bob is now responsible for safety of a collection of warehouses, each containing the most valuable Bubble Cup assets - the high-quality bubbles. His task is to detect thieves inside the warehouses and call the police.

Looking from the sky, each warehouse has a shape of a convex polygon. Walls of no two warehouses intersect, and of course, none of the warehouses is built inside of another warehouse.

Little did the Bubble Cup bosses know how lazy Bob is and that he enjoys watching soap operas (he heard they are full of bubbles) from the coziness of his office. Instead of going from one warehouse to another to check if warehouses are secured, the plan Bob has is to monitor all the warehouses from the comfort of his office using the special X-ray goggles. The goggles have an infinite range, so a thief in any of the warehouses could easily be spotted.

However, the goggles promptly broke and the X-rays are now strong only enough to let Bob see through a single wall. Now, Bob would really appreciate if you could help him find out what is the total area inside of the warehouses monitored by the broken goggles, so that he could know how much area of the warehouses he needs to monitor in person.

Input

The first line contains one integer N (1 ≤ N ≤ 10^4) – the number of warehouses.

The next N lines describe the warehouses.

The first number of the line is integer c_i (3 ≤ c_i ≤ 10^4) – the number corners in the i^{th} warehouse, followed by c_i pairs of integers. The j^{th} pair is (x_j, y_j) – the coordinates of the j^{th} corner (|x_j|, |y_j| ≤ 3 * 10^4). The corners are listed in the clockwise order. The total number of corners in all the warehouses is at most 5 * 10^4.

Bob's office is positioned at the point with coordinates (0, 0). The office is not contained within any of the warehouses.

Output

Print a single line containing a single decimal number accurate to at least four decimal places – the total area of the warehouses Bob can monitor using the broken X-ray goggles.

Example

Input


5
4 1 1 1 3 3 3 3 1
4 4 3 6 2 6 0 4 0
6 -5 3 -4 4 -3 4 -2 3 -3 2 -4 2
3 0 -1 1 -3 -1 -3
4 1 -4 1 -6 -1 -6 -1 -4


Output


13.333333333333

Note

<image>

Areas monitored by the X-ray goggles are colored green and areas not monitored by the goggles are colored red.

The warehouses ABCD, IJK and LMNOPQ are completely monitored using the googles.

The warehouse EFGH is partially monitored using the goggles: part EFW is not monitored because to monitor each point inside it, the X-rays must go through two walls of warehouse ABCD.

The warehouse RUTS is not monitored from the Bob's office, because there are two walls of the warehouse IJK between Bob's office and each point in RUTS.

The total area monitored by the goggles is P = P_{ABCD} + P_{FGHW} + P_{IJK} + P_{LMNOPQ} = 4 + 3.333333333333 + 2 + 4 = 13.333333333333.

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
clock_t t = clock();
namespace my_std {
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
template <typename T>
inline T rnd(T l, T r) {
  return uniform_int_distribution<T>(l, r)(rng);
}
template <typename T>
inline bool chkmax(T &x, T y) {
  return x < y ? x = y, 1 : 0;
}
template <typename T>
inline bool chkmin(T &x, T y) {
  return !(x < y) ? x = y, 1 : 0;
}
template <typename T>
inline void read(T &t) {
  t = 0;
  char f = 0, ch = getchar();
  double d = 0.1;
  while (ch > '9' || ch < '0') f |= (ch == '-'), ch = getchar();
  while (ch <= '9' && ch >= '0') t = t * 10 + ch - 48, ch = getchar();
  if (ch == '.') {
    ch = getchar();
    while (ch <= '9' && ch >= '0') t += d * (ch ^ 48), d *= 0.1, ch = getchar();
  }
  t = (f ? -t : t);
}
template <typename T, typename... Args>
inline void read(T &t, Args &...args) {
  read(t);
  read(args...);
}
char __sr[1 << 21], __z[20];
int __C = -1, __zz = 0;
inline void Ot() { fwrite(__sr, 1, __C + 1, stdout), __C = -1; }
inline void print(register int x) {
  if (__C > 1 << 20) Ot();
  if (x < 0) __sr[++__C] = '-', x = -x;
  while (__z[++__zz] = x % 10 + 48, x /= 10)
    ;
  while (__sr[++__C] = __z[__zz], --__zz)
    ;
  __sr[++__C] = '\n';
}
void file() {}
inline void chktime() {}
long long ksm(long long x, int y) {
  long long ret = 1;
  for (; y; y >>= 1, x = x * x)
    if (y & 1) ret = ret * x;
  return ret;
}
}  // namespace my_std
using namespace my_std;
int dcmp(double x) { return fabs(x) < 1e-8 ? 0 : (x > 0 ? 1 : -1); }
struct Point {
  double x, y;
  int id;
  Point(double X = 0, double Y = 0, int I = 0) { x = X, y = Y, id = I; }
  const Point operator+(const Point &a) const {
    return Point(x + a.x, y + a.y);
  }
  const Point operator-(const Point &a) const {
    return Point(x - a.x, y - a.y);
  }
  const Point operator*(const double &a) const {
    return Point(x * a, y * a, id);
  }
  const bool operator<(const Point &a) const {
    return atan2(y, x) < atan2(a.y, a.x);
  }
};
double Dot(Point a, Point b) { return a.x * b.x + a.y * b.y; }
double Cross(Point a, Point b) { return a.x * b.y - a.y * b.x; }
Point Rot(Point a, double x) {
  return Point(a.x * cos(x) - a.y * sin(x), a.y * cos(x) + a.x * sin(x), a.id);
}
double Area(Point a, Point b, Point c) { return fabs(Cross(b - a, c - a)) / 2; }
double Len(Point a) { return sqrt(Dot(a, a)); }
struct Line {
  Point a, b;
  Line(Point A, Point B) { a = A, b = B; }
};
Point LI(Line l1, Line l2) {
  double k1 = dcmp(l1.a.x - l1.b.x) ? (l1.a.y - l1.b.y) / (l1.a.x - l1.b.x)
                                    : 1e18,
         b1 = l1.a.y - l1.a.x * k1;
  double k2 = dcmp(l2.a.x - l2.b.x) ? (l2.a.y - l2.b.y) / (l2.a.x - l2.b.x)
                                    : 1e18,
         b2 = l2.a.y - l2.a.x * k2;
  if (!dcmp(k1 - k2)) {
    if (dcmp(b1 - b2)) return Point(1e18, 1e18);
    if (dcmp(Dot(l1.a - l2.a, l1.a - l2.b)) <= 0) return l1.a;
    return l1.b;
  }
  if (k1 > 1e17) return Point(l1.a.x, k2 * l1.a.x + b2);
  if (k2 > 1e17) return Point(l2.a.x, k1 * l2.a.x + b1);
  double x = (b2 - b1) / (k1 - k2), y = k1 * x + b1;
  return Point(x, y);
}
bool SSI(Line l1, Line l2) {
  Point a = LI(l1, l2);
  return dcmp(Dot(a - l2.a, a - l2.b)) <= 0 &&
         dcmp(Dot(a - l1.a, a - l1.b)) <= 0;
}
bool check(Point a, Point b, Point c) { return dcmp(Area(a, b, c)) == 0; }
int n, m;
Point p[101010];
vector<Point> poly[101010], up[101010], dn[101010];
vector<double> Up[101010], Dn[101010];
Point L[101010], R[101010];
int p1[101010], p2[101010];
Point c1[101010], c2[101010];
Point cur;
void Maintain(int i) {
  while (!SSI(Line(Point(0, 0), cur), Line(up[i][p1[i]], up[i][p1[i] + 1])))
    ++p1[i];
  while (!SSI(Line(Point(0, 0), cur), Line(dn[i][p2[i]], dn[i][p2[i] + 1])))
    ++p2[i];
  c1[i] = LI(Line(Point(0, 0), cur), Line(up[i][p1[i]], up[i][p1[i] + 1]));
  c2[i] = LI(Line(Point(0, 0), cur), Line(dn[i][p2[i]], dn[i][p2[i] + 1]));
  if (check(Point(0, 0), cur * 1e-5, L[i]))
    p1[i] = p2[i] = 0, c1[i] = c2[i] = L[i];
  else if (check(Point(0, 0), cur * 1e-5, R[i]))
    p1[i] = (int)up[i].size() - 2, p2[i] = (int)dn[i].size() - 2,
    c1[i] = c2[i] = R[i];
}
double calc(int id) {
  return Up[id][p1[id]] + Dn[id][p2[id]] + Area(L[id], c1[id], up[id][p1[id]]) +
         Area(L[id], c2[id], dn[id][p2[id]]) + Area(L[id], c1[id], c2[id]);
}
struct cmp {
  const bool operator()(const int &x, const int &y) {
    Point a = LI(Line(Point(0, 0), cur), Line(L[x], R[x])),
          b = LI(Line(Point(0, 0), cur), Line(L[y], R[y]));
    return Dot(a, a) < Dot(b, b);
  }
};
set<int, cmp> s;
int main() {
  file();
  read(n);
  for (int i = (1); i <= (n); i++) {
    int k;
    read(k);
    int x, y;
    for (int j = (1); j <= (k); j++)
      read(x, y), poly[i].push_back(p[++m] = Point(x, y, i));
  }
  for (int i = (1); i <= (m); i++) p[i] = Rot(p[i], 1.9260817);
  for (int i = (1); i <= (n); i++)
    for (auto &x : poly[i]) x = Rot(x, 1.9260817);
  sort(p + 1, p + m + 1);
  for (int i = (1); i <= (n); i++) {
    int s = poly[i].size();
    Point mx = poly[i][0], mn = poly[i][0];
    int pmx = 0, pmn = 0;
    for (int j = (0); j <= (s - 1); j++) {
      if (chkmax(mx, poly[i][j])) pmx = j;
      if (chkmin(mn, poly[i][j])) pmn = j;
    }
    if (dcmp(Cross(mx, mn)) > 0) {
      swap(mn, mx);
      swap(pmn, pmx);
      for (int j = (0); j <= (s - 1); j++)
        if (atan2(poly[i][j].y, poly[i][j].x) > 0 && chkmin(mn, poly[i][j]))
          pmn = j;
      for (int j = (0); j <= (s - 1); j++)
        if (atan2(poly[i][j].y, poly[i][j].x) < 0 && chkmax(mx, poly[i][j]))
          pmx = j;
    }
    vector<Point> tmp;
    for (int j = (0); j <= (s - 1); j++) tmp.push_back(poly[i][(j + pmn) % s]);
    poly[i] = tmp;
    tmp.push_back(mn);
    (pmx += s - pmn) %= s;
    pmn = 0;
    for (int j = (0); j <= (pmx); j++) up[i].push_back(tmp[j]);
    for (int j = (s); j >= (pmx); j--) dn[i].push_back(tmp[j]);
    int s1 = up[i].size(), s2 = dn[i].size();
    Up[i].push_back(0), Dn[i].push_back(0);
    for (int j = (1); j <= (s1 - 1); j++)
      Up[i].push_back(Area(up[i][j - 1], up[i][j], mn));
    for (int j = (1); j <= (s2 - 1); j++)
      Dn[i].push_back(Area(dn[i][j - 1], dn[i][j], mn));
    for (int j = (1); j <= (s1 - 1); j++) Up[i][j] += Up[i][j - 1];
    for (int j = (1); j <= (s2 - 1); j++) Dn[i][j] += Dn[i][j - 1];
    L[i] = mn, R[i] = mx;
  }
  cur = Point(-1e9, 0);
  for (int i = (1); i <= (n); i++) {
    if (!SSI(Line(Point(0, 0), cur), Line(L[i], R[i]))) continue;
    s.insert(i);
    Maintain(i);
  }
  p[++m] = cur;
  double ans = 0;
  for (int k = (1); k <= (m); k++) {
    int i = p[k].id;
    cur = p[k] * 1e5;
    if (fabs(Len(p[k] - L[i])) && fabs(Len(p[k] - R[i])) &&
        (k != m || !s.size()))
      continue;
    if (k != m && !fabs(Len(p[k] - L[i]))) {
      Maintain(i);
      if (!s.size()) {
        s.insert(i);
        continue;
      }
      int beg = *(s.begin());
      s.insert(i);
      if (*(s.begin()) != i) continue;
      i = beg;
      double S1 = calc(i);
      Maintain(i);
      double S2 = calc(i);
      ans += S2 - S1;
    } else {
      if (k == m) i = *(s.begin());
      if (k != m && i != *(s.begin())) {
        s.erase(i);
        p1[i] = p2[i] = 0;
        continue;
      }
      s.erase(i);
      double S1 = calc(i);
      Maintain(i);
      double S2 = calc(i);
      ans += S2 - S1;
      p1[i] = p2[i] = 0;
      if (s.size()) Maintain(*(s.begin()));
    }
  }
  printf("%.10lf", ans);
  return 0;
}