Problem: The second semester starts at the University of Pavlopolis. After vacation in Vičkopolis Noora needs to return to Pavlopolis and continue her study.

Sometimes (or quite often) there are teachers who do not like you. Incidentally Noora also has one such teacher. His name is Yury Dmitrievich and he teaches graph theory. Yury Dmitrievich doesn't like Noora, so he always gives the girl the most difficult tasks. So it happened this time.

The teacher gives Noora a tree with n vertices. Vertices are numbered with integers from 1 to n. The length of all the edges of this tree is 1. Noora chooses a set of simple paths that pairwise don't intersect in edges. However each vertex should belong to at least one of the selected path.

For each of the selected paths, the following is done:

  1. We choose exactly one edge (u, v) that belongs to the path. 
  2. On the selected edge (u, v) there is a point at some selected distance x from the vertex u and at distance 1 - x from vertex v. But the distance x chosen by Noora arbitrarily, i. e. it can be different for different edges. 
  3. One of the vertices u or v is selected. The point will start moving to the selected vertex. 



Let us explain how the point moves by example. Suppose that the path consists of two edges (v1, v2) and (v2, v3), the point initially stands on the edge (v1, v2) and begins its movement to the vertex v1. Then the point will reach v1, then "turn around", because the end of the path was reached, further it will move in another direction to vertex v2, then to vertex v3, then "turn around" again, then move to v2 and so on. The speed of the points is 1 edge per second. For example, for 0.5 second the point moves to the length of the half of an edge.

A stopwatch is placed at each vertex of the tree. The time that the stopwatches indicate at start time is 0 seconds. Then at the starting moment of time, all points simultaneously start moving from the selected positions to selected directions along the selected paths, and stopwatches are simultaneously started. When one of the points reaches the vertex v, the stopwatch at the vertex v is automatically reset, i.e. it starts counting the time from zero.

Denote by resv the maximal time that the stopwatch at the vertex v will show if the point movement continues infinitely. Noora is asked to select paths and points on them so that res1 is as minimal as possible. If there are several solutions to do this, it is necessary to minimize res2, then res3, res4, ..., resn.

Help Noora complete the teacher's task.

For the better understanding of the statement, see the explanation for the example.

Input

The first line contains single integer n (2 ≤ n ≤ 100) — number of vertices in the given tree.

Each of next n - 1 lines contains two integers u and v (1 ≤ u, v ≤ n, u ≠ v) — vertices connected by an edge.

Guaranteed that input defines a valid tree.

Output

In the first line print single integer paths — number of paths you want to choose.

In the next paths lines print path's descriptions:

  1. Single integer len — number of edges in the current path. 
  2. len integers — indices of the edges in the path. The edges are numbered from 1 to n - 1 in order they are given in input. 
  3. Two integers u and v — means that you put point on the edge between vertices u and v (obviously the edge should belong to the path) and a point will start moving to the vertex v. Note that order of printing of the edge's ends is important. For example if you print "1 2" (without quotes), then point will start moving to vertex 2; but if you print "2 1" (without quotes), then point will start moving to vertex 1. 
  4. Single real number x (0 ≤ x ≤ 1) — distance between point and vertex u (the same vertex that you print first in the third paragraph). 

Scoring

Judge system will generate array res using the output data provided by the participant. Also system will generate array resOptimal by the jury answer. Your answer will be accepted if only for each i (1 ≤ i ≤ n) the following is satisfied: <image>.

Example

Input

3
1 2
2 3


Output

2
1 1 1 2 0.6666666666
1 2 2 3 0.6666666666

Note

Consider an example.

In starting moment of time points are located as following:

<image>

The first path is highlighted in red, the second in blue, green circles represent chosen points, and brown numbers inside vertices — current time at stopwatch. Purple arrows represent direction in which points will move.

In 0.(3) seconds points will be located in following way (before stopwatch reset):

<image>

After stopwatch reset:

<image>

In 1.0 second after the start of moving:

<image>

In 1.(3) seconds after the start of moving (after stopwatch reset):

<image>

Finally, in 2 seconds after the start of moving points return to their initial positions.

<image>

This process will continue infinitely.

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
struct LevelAncestor {
  int N;
  vector<int> P, L;
  vector<int> pathId;
  vector<vector<int>> paths;
  LevelAncestor(const vector<int> &P)
      : N(P.size()), P(P), L(P.size(), -1), pathId(N, -1) {
    vector<int> isLeaf(P.size(), 1);
    vector<int> taken(N, 0);
    stack<int> S;
    for (int u = 0; u < N; ++u) {
      int cu = u;
      while (cu != -1 && L[cu] == -1) {
        S.push(cu);
        cu = P[cu];
      }
      if (cu == -1) {
        L[S.top()] = 0;
        S.pop();
      }
      while (S.size() > 0) {
        isLeaf[P[S.top()]] = 0;
        L[S.top()] = L[P[S.top()]] + 1;
        S.pop();
      }
    }
    vector<vector<int>> leaves(N);
    for (int u = 0; u < N; ++u) {
      if (isLeaf[u]) leaves[L[u]].push_back(u);
    }
    for (int i = N - 1; i >= 0; --i) {
      for (int u : leaves[i]) {
        paths.push_back(vector<int>());
        while (u != -1 && !taken[u]) {
          paths.back().push_back(u);
          pathId[u] = paths.size() - 1;
          taken[u] = 1;
          u = P[u];
        }
      }
    }
  }
};
struct Fibo {
  long long b, c;
  static Fibo one() { return (Fibo){1, 0}; }
  Fibo operator*(const Fibo &F) const {
    Fibo r;
    r.b = ((b + c) * F.b + b * F.c) % 1000000007;
    r.c = (b * F.b + c * F.c) % 1000000007;
    return r;
  }
};
using namespace std;
struct SegmentNode {
  int sz;
  bool HasCarry;
  SegmentNode() {
    this->sz = 1;
    HasCarry = 0;
  }
  void join(const SegmentNode &l, const SegmentNode &r) { sz = l.sz + r.sz; }
  void update() { HasCarry = 1; }
  void clear() { HasCarry = 0; }
};
template <class T>
struct SegmentTree {
  T *V;
  int N;
  SegmentTree(int N) {
    this->V = new T[4 * N];
    this->N = N;
  }
  void create(const vector<typename T::Init> &VEC, int n = 1, int b = 0,
              int e = -1) {
    if (e == -1) e = N - 1;
    if (b == e) {
      V[n] = T(VEC[b]);
    } else {
      create(VEC, 2 * n, b, (e + b) / 2);
      create(VEC, 2 * n + 1, (e + b) / 2 + 1, e);
      V[n] = V[2 * n] + V[2 * n + 1];
    }
  }
  T query(int i, int j, int n = 1, int b = 0, int e = -1) {
    if (e == -1) e = N - 1;
    if (i <= b && e <= j)
      return V[n];
    else {
      if (V[n].HasCarry) {
        V[2 * n].update(V[n].carry);
        V[2 * n + 1].update(V[n].carry);
        V[n].clear();
      }
      int mid = (b + e) / 2;
      if (i > mid) return query(i, j, 2 * n + 1, mid + 1, e);
      if (j <= mid) return query(i, j, 2 * n, b, mid);
      return query(i, j, 2 * n, b, mid) + query(i, j, 2 * n + 1, mid + 1, e);
    }
  }
  void update(int i, int j, int v, int n = 1, int b = 0, int e = -1) {
    if (e == -1) e = N - 1;
    if (i <= b && e <= j) {
      V[n].update(v);
    } else if (i > e || j < b)
      return;
    else {
      if (V[n].HasCarry) {
        V[2 * n].update(V[n].carry);
        V[2 * n + 1].update(V[n].carry);
        V[n].clear();
      }
      int mid = (b + e) / 2;
      update(i, j, v, 2 * n, b, mid);
      update(i, j, v, 2 * n + 1, mid + 1, e);
      V[n] = V[2 * n] + V[2 * n + 1];
    }
  }
  int findLastIndex(bool (*isOk)(T)) {
    int n = 1;
    T acum;
    acum.sz = 0;
    while (V[n].sz > 1) {
      int l = 2 * n, r = 2 * n + 1;
      T newAcum = (acum.sz == 0 ? V[r] : (V[r] + acum));
      if (isOk(newAcum)) {
        n = r;
      } else {
        acum = newAcum;
        n = l;
      }
    }
    return N - acum.sz - 1;
  }
};
struct MinVal : SegmentNode {
  struct Init {
    int val;
    Init(int val = 0) : val(val) {}
  };
  int open, close;
  int carry;
  MinVal() : SegmentNode() {
    open = 0;
    close = 0;
    carry = 0;
  }
  MinVal(Init n) : SegmentNode() {
    open = (n.val == 1);
    close = (n.val == 2);
    carry = 0;
  }
  MinVal operator+(const MinVal &N) const {
    MinVal ret;
    ret.join(*this, N);
    int cancel = min(open, N.close);
    ret.open = open + N.open - cancel;
    ret.close = close + N.close - cancel;
    return ret;
  }
  void update(int val) {
    SegmentNode::update();
    if (val == 1) {
      close = 0;
      open = sz;
    } else if (val == 2) {
      close = sz;
      open = 0;
    } else {
      open = 0;
      close = 0;
    }
  }
};
double invert(double d) {
  if (d >= 0) {
    return d - 1;
  } else {
    return 1 + d;
  }
}
double wrap(double d) {
  while (d >= 1) {
    d -= 2;
  }
  return d;
}
void dfs(int u, vector<vector<int>> &adj, vector<vector<int>> &edg,
         double sh = 0, int p = -1, int eid = -1) {
  int ch = adj[u].size();
  double phase = 2.0 / ch;
  if (p != -1) {
    if (sh <= 0) {
      printf("%d %d %d %d %0.10lf\n", 1, eid, u + 1, p + 1, abs(sh));
    } else {
      printf("%d %d %d %d %0.10lf\n", 1, eid, p + 1, u + 1, abs(invert(sh)));
    }
  }
  for (int i = 0; i < adj[u].size(); ++i) {
    int id = edg[u][i];
    int v = adj[u][i];
    if (v == p) continue;
    sh = wrap(sh + phase);
    dfs(v, adj, edg, invert(sh), u, id);
  }
}
int main() {
  int N;
  cin >> N;
  vector<vector<int>> adj(N);
  vector<vector<int>> edg(N);
  for (int i = 0; i < N - 1; ++i) {
    int u, v;
    cin >> u >> v;
    u--;
    v--;
    adj[u].push_back(v);
    adj[v].push_back(u);
    edg[u].push_back(i + 1);
    edg[v].push_back(i + 1);
  }
  cout << N - 1 << endl;
  dfs(0, adj, edg);
}