#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using vi = vector<int>;
using vd = vector<double>;
using vll = vector<ll>;
using vs = vector<string>;
template <int V, int E, typename T = int>
struct MaxFlowGraph {
  T inf = numeric_limits<T>::max();
  void add_edge(int i, int j, T c = 1) {
    g[i].push_back(e1);
    *(e1++) = {j, c, 0};
    g[j].push_back(e1);
    *(e1++) = {i, 0, 0};
  }
  T max_flow(int s, int t) {
    T ans = 0, f;
    while (f = dfs(s, t, inf)) {
      ans += f;
      memset(seen, 0, sizeof(seen));
    }
    return ans;
  }
  void get_maximum_matching(bool *seen, bool *match, int nx, int ny, int m) {
    deque<int> q;
    for (auto e : g[m - 2])
      if (e->f < e->c) {
        q.push_back(e->j);
        seen[e->j] = true;
      }
    while (!q.empty()) {
      int u = q.front();
      q.pop_front();
      for (auto e : g[u])
        if (e->f < e->c && e->j < m - 2 && !seen[e->j]) {
          q.push_back(e->j);
          seen[e->j] = true;
        }
    }
    for (auto i = (0); i < (nx); i++)
      if (!seen[i]) {
        match[i] = true;
      }
    for (auto j = (0); j < (ny); j++)
      if (seen[nx + j]) {
        match[nx + j] = true;
      }
  }

 private:
  struct Edge {
    int j;
    T c, f;
  };
  Edge e0[2 * E], *e1 = e0;
  vector<Edge *> g[V];
  bool seen[V];
  T dfs(int s, int t, T f) {
    if (s == t) return f;
    if (seen[s]) return 0;
    seen[s] = true;
    for (auto e : g[s])
      if (e->c > e->f) {
        T f2 = dfs(e->j, t, min(f, e->c - e->f));
        if (f2) {
          e->f += f2, e0[(e - e0) ^ 1].f -= f2;
          return f2;
        }
      }
    return 0;
  }
};
constexpr int N = 2005, E = 200005;
map<int, vi> by_x, by_y;
bool match[N], seen[N];
MaxFlowGraph<N, E> flow_graph;
int main() {
  int n, x, y;
  scanf("%d", &n);
  for (auto i = (0); i < (n); i++) {
    scanf("%d%d", &x, &y);
    by_x[x].push_back(y);
    by_y[y].push_back(x);
  }
  int nx = 0;
  for (auto &xys : by_x) {
    sort(begin(xys.second), end(xys.second));
    nx += xys.second.size() - 1;
  }
  int ny = 0;
  for (auto &yxs : by_y) {
    sort(begin(yxs.second), end(yxs.second));
    ny += yxs.second.size() - 1;
  }
  int m = nx + ny + 2;
  for (auto i = (0); i < (nx); i++) {
    flow_graph.add_edge(m - 2, i);
  }
  for (auto j = (0); j < (ny); j++) {
    flow_graph.add_edge(nx + j, m - 1);
  }
  int x_id = 0, y_id = 0;
  for (auto &xys : by_x) {
    int x = xys.first;
    for (auto i = (0); i < (xys.second.size() - 1); i++) {
      int y0 = xys.second[i], y1 = xys.second[i + 1];
      y_id = 0;
      for (auto &yxs : by_y) {
        int y = yxs.first;
        for (auto j = (0); j < (yxs.second.size() - 1); j++) {
          int x0 = yxs.second[j], x1 = yxs.second[j + 1];
          if (x0 < x && x < x1 && y0 < y && y < y1)
            flow_graph.add_edge(x_id, nx + y_id);
          y_id++;
        }
      }
      x_id++;
    }
  }
  flow_graph.max_flow(m - 2, m - 1);
  flow_graph.get_maximum_matching(seen, match, nx, ny, m);
  vector<vi> hs;
  y_id = 0;
  for (auto &yxs : by_y) {
    int y = yxs.first;
    int x0 = yxs.second[0];
    for (auto j = (0); j < (yxs.second.size() - 1); j++) {
      if (match[nx + y_id]) {
        hs.push_back({x0, y, yxs.second[j], y});
        x0 = yxs.second[j + 1];
      }
      y_id++;
    }
    hs.push_back({x0, y, yxs.second.back(), y});
  }
  printf("%d\n", hs.size());
  for (auto &h : hs) {
    printf("%d %d %d %d\n", h[0], h[1], h[2], h[3]);
  }
  vector<vi> vs;
  x_id = 0;
  for (auto &xys : by_x) {
    int x = xys.first;
    int y0 = xys.second[0];
    for (auto i = (0); i < (xys.second.size() - 1); i++) {
      if (match[x_id]) {
        vs.push_back({x, y0, x, xys.second[i]});
        y0 = xys.second[i + 1];
      }
      x_id++;
    }
    vs.push_back({x, y0, x, xys.second.back()});
  }
  printf("%d\n", vs.size());
  for (auto &v : vs) {
    printf("%d %d %d %d\n", v[0], v[1], v[2], v[3]);
  }
  return 0;
}
