private void writeBuckets(Writer w, ImmutableSortedMap<Integer, Bucket> buckets)
            throws IOException {

          for (Entry<Integer, Bucket> entry : buckets.entrySet()) {
            Integer bucketIndex = entry.getKey();
            Bucket bucket = entry.getValue();
            print(w, TreeNode.BUCKET.name());
            print(w, "\t");
            print(w, bucketIndex.toString());
            print(w, "\t");
            print(w, bucket.id().toString());
            print(w, "\t");
            Envelope env = new Envelope();
            env.setToNull();
            bucket.expand(env);
            writeEnvelope(w, env);
            println(w);
          }
        }
        @Override
        protected RevTree read(ObjectId id, BufferedReader reader, TYPE type) throws IOException {
          Preconditions.checkArgument(TYPE.TREE.equals(type), "Wrong type: %s", type.name());
          Builder<Node> features = ImmutableList.builder();
          Builder<Node> trees = ImmutableList.builder();
          TreeMap<Integer, Bucket> subtrees = Maps.newTreeMap();
          long size = Long.parseLong(parseLine(requireLine(reader), "size"));
          int numTrees = Integer.parseInt(parseLine(requireLine(reader), "numtrees"));
          String line;
          while ((line = reader.readLine()) != null) {
            Preconditions.checkArgument(!line.isEmpty(), "Empty tree element definition");
            ArrayList<String> tokens = Lists.newArrayList(Splitter.on('\t').split(line));
            String nodeType = tokens.get(0);
            if (nodeType.equals(TextWriter.TreeNode.REF.name())) {
              Node entryRef = parseNodeLine(line);
              if (entryRef.getType().equals(TYPE.TREE)) {
                trees.add(entryRef);
              } else {
                features.add(entryRef);
              }
            } else if (nodeType.equals(TextWriter.TreeNode.BUCKET.name())) {
              Preconditions.checkArgument(tokens.size() == 4, "Wrong bucket definition: %s", line);
              Integer idx = Integer.parseInt(tokens.get(1));
              ObjectId bucketId = ObjectId.valueOf(tokens.get(2));
              Envelope bounds = parseBBox(tokens.get(3));
              Bucket bucket = Bucket.create(bucketId, bounds);
              subtrees.put(idx, bucket);
            } else {
              throw new IllegalArgumentException("Wrong tree element definition: " + line);
            }
          }

          RevTree tree;
          if (subtrees.isEmpty()) {
            tree = RevTreeImpl.createLeafTree(id, size, features.build(), trees.build());
          } else {
            tree = RevTreeImpl.createNodeTree(id, size, numTrees, subtrees);
          }
          return tree;
        }