private static void validateMaxLine(Map<Integer, Integer> m, InputFile inputFile) {
    int maxLine = inputFile.lines();

    for (int l : m.keySet()) {
      if (l > maxLine) {
        throw new IllegalStateException(
            String.format(
                "Can't create measure for line %d for file '%s' with %d lines",
                l, inputFile.absolutePath(), maxLine));
      }
    }
  }
  @Override
  public synchronized void blameResult(InputFile file, List<BlameLine> lines) {
    Preconditions.checkNotNull(file);
    Preconditions.checkNotNull(lines);
    Preconditions.checkArgument(
        allFilesToBlame.contains(file),
        "It was not expected to blame file %s",
        file.relativePath());

    if (lines.size() != file.lines()) {
      LOG.debug(
          "Ignoring blame result since provider returned {} blame lines but file {} has {} lines",
          lines.size(),
          file.relativePath(),
          file.lines());
      return;
    }

    BatchComponent batchComponent = componentCache.get(file);
    Builder scmBuilder = BatchReport.Changesets.newBuilder();
    scmBuilder.setComponentRef(batchComponent.batchId());
    Map<String, Integer> changesetsIdByRevision = new HashMap<>();

    int lineId = 1;
    for (BlameLine line : lines) {
      validateLine(line, lineId, file);
      Integer changesetId = changesetsIdByRevision.get(line.revision());
      if (changesetId == null) {
        addChangeset(scmBuilder, line);
        changesetId = scmBuilder.getChangesetCount() - 1;
        changesetsIdByRevision.put(line.revision(), changesetId);
      }
      scmBuilder.addChangesetIndexByLine(changesetId);
      lineId++;
    }
    writer.writeComponentChangesets(scmBuilder.build());
    allFilesToBlame.remove(file);
    count++;
    progressReport.message(count + "/" + total + " files analyzed");
  }