code: public String summary(Map<String, List<File>> result, Path outDir, String dist, long duration,
        String... extraInfo) {
      StringBuilder buffer = new StringBuilder();
  
      buffer.append("Summary:\n");
      long seconds = Duration.ofMillis(duration).getSeconds();
      String took = seconds > 0 ? seconds + "s" : duration + "ms";
      buffer.append("Pipeline: ").append(pipeline(dist)).append("\n");
      buffer.append("Time: ").append(took).append("\n");
      buffer.append("Output: ").append(outDir).append("\n");
      Stream.of(extraInfo).forEach(line -> buffer.append(line).append("\n"));
      int w1 = result.keySet().stream()
          .map(it -> it.length() + 2)
          .max(Integer::compareTo)
          .orElse(0);
      int mw1 = Math.max(w1, "Fileset".length() + 2);
      int w2 = result.values().stream()
          .flatMap(List::stream)
          .map(file -> outDir.relativize(file.toPath()).toString())
          .map(String::length)
          .max(Integer::compareTo)
          .orElse(0);
      buffer.append(format(w1, w2, "Fileset", "Output", "Size"));
      result.forEach((fileset, files) -> {
        if (files.size() > 0) {
          // Head
          buffer.append(format(mw1, w2, "  " + fileset, "", ""));
          // Tail
          files.forEach(file -> buffer.append(format(mw1, w2, "", outDir.relativize(file.toPath()),
              AssetCompiler.humanReadableByteCount(file.length()))));
        }
      });
      return buffer.toString();
    }
docs: Print a summary of the given results.
  
  @param result Compilation result.
  @param outDir Output directory.
  @param dist Distribution (dev or prod).
  @param duration Execution time in millis.
  @param extraInfo Additional information.
  @return Summary.