Problem: On the surface of a newly discovered planet, which we model by a plane, explorers found remains of two different civilizations in various locations. They would like to learn more about those civilizations and to explore the area they need to build roads between some of locations. But as always, there are some restrictions: 

  1. Every two locations of the same civilization are connected by a unique path of roads 
  2. No two locations from different civilizations may have road between them (explorers don't want to accidentally mix civilizations they are currently exploring) 
  3. Roads must be straight line segments
  4. Since intersections are expensive to build, they don't want any two roads to intersect (that is, only common point for any two roads may be at some of locations) 



Obviously all locations are different points in the plane, but explorers found out one more interesting information that may help you – no three locations lie on the same line!

Help explorers and find a solution for their problem, or report it is impossible.

Input

In the first line, integer n (1 ≤ n ≤ 10^3) - the number of locations discovered.

In next n lines, three integers x, y, c (0 ≤ x, y ≤ 10^4, c ∈ \{0, 1\}) - coordinates of the location and number of civilization it belongs to.

Output

In first line print number of roads that should be built.

In the following lines print all pairs of locations (their 0-based indices) that should be connected with a road.

If it is not possible to build roads such that all restrictions are met, print "Impossible". You should not print the quotation marks.

Example

Input

5
0 0 1
1 0 0
0 1 0
1 1 1
3 2 0


Output

3
1 4
4 2
3 0

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
struct UnionFindSet {
  vector<int> f;
  int n;
  UnionFindSet(int n) : f(n) { clear(n); }
  void clear(int n) {
    this->n = n;
    for (int i = 0; i < n; i++) {
      f[i] = i;
    }
  }
  int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
  void Union(int x, int y) { f[find(y)] = find(x); }
};
using db = double;
const db EPS = 1e-6;
const db PI = acos(-1.0);
int sgn(db x) {
  if (x < -EPS) return -1;
  return x > EPS;
}
int cmp(db a, db b) { return sgn(a - b); }
struct db_less : public binary_function<db, db, bool> {
  db_less(db eps = EPS) : eps(eps) {}
  bool operator()(const db &a, const db &b) const { return cmp(a, b) == -1; }
  double eps;
};
db dtor(db d) { return d * PI / 180; }
db rtod(db r) { return r * 180 / PI; }
struct Point2 {
  db x, y;
  db angle;
  int color;
  int id;
  Point2() {}
  Point2(db x, db y) : x(x), y(y) {}
  using p2 = Point2;
  p2 operator+(const p2 b) const { return p2(x + b.x, y + b.y); }
  p2 operator-(const p2 b) const { return p2(x - b.x, y - b.y); }
  p2 operator*(const db k) const { return p2(x * k, y * k); }
  p2 operator/(const db k) const { return p2(x / k, y / k); }
  bool operator<(const p2 b) const {
    if (cmp(x, b.x) != 0) return cmp(x, b.x) < 0;
    return cmp(y, b.y) < 0;
  }
  bool operator==(const p2 b) const {
    return cmp(x, b.x) == 0 && cmp(y, b.y) == 0;
  }
  bool operator>(const p2 b) const { return !operator<(b) && !operator==(b); }
  db norm2() { return x * x + y * y; }
  db norm() { return sqrt(norm2()); }
  p2 unit() { return (*this) / norm(); }
  p2 rot90() { return p2(-y, x); }
  p2 rotate(db a) {
    return p2(x * cos(a) - y * sin(a), x * sin(a) + y * cos(a));
  }
};
using p2 = Point2;
using v2 = p2;
istream &operator>>(istream &in, p2 &p) { return (in >> p.x >> p.y); }
ostream &operator<<(ostream &out, p2 &p) {
  return (out << '(' << p.x << ',' << p.y << ')');
}
struct Hashp2 {
  size_t operator()(const p2 &p) const {
    return (hash<int>()((int)(p.x * 1e6)) << 13) ^
           hash<int>()((int)(p.y * 1e6));
  }
};
db dis(p2 a, p2 b) { return (a - b).norm(); }
db dot(p2 a, p2 b) { return a.x * b.x + a.y * b.y; }
db det(p2 a, p2 b) { return a.x * b.y - a.y * b.x; }
p2 point_proj_line(p2 p, p2 a, p2 b) {
  return a + (b - a) * dot(p - a, b - a) / dot(b - a, b - a);
}
db rad(p2 a, p2 b) { return atan2(det(a, b), dot(a, b)); }
struct Line2 {
  p2 a, b;
  Line2() {}
  Line2(p2 a, p2 b) : a(a), b(b) {}
  using l2 = Line2;
};
using l2 = Line2;
inline bool is_range_cross(db a1, db a2, db b1, db b2) {
  return cmp(max(min(a1, a2), min(b1, b2)), min(max(a1, a2), max(b1, b2))) <= 1;
}
inline bool is_rect_cross(const p2 &a1, const p2 &a2, const p2 &b1,
                          const p2 &b2) {
  return is_range_cross(a1.x, a2.x, b1.x, b2.x) &&
         is_range_cross(a1.y, a2.y, b1.y, b2.y);
}
inline bool is_same_side(l2 l, p2 a, p2 b) {
  return sgn(det(l.b - l.a, a - l.a)) * sgn(det(l.b - l.a, b - l.a)) <= 0;
}
inline bool is_segment_cross(l2 a, l2 b) {
  return is_rect_cross(a.a, a.b, b.a, b.b) && is_same_side(a, b.a, b.b) &&
         is_same_side(b, a.a, a.b);
}
p2 intersection(l2 a, l2 b) {
  db t = det(b.b - b.a, a.a - b.a) / det(a.b - a.a, b.b - b.a);
  return a.a + (a.b - a.a) * t;
}
using Polygon = vector<p2>;
db area(Polygon p) {
  db s = 0;
  for (int i = 0; i < (int)p.size(); i++) s += det(p[i], p[(i + 1) % p.size()]);
  return s / 2;
}
bool is_in(p2 a, Polygon p) {
  int side = sgn(det(p[0] - p.back(), a - p.back()));
  for (int i = 0; i < (int)p.size() - 1; i++)
    if (side != sgn(det(p[i + 1] - p[i], a - p[i]))) return false;
  return true;
}
Polygon convex(Polygon p) {
  int k = 0;
  for (int i = 1; i < (int)p.size(); i++)
    if (p[i] < p[k]) k = i;
  swap(p[k], p[0]);
  auto cmp = [&](p2 a, p2 b) { return sgn(det(a - p[0], b - p[0])) > 0; };
  sort(p.begin() + 1, p.end(), cmp);
  Polygon res;
  res.push_back(p[0]);
  for (int i = 1; i < (int)p.size(); i++) {
    while (res.size() >= 2 &&
           sgn(det(res.back() - *(res.rbegin() + 1), p[i] - res.back())) <= 0)
      res.pop_back();
    res.push_back(p[i]);
  }
  return res;
}
int main() {
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  int n;
  cin >> n;
  vector<p2> pts(n);
  for (int i = 0; i < n; i++) {
    cin >> pts[i].x >> pts[i].y >> pts[i].color;
    pts[i].id = i;
  }
  Polygon hull = convex(pts);
  int cnt = 0;
  for (int i = 0; i < (int)hull.size() - 1; i++)
    cnt += hull[i].color ^ hull[i + 1].color;
  cnt += hull.back().color ^ hull[0].color;
  if (cnt > 2) {
    cout << "Impossible";
    return 0;
  }
  vector<pair<int, int>> ans;
  UnionFindSet cpnt(n);
  auto combine = [&](int u, int v) {
    if (cpnt.find(u) != cpnt.find(v)) {
      ans.emplace_back(u, v);
      cpnt.Union(u, v);
    }
  };
  auto get_st = [&](vector<p2> p) {
    sort(p.begin(), p.end());
    for (int i = 0; i < (int)p.size() - 1; i++) combine(p[i].id, p[i + 1].id);
  };
  function<void(Polygon, vector<p2>)> solve = [&](Polygon p, vector<p2> range) {
    int strange_color = p[0].color;
    vector<p2> inner;
    int strange_id = -1;
    for (auto &pt : range) {
      if (pt.id == p[0].id || pt.id == p[1].id || pt.id == p[2].id) continue;
      if (!is_in(pt, p)) continue;
      inner.push_back(pt);
      if (pt.color == strange_color) {
        strange_id = pt.id;
      }
    }
    if (strange_id != -1) {
      inner.push_back(p[0]);
      inner.push_back(p[1]);
      inner.push_back(p[2]);
      solve({pts[strange_id], p[1], p[2]}, inner);
      solve({p[1], p[0], pts[strange_id]}, inner);
      solve({p[2], p[0], pts[strange_id]}, inner);
    } else {
      inner.push_back(p[1]);
      inner.push_back(p[2]);
      get_st(inner);
    }
  };
  if (cnt == 0) {
    int strange_color = 1 - hull[0].color;
    vector<int> is_on_hull(n);
    for (auto &p : hull) is_on_hull[p.id] = 1;
    int strange_id = -1;
    for (auto &pt : pts) {
      if (is_on_hull[pt.id]) continue;
      if (pt.color == strange_color) {
        strange_id = pt.id;
        break;
      }
    }
    if (strange_id != -1) {
      for (int i = 0; i < (int)hull.size() - 1; i++)
        solve({pts[strange_id], hull[i], hull[i + 1]}, pts);
      solve({pts[strange_id], hull.back(), hull[0]}, pts);
    } else {
      get_st(pts);
    }
  } else {
    int start = 0;
    array<vector<p2>, 2> half_hull;
    for (int i = 1; i < (int)hull.size(); i++) {
      if (hull[i].color != hull[i - 1].color) {
        start = i;
        break;
      }
    }
    for (int i = 0; i < (int)hull.size(); i++) {
      p2 pt = hull[(start + i) % hull.size()];
      half_hull[pt.color].push_back(pt);
    }
    for (int i = 0; i < (int)half_hull[0].size() - 1; i++)
      solve({half_hull[1][0], half_hull[0][i], half_hull[0][i + 1]}, pts);
    for (int i = 0; i < (int)half_hull[1].size() - 1; i++)
      solve({half_hull[0][0], half_hull[1][i], half_hull[1][i + 1]}, pts);
  }
  cout << ans.size() << endl;
  for (auto &e : ans) {
    int u = e.first, v = e.second;
    cout << u << " " << v << endl;
  }
}