#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9 + 7;
const long long INFL = 1e18 + 123;
const double PI = atan2(0, -1);
mt19937 tw(960172);
long long rnd(long long x, long long y) {
  static uniform_int_distribution<long long> d;
  return d(tw) % (y - x + 1) + x;
}
struct edge {
  int f, c;
  edge() : f(0), c(0) {}
  edge(int _c) : f(0), c(_c) {}
};
vector<edge> edges;
vector<vector<pair<int, int>>> graph;
int add_node() {
  graph.push_back({});
  return ((int)(graph).size()) - 1;
}
void add_edge(int a, int b, int c) {
  graph[a].push_back({b, ((int)(edges).size())});
  edges.push_back(edge(c));
  graph[b].push_back({a, ((int)(edges).size())});
  edges.push_back(edge(0));
}
vector<int> qu;
vector<int> vcnt;
vector<int> dist;
int build_layers(int s, int t) {
  int l = 0, r = 0;
  qu[r++] = s;
  fill(dist.begin(), dist.end(), INF);
  dist[s] = 0;
  fill(vcnt.begin(), vcnt.end(), 0);
  while (l < r) {
    int v = qu[l++];
    for (pair<int, int> to : graph[v]) {
      if (edges[to.second].f < edges[to.second].c &&
          dist[to.first] > dist[v] + 1) {
        dist[to.first] = dist[v] + 1;
        qu[r++] = to.first;
      }
    }
  }
  if (dist[t] == INF) {
    return 0;
  }
  return 1;
}
int push_flow(int v, int t, int f) {
  if (v == t) {
    return f;
  }
  while (vcnt[v] < ((int)(graph[v]).size())) {
    auto& to = graph[v][vcnt[v]];
    if (edges[to.second].f < edges[to.second].c &&
        dist[to.first] == dist[v] + 1) {
      int tmp = push_flow(to.first, t,
                          min(f, edges[to.second].c - edges[to.second].f));
      if (tmp) {
        edges[to.second].f += tmp;
        edges[to.second ^ 1].f -= tmp;
        return tmp;
      }
    }
    vcnt[v]++;
  }
  return 0;
}
void solve() {
  int n;
  cin >> n;
  map<int, vector<pair<int, int>>> by_x, by_y;
  vector<pair<int, int>> coords;
  for (int i = 0; i < n; ++i) {
    int x, y;
    cin >> x >> y;
    coords.push_back({x, y});
    by_x[x].push_back({y, i});
    by_y[y].push_back({x, i});
  }
  vector<pair<int, int>> hor_segs, ver_segs;
  for (auto& p : by_x) {
    sort(p.second.begin(), p.second.end());
    for (int i = 0; i < ((int)(p.second).size()) - 1; ++i) {
      ver_segs.push_back({p.second[i].second, p.second[i + 1].second});
    }
  }
  for (auto& p : by_y) {
    sort(p.second.begin(), p.second.end());
    for (int i = 0; i < ((int)(p.second).size()) - 1; ++i) {
      hor_segs.push_back({p.second[i].second, p.second[i + 1].second});
    }
  }
  int s = add_node();
  int t = add_node();
  vector<int> left_nodes, right_nodes;
  for (int i = 0; i < ((int)(ver_segs).size()); ++i) {
    left_nodes.push_back(add_node());
    add_edge(s, left_nodes.back(), 1);
  }
  for (int i = 0; i < ((int)(hor_segs).size()); ++i) {
    right_nodes.push_back(add_node());
    add_edge(right_nodes.back(), t, 1);
  }
  for (int i = 0; i < ((int)(ver_segs).size()); ++i) {
    for (int j = 0; j < ((int)(hor_segs).size()); ++j) {
      int a, b, c, d;
      tie(a, b) = ver_segs[i];
      tie(c, d) = hor_segs[j];
      if (coords[c].first < coords[a].first &&
          coords[a].first < coords[d].first &&
          coords[a].second < coords[c].second &&
          coords[c].second < coords[b].second) {
        add_edge(left_nodes[i], right_nodes[j], 1);
      }
    }
  }
  int f = 0;
  qu = dist = vcnt = vector<int>(((int)(graph).size()));
  while (true) {
    if (!build_layers(s, t)) {
      break;
    }
    while (true) {
      int tmp = push_flow(s, t, INF);
      if (!tmp) {
        break;
      }
      f += tmp;
    }
  }
  queue<int> qu;
  vector<bool> used(((int)(graph).size()));
  for (pair<int, int> to : graph[s]) {
    if (!edges[to.second].f) {
      qu.push(to.first);
      used[to.first] = true;
    }
  }
  while (((int)(qu).size())) {
    int v = qu.front();
    qu.pop();
    for (pair<int, int> to : graph[v]) {
      if (to.first != s && to.first != t &&
          edges[to.second].f < edges[to.second].c) {
        if (!used[to.first]) {
          used[to.first] = true;
          qu.push(to.first);
        }
      }
    }
  }
  set<pair<int, int>> take_ver, take_hor;
  for (int i = 2; i < ((int)(graph).size()); ++i) {
    if (i < 2 + ((int)(left_nodes).size())) {
      if (used[i]) {
        take_ver.insert(ver_segs[i - 2]);
      }
    } else {
      if (!used[i]) {
        take_hor.insert(hor_segs[i - 2 - ((int)(left_nodes).size())]);
      }
    }
  }
  vector<pair<pair<int, int>, pair<int, int>>> ans;
  for (auto& p : by_y) {
    pair<int, int> from = {p.second.front().first, p.first};
    for (int i = 0; i < ((int)(p.second).size()) - 1; ++i) {
      if (!take_hor.count({p.second[i].second, p.second[i + 1].second})) {
        ans.push_back({from, {p.second[i].first, p.first}});
        from = {p.second[i + 1].first, p.first};
      }
    }
    ans.push_back({from, {p.second.back().first, p.first}});
  }
  cout << ((int)(ans).size()) << "\n";
  for (auto p : ans) {
    cout << p.first.first << " " << p.first.second << " " << p.second.first
         << " " << p.second.second << "\n";
  }
  ans = {};
  for (auto& p : by_x) {
    pair<int, int> from = {p.first, p.second.front().first};
    for (int i = 0; i < ((int)(p.second).size()) - 1; ++i) {
      if (!take_ver.count({p.second[i].second, p.second[i + 1].second})) {
        ans.push_back({from, {p.first, p.second[i].first}});
        from = {p.first, p.second[i + 1].first};
      }
    }
    ans.push_back({from, {p.first, p.second.back().first}});
  }
  cout << ((int)(ans).size()) << "\n";
  for (auto p : ans) {
    cout << p.first.first << " " << p.first.second << " " << p.second.first
         << " " << p.second.second << "\n";
  }
}
int main() {
  cerr << fixed << setprecision(15);
  cout << fixed << setprecision(15);
  ios::sync_with_stdio(false);
  int tests = 1;
  for (int it = 1; it <= tests; ++it) {
    solve();
  }
  return 0;
}
