#include <bits/stdc++.h>
using namespace std;
template <class X, class Y>
bool minimize(X &x, const Y &y) {
  X eps = 1e-9;
  if (x > y + eps) {
    x = y;
    return true;
  } else
    return false;
}
template <class X, class Y>
bool maximize(X &x, const Y &y) {
  X eps = 1e-9;
  if (x + eps < y) {
    x = y;
    return true;
  } else
    return false;
}
template <class T>
T Abs(const T &x) {
  return (x < 0 ? -x : x);
}
struct DinicFlow {
  static const int INF = (int)1e9 + 7;
  int numNode, numEdge;
  vector<int> dist, head, work;
  vector<int> point, flow, capa, ___next;
  DinicFlow(int n = 0) {
    numNode = n;
    numEdge = 0;
    dist.assign(n + 7, 0);
    head.assign(n + 7, -1);
    work.assign(n + 7, 0);
  }
  int addEdge(int u, int v, int c1, int c2 = 0) {
    int ret = numEdge;
    point.push_back(v);
    capa.push_back(c1);
    flow.push_back(0);
    ___next.push_back(head[u]);
    head[u] = numEdge++;
    point.push_back(u);
    capa.push_back(c2);
    flow.push_back(0);
    ___next.push_back(head[v]);
    head[v] = numEdge++;
    return ret;
  }
  bool bfs(int s, int t) {
    queue<int> q;
    for (int i = 1; i <= numNode; i++) dist[i] = -1;
    dist[s] = 0;
    q.push(s);
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      for (int i = head[u]; i >= 0; i = ___next[i])
        if (flow[i] < capa[i] && dist[point[i]] < 0) {
          dist[point[i]] = dist[u] + 1;
          q.push(point[i]);
        }
    }
    return dist[t] >= 0;
  }
  int dfs(int s, int t, int f) {
    if (s == t) return f;
    for (int &i = work[s]; i >= 0; i = ___next[i])
      if (flow[i] < capa[i] && dist[point[i]] == dist[s] + 1) {
        int d = dfs(point[i], t, min(f, capa[i] - flow[i]));
        if (d > 0) {
          flow[i] += d;
          flow[i ^ 1] -= d;
          return d;
        }
      }
    return 0;
  }
  int maxFlow(int s, int t) {
    int totFlow = 0;
    while (bfs(s, t)) {
      for (int i = 1; i <= numNode; i++) work[i] = head[i];
      while (true) {
        int d = dfs(s, t, INF);
        if (d == 0) break;
        totFlow += d;
      }
    }
    return totFlow;
  }
  int getFlow(int id) const { return flow[id]; }
  bool havePath(int node) const { return dist[node] >= 0; }
};
struct Triple {
  int a, b, c;
  Triple(int a = 0, int b = 0, int c = 0) {
    this->a = a;
    this->b = b;
    this->c = c;
  }
};
const int INF = (int)1e9 + 7;
pair<int, int> points[1010];
map<int, vector<int>> atX, atY;
int numPoint;
int rightPoint[1010], upPoint[1010], rightNode[1010], upNode[1010];
void init(void) {
  scanf("%d", &numPoint);
  for (int i = (1), _b = (numPoint); i <= _b; i++)
    scanf("%d%d", &points[i].first, &points[i].second);
}
int pointID(int x, int y) {
  int id =
      lower_bound(points + 1, points + numPoint + 1, make_pair(x, y)) - points;
  assert(id <= numPoint && points[id].first == x && points[id].second == y);
  return id;
}
void prepare(void) {
  sort(points + 1, points + numPoint + 1);
  for (int i = (1), _b = (numPoint); i <= _b; i++) {
    int x = points[i].first, y = points[i].second;
    atX[x].push_back(y);
    atY[y].push_back(x);
  }
  memset(upPoint, -1, sizeof upPoint);
  for (__typeof((atX).begin()) it = (atX).begin(); it != (atX).end(); it++) {
    int x = it->first;
    vector<int> &y = it->second;
    sort((y).begin(), (y).end());
    for (int j = 0, _n = ((int)y.size() - 1); j < _n; j++) {
      int y1 = y[j], y2 = y[j + 1];
      int id1 = pointID(x, y1);
      int id2 = pointID(x, y2);
      upPoint[id1] = id2;
    }
  }
  memset(rightPoint, -1, sizeof rightPoint);
  for (__typeof((atY).begin()) jt = (atY).begin(); jt != (atY).end(); jt++) {
    int y = jt->first;
    vector<int> &x = jt->second;
    sort((x).begin(), (x).end());
    for (int i = 0, _n = ((int)x.size() - 1); i < _n; i++) {
      int x1 = x[i], x2 = x[i + 1];
      int id1 = pointID(x1, y);
      int id2 = pointID(x2, y);
      rightPoint[id1] = id2;
    }
  }
}
bool intersect(int rightID, int upID) {
  int x = points[upID].first, y1 = points[upID].second,
      y2 = points[upPoint[upID]].second;
  int y = points[rightID].second, x1 = points[rightID].first,
      x2 = points[rightPoint[rightID]].first;
  return x1 < x && x < x2 && y1 < y && y < y2;
}
void process(void) {
  int numNode = 0;
  for (int i = (1), _b = (numPoint); i <= _b; i++)
    if (upPoint[i] > 0) upNode[i] = ++numNode;
  for (int i = (1), _b = (numPoint); i <= _b; i++)
    if (rightPoint[i] > 0) rightNode[i] = ++numNode;
  DinicFlow df(numNode + 2);
  int src = numNode + 1, snk = numNode + 2;
  for (int i = (1), _b = (numPoint); i <= _b; i++)
    if (upPoint[i] > 0) df.addEdge(src, upNode[i], 1);
  for (int i = (1), _b = (numPoint); i <= _b; i++)
    if (rightPoint[i] > 0) df.addEdge(rightNode[i], snk, 1);
  for (int i = (1), _b = (numPoint); i <= _b; i++)
    if (upPoint[i] > 0)
      for (int j = (1), _b = (numPoint); j <= _b; j++)
        if (rightPoint[j] > 0)
          if (intersect(j, i)) df.addEdge(upNode[i], rightNode[j], INF);
  df.maxFlow(src, snk);
  vector<Triple> segX;
  for (__typeof((atX).begin()) it = (atX).begin(); it != (atX).end(); it++) {
    int x = it->first;
    vector<int> &y = it->second;
    vector<bool> isCut;
    for (int j = 0, _n = ((int)y.size() - 1); j < _n; j++) {
      int id = pointID(x, y[j]);
      assert(upNode[id] > 0);
      isCut.push_back(!df.havePath(upNode[id]));
    }
    vector<int> sta, fin;
    for (int j = 0, _n = (y.size()); j < _n; j++) {
      if (j == 0 || isCut[j - 1]) sta.push_back(y[j]);
      if (j == (int)y.size() - 1 || isCut[j]) fin.push_back(y[j]);
    }
    assert(sta.size() == fin.size());
    for (int t = 0, _n = (sta.size()); t < _n; t++)
      segX.push_back(Triple(x, sta[t], fin[t]));
  }
  vector<Triple> segY;
  for (__typeof((atY).begin()) jt = (atY).begin(); jt != (atY).end(); jt++) {
    int y = jt->first;
    vector<int> &x = jt->second;
    vector<bool> isCut;
    for (int i = 0, _n = ((int)x.size() - 1); i < _n; i++) {
      int id = pointID(x[i], y);
      assert(rightNode[id] > 0);
      isCut.push_back(df.havePath(rightNode[id]));
    }
    vector<int> sta, fin;
    for (int i = 0, _n = (x.size()); i < _n; i++) {
      if (i == 0 || isCut[i - 1]) sta.push_back(x[i]);
      if (i == (int)x.size() - 1 || isCut[i]) fin.push_back(x[i]);
    }
    assert(sta.size() == fin.size());
    for (int t = 0, _n = (sta.size()); t < _n; t++)
      segY.push_back(Triple(y, sta[t], fin[t]));
  }
  printf("%d\n", (int)segY.size());
  for (__typeof((segY).begin()) it = (segY).begin(); it != (segY).end(); it++)
    printf("%d %d %d %d\n", it->b, it->a, it->c, it->a);
  printf("%d\n", (int)segX.size());
  for (__typeof((segX).begin()) it = (segX).begin(); it != (segX).end(); it++)
    printf("%d %d %d %d\n", it->a, it->b, it->a, it->c);
}
int main(void) {
  init();
  prepare();
  process();
  return 0;
}
