#include <bits/stdc++.h>
using namespace std;
vector<vector<int> > adj(2001);
int match[2001 + 1], dis[2001 + 1];
bool visited[2001 + 1], minimumVertexCover[2001], maximumIndependentSet[2001];
const int inf = 1E9;
void ResetVisited() {
  for (int i = 0; i <= 2001; ++i) {
    visited[i] = 0;
  }
}
bool BFS(vector<int> &U) {
  queue<int> Q;
  for (auto u : U) {
    if (match[u] == 2001) {
      dis[u] = 0;
      Q.push(u);
    } else {
      dis[u] = inf;
    }
  }
  dis[2001] = inf;
  while (!Q.empty()) {
    int u = Q.front();
    Q.pop();
    visited[u] = 1;
    if (dis[u] < dis[2001]) {
      for (auto v : adj[u]) {
        if (dis[match[v]] == inf) {
          visited[v] = 1;
          dis[match[v]] = 1 + dis[u];
          Q.push(match[v]);
        }
      }
    }
  }
  return (dis[2001] != inf);
}
bool DFS(int u) {
  if (u == 2001) {
    return true;
  }
  for (auto v : adj[u]) {
    if (dis[match[v]] == 1 + dis[u]) {
      if (DFS(match[v])) {
        match[v] = u;
        match[u] = v;
        return true;
      }
    }
  }
  dis[u] = inf;
  return false;
}
int HopcroftKarpMaximumMatching(vector<int> &U, vector<int> &V) {
  for (auto u : U) {
    match[u] = 2001;
  }
  for (auto v : V) {
    match[v] = 2001;
  }
  int matching = 0;
  for (ResetVisited(); BFS(U); ResetVisited()) {
    for (auto u : U) {
      if (match[u] == 2001) {
        matching += DFS(u);
      }
    }
  }
  return matching;
}
void FillMinimumVertexCover(vector<int> &U, vector<int> &V) {
  for (auto u : U) {
    minimumVertexCover[u] = (match[u] != 2001 && visited[u] == 0);
  }
  for (auto v : V) {
    minimumVertexCover[v] = (match[v] != 2001 && visited[v] == 1);
  }
}
void FillMaximumIndependentSet(vector<int> &U, vector<int> &V) {
  for (auto u : U) {
    maximumIndependentSet[u] = (match[u] == 2001 || visited[u] == 1);
  }
  for (auto v : V) {
    maximumIndependentSet[v] = (match[v] == 2001 || visited[v] == 0);
  }
}
vector<tuple<int, int, int> > segments;
vector<int> AddSegments(vector<pair<int, int> > v) {
  vector<int> V;
  sort(v.begin(), v.end());
  for (int i = 0; i < v.size() - 1; ++i) {
    if (v[i + 1].first == v[i].first) {
      V.push_back(segments.size());
      segments.push_back(make_tuple(v[i].first, v[i].second, v[i + 1].second));
    }
  }
  return V;
}
bool DoSegmentsIntersect(int i, int j) {
  int x, y1, y2, y, x1, x2;
  tie(x, y1, y2) = segments[i];
  tie(y, x1, x2) = segments[j];
  return (x1 < x && x < x2 && y1 < y && y < y2);
}
vector<tuple<int, int, int, int> > MakeAnswerSegments(
    vector<int> &V, vector<pair<int, int> > &P, bool isHorizontal) {
  vector<tuple<int, int, int> > v;
  for (auto i : V) {
    if (maximumIndependentSet[i]) {
      v.push_back(segments[i]);
    }
  }
  for (auto p : P) {
    v.push_back(make_tuple(p.first, p.second, p.second));
  }
  sort(v.begin(), v.end());
  vector<tuple<int, int, int, int> > ans;
  for (int i = 0, j; i < v.size(); i = j) {
    int x, y1, y2;
    tie(x, y1, y2) = v[i];
    for (j = i + 1; j < v.size(); ++j) {
      int nx, ny1, ny2;
      tie(nx, ny1, ny2) = v[j];
      if (nx == x && ny1 == y2) {
        y2 = ny2;
      } else {
        break;
      }
    }
    if (isHorizontal) {
      ans.push_back(make_tuple(y1, x, y2, x));
    } else {
      ans.push_back(make_tuple(x, y1, x, y2));
    }
  }
  return ans;
}
void PrintAnswerSegments(vector<tuple<int, int, int, int> > &ans) {
  printf("%lu\n", ans.size());
  for (auto t : ans) {
    int x1, y1, x2, y2;
    tie(x1, y1, x2, y2) = t;
    printf("%d %d %d %d\n", x1, y1, x2, y2);
  }
}
int main() {
  int n;
  vector<pair<int, int> > xyPoints, yxPoints;
  cin >> n;
  while (n--) {
    int x, y;
    cin >> x >> y;
    xyPoints.push_back(make_pair(x, y));
    yxPoints.push_back(make_pair(y, x));
  }
  vector<int> U = AddSegments(xyPoints);
  vector<int> V = AddSegments(yxPoints);
  for (auto u : U) {
    for (auto v : V) {
      if (DoSegmentsIntersect(u, v)) {
        adj[u].push_back(v);
      }
    }
  }
  HopcroftKarpMaximumMatching(U, V);
  FillMaximumIndependentSet(U, V);
  vector<tuple<int, int, int, int> > horizontalSegments =
      MakeAnswerSegments(V, yxPoints, 1);
  vector<tuple<int, int, int, int> > verticalSegments =
      MakeAnswerSegments(U, xyPoints, 0);
  PrintAnswerSegments(horizontalSegments);
  PrintAnswerSegments(verticalSegments);
  return 0;
}
