Cowboy Beblop is a funny little boy who likes sitting at his computer. He somehow obtained two elastic hoops in the shape of 2D polygons, which are not necessarily convex. Since there's no gravity on his spaceship, the hoops are standing still in the air. Since the hoops are very elastic, Cowboy Beblop can stretch, rotate, translate or shorten their edges as much as he wants.

For both hoops, you are given the number of their vertices, as well as the position of each vertex, defined by the X , Y and Z coordinates. The vertices are given in the order they're connected: the 1st vertex is connected to the 2nd, which is connected to the 3rd, etc., and the last vertex is connected to the first one. Two hoops are connected if it's impossible to pull them to infinity in different directions by manipulating their edges, without having their edges or vertices intersect at any point – just like when two links of a chain are connected. The polygons' edges do not intersect or overlap. 

To make things easier, we say that two polygons are well-connected, if the edges of one polygon cross the area of the other polygon in two different directions (from the upper and lower sides of the plane defined by that polygon) a different number of times.

Cowboy Beblop is fascinated with the hoops he has obtained and he would like to know whether they are well-connected or not. Since he’s busy playing with his dog, Zwei, he’d like you to figure it out for him. He promised you some sweets if you help him! 

Input

The first line of input contains an integer n (3 ≤ n ≤ 100 000), which denotes the number of edges of the first polygon. The next N lines each contain the integers x, y and z ( - 1 000 000 ≤ x, y, z ≤ 1 000 000) — coordinates of the vertices, in the manner mentioned above. The next line contains an integer m (3 ≤ m ≤ 100 000) , denoting the number of edges of the second polygon, followed by m lines containing the coordinates of the second polygon’s vertices.

It is guaranteed that both polygons are simple (no self-intersections), and in general that the obtained polygonal lines do not intersect each other. Also, you can assume that no 3 consecutive points of a polygon lie on the same line.

Output

Your output should contain only one line, with the words "YES" or "NO", depending on whether the two given polygons are well-connected. 

Example

Input

4
0 0 0
2 0 0
2 2 0
0 2 0
4
1 1 -1
1 1 1
1 3 1
1 3 -1


Output

YES

Note

On the picture below, the two polygons are well-connected, as the edges of the vertical polygon cross the area of the horizontal one exactly once in one direction (for example, from above to below), and zero times in the other (in this case, from below to above). Note that the polygons do not have to be parallel to any of the xy-,xz-,yz- planes in general. <image>
#include <bits/stdc++.h>
typedef struct {
  double x, y, z;
} three_vector;
typedef struct {
  three_vector origin;
  three_vector normal_vector;
} plane_3D;
typedef struct {
  three_vector origin;
  three_vector direction_vector;
} line_3D;
int compare_t_table(const void *a, const void *b) {
  return (*(const double *)a) > (*(const double *)b);
}
extern inline bool is_approx_zero(const double value) {
  const double tolerence = 1e-10;
  return fabs(value) < tolerence;
}
extern inline bool is_approx_equal(const double val1, const double val2) {
  return is_approx_zero(val1 - val2);
}
extern inline bool is_null_three_vector(const three_vector *target) {
  return is_approx_zero(target->x) && is_approx_zero(target->y) &&
         is_approx_zero(target->z);
}
extern inline void add(three_vector *result, const three_vector *first,
                       const three_vector *second) {
  result->x = first->x + second->x;
  result->y = first->y + second->y;
  result->z = first->z + second->z;
}
extern inline void sub(three_vector *result, const three_vector *first,
                       const three_vector *second) {
  result->x = first->x - second->x;
  result->y = first->y - second->y;
  result->z = first->z - second->z;
}
extern inline void scalar_product_to_target(three_vector *target,
                                            const double scalar) {
  target->x *= scalar;
  target->y *= scalar;
  target->z *= scalar;
}
extern inline double dot_product(const three_vector *first,
                                 const three_vector *second) {
  return first->x * second->x + first->y * second->y + first->z * second->z;
}
extern inline double get_norm2(const three_vector *target) {
  return dot_product(target, target);
}
extern inline void cross_product(three_vector *result,
                                 const three_vector *first,
                                 const three_vector *second) {
  result->x = first->y * second->z - first->z * second->y;
  result->y = first->z * second->x - first->x * second->z;
  result->z = first->x * second->y - first->y * second->x;
}
extern inline void get_intersection(three_vector *result, const plane_3D *plane,
                                    const three_vector *pre_point,
                                    const three_vector *post_point) {
  three_vector vec_n, point_position;
  double t;
  sub(&vec_n, post_point, pre_point);
  sub(&point_position, &plane->origin, pre_point);
  t = dot_product(&plane->normal_vector, &point_position) /
      dot_product(&plane->normal_vector, &vec_n);
  scalar_product_to_target(&vec_n, t);
  add(result, pre_point, &vec_n);
}
extern inline double calculate_t(const line_3D *line,
                                 const three_vector *target) {
  if (!is_approx_zero(line->direction_vector.x))
    return (target->x - line->origin.x) / line->direction_vector.x;
  else if (!is_approx_zero(line->direction_vector.y))
    return (target->y - line->origin.y) / line->direction_vector.y;
  else if (!is_approx_zero(line->direction_vector.z))
    return (target->z - line->origin.z) / line->direction_vector.z;
  else
    return 0;
}
extern inline size_t generate_t_table(const line_3D *intersection_line,
                                      const three_vector *contour,
                                      const size_t contour_num,
                                      double *t_table) {
  size_t i;
  double t1, t2, det;
  size_t now_size = 0;
  three_vector vec_N, vec_Ncross, vec_Np, vec_Npcross, vec_n, point_to_start;
  vec_n = intersection_line->direction_vector;
  for (i = 0; i < contour_num; i++) {
    t1 = t2 = 0;
    sub(&vec_N, &contour[(i + 1) % contour_num], &contour[i]);
    det = vec_n.y * vec_N.x - vec_n.x * vec_N.y;
    if (is_approx_zero(det)) {
      det = vec_n.z * vec_N.x - vec_n.x * vec_N.z;
      if (is_approx_zero(det)) {
        det = vec_n.z * vec_N.y - vec_n.y * vec_N.z;
        if (is_approx_zero(det))
          continue;
        else {
          sub(&point_to_start, &contour[i], &intersection_line->origin);
          t1 = (vec_N.y * point_to_start.z - vec_N.z * point_to_start.y) / det;
          t2 = (vec_n.y * point_to_start.z - vec_n.z * point_to_start.y) / det;
        }
      } else {
        sub(&point_to_start, &contour[i], &intersection_line->origin);
        t1 = (vec_N.x * point_to_start.z - vec_N.z * point_to_start.x) / det;
        t2 = (vec_n.x * point_to_start.z - vec_n.z * point_to_start.x) / det;
      }
    } else {
      sub(&point_to_start, &contour[i], &intersection_line->origin);
      t1 = (vec_N.x * point_to_start.y - vec_N.y * point_to_start.x) / det;
      t2 = (vec_n.x * point_to_start.y - vec_n.y * point_to_start.x) / det;
    }
    if (!is_approx_zero(t2) && (t2 > 0 && t2 < 1))
      t_table[now_size++] = t1;
    else if (is_approx_equal(t2, 1)) {
      do {
        i++;
        sub(&vec_Np, &contour[(i + 1) % contour_num],
            &contour[i % contour_num]);
        cross_product(&vec_Npcross, &intersection_line->direction_vector,
                      &vec_Np);
      } while (is_approx_zero(get_norm2(&vec_Npcross)));
      cross_product(&vec_Ncross, &intersection_line->direction_vector, &vec_N);
      if (!signbit(dot_product(&vec_Ncross, &vec_Npcross)))
        t_table[now_size++] = t1;
      i--;
    }
  }
  qsort(t_table, now_size, sizeof(double), compare_t_table);
  return now_size;
}
extern inline bool is_point_in_contour(const three_vector *point,
                                       const line_3D *line,
                                       const double *t_table,
                                       const size_t t_table_size) {
  double now_t;
  size_t count = t_table_size, first = 0, step;
  now_t = calculate_t(line, point);
  while (count > 0) {
    step = count / 2;
    if (now_t > t_table[first + step]) {
      count -= step + 1;
      first += step + 1;
    } else
      count = step;
  }
  return ((first % 2) == 1);
}
int main() {
  three_vector *first_loop;
  three_vector *second_loop;
  double *t_table;
  size_t n, m, i, t_table_size, start_idx;
  size_t d2u = 0, u2d = 0;
  bool pre_signbit, now_signbit, t_tbl_gened = false;
  int tx, ty, tz;
  three_vector position_vector[2], normal_vector;
  plane_3D first_loop_plane;
  plane_3D second_loop_plane;
  line_3D intersection_line;
  double now_dotp = 0;
  three_vector intersection_point;
  three_vector position_on_plane;
  size_t first_outofsurface_idx = 0;
  size_t pre_point_idx;
  size_t next_of_pre_point_idx;
  scanf("%lu", &n);
  first_loop = (three_vector *)malloc(sizeof(three_vector) * n);
  t_table = (double *)malloc(sizeof(double) * (n - 1));
  normal_vector.x = normal_vector.y = normal_vector.z = 0.;
  start_idx = 0;
  while (is_null_three_vector(&normal_vector)) {
    scanf("%d %d %d", &tx, &ty, &tz);
    first_loop[start_idx].x = tx;
    first_loop[start_idx].y = ty;
    first_loop[start_idx].z = tz;
    if (start_idx > 2) {
      sub(&(position_vector[0]), &first_loop[1], first_loop);
      sub(&(position_vector[1]), &first_loop[start_idx], first_loop);
      cross_product(&normal_vector, &position_vector[0], &position_vector[1]);
    }
    start_idx++;
  }
  for (i = start_idx; i < n; i++) {
    scanf("%d %d %d", &tx, &ty, &tz);
    first_loop[i].x = tx;
    first_loop[i].y = ty;
    first_loop[i].z = tz;
  }
  first_loop_plane.origin = first_loop[0];
  first_loop_plane.normal_vector = normal_vector;
  normal_vector.x = normal_vector.y = normal_vector.z = 0.;
  start_idx = 0;
  scanf("%lu", &m);
  second_loop = (three_vector *)malloc(sizeof(three_vector) * m);
  while (is_null_three_vector(&normal_vector)) {
    scanf("%d %d %d", &tx, &ty, &tz);
    second_loop[start_idx].x = tx;
    second_loop[start_idx].y = ty;
    second_loop[start_idx].z = tz;
    if (start_idx > 2) {
      sub(&(position_vector[0]), &second_loop[1], second_loop);
      sub(&(position_vector[1]), &second_loop[start_idx], second_loop);
      cross_product(&normal_vector, &position_vector[0], &position_vector[1]);
    }
    start_idx++;
  }
  for (i = start_idx; i < m; i++) {
    scanf("%d %d %d", &tx, &ty, &tz);
    second_loop[i].x = tx;
    second_loop[i].y = ty;
    second_loop[i].z = tz;
  }
  second_loop_plane.origin = second_loop[0];
  second_loop_plane.normal_vector = normal_vector;
  cross_product(&intersection_line.direction_vector,
                &first_loop_plane.normal_vector,
                &second_loop_plane.normal_vector);
  if (is_null_three_vector(&intersection_line.direction_vector)) {
    printf("NO");
    return 0;
  }
  for (i = 0; i < m; i++) {
    sub(&position_on_plane, &second_loop[i], &first_loop_plane.origin);
    now_dotp = dot_product(&first_loop_plane.normal_vector, &position_on_plane);
    if (!is_approx_zero(now_dotp)) {
      pre_point_idx = first_outofsurface_idx = i;
      pre_signbit = signbit(now_dotp);
      break;
    }
  }
  if (i == m) {
    printf("NO");
    return 0;
  } else {
    while (true) {
      i = (i + 1) % m;
      sub(&position_on_plane, &second_loop[i], &first_loop_plane.origin);
      now_dotp =
          dot_product(&first_loop_plane.normal_vector, &position_on_plane);
      if (is_approx_zero(now_dotp)) continue;
      now_signbit = signbit(now_dotp);
      if (now_signbit != pre_signbit) {
        next_of_pre_point_idx = (pre_point_idx + 1) % m;
        get_intersection(&intersection_point, &first_loop_plane,
                         &second_loop[pre_point_idx],
                         &second_loop[next_of_pre_point_idx]);
        if (!t_tbl_gened) {
          intersection_line.origin = intersection_point;
          t_table_size =
              generate_t_table(&intersection_line, first_loop, n, t_table);
          t_tbl_gened = true;
        }
        if (is_point_in_contour(&intersection_point, &intersection_line,
                                t_table, t_table_size)) {
          if (pre_signbit)
            d2u++;
          else
            u2d++;
        }
        pre_signbit = now_signbit;
      }
      pre_point_idx = i;
      if (pre_point_idx == first_outofsurface_idx) break;
    }
    if (d2u != u2d)
      printf("YES");
    else
      printf("NO");
  }
  free(t_table);
  free(first_loop);
  free(second_loop);
}
