class Report implements Runnable {

    private final BufferedWriter reportWriter;

    Report(BufferedWriter reportWriter) {
      this.reportWriter = reportWriter;
    }

    @Override
    public void run() {<FILL_FUNCTION_BODY>}
  }

      if (reportWriter == null) {
        return;
      }
      try {
        StringBuilder report = new StringBuilder();
        report.append("Overall report:\n\n");

        SuggestionChangesExperiment best = null;
        int bestId = -1;
        double bestAccuracy = 0.0;

        int experimentId = 0;
        for (SuggestionChangesExperiment experiment : experiments) {
          experimentId++;
          int correct = correctSuggestions.getOrDefault(experiment, 0);
          int score = suggestionPosSum.getOrDefault(experiment, 0);
          int notFound = notFoundSuggestions.getOrDefault(experiment, 0);
          int total = numSamples.getOrDefault(experiment, 0);
          double accuracy = (double) correct / total * 100.0;
          double speed = (double) textSize.getOrDefault(experiment, 0) /
            computationTime.getOrDefault(experiment, 0L) * 1000.0;
          if (accuracy > bestAccuracy) {
            best = experiment;
            bestAccuracy = accuracy;
            bestId = experimentId;
          }
          report.append(String.format("Experiment #%d (%s): %d / %d correct suggestions -> %f%% accuracy;" +
            " score (less = better): %d; not found: %d; processed %f chars/second.%n",
            experimentId, experiment, correct, total, accuracy, score, notFound, speed));
        }

        report.append(String.format("%nBest experiment: #%d (%s) @ %f%% accuracy%n", bestId, best, bestAccuracy));

        for (SuggestionChangesDataset dataset : config.datasets) {
          report.append(String.format("%nReport for dataset: %s%n", dataset.name));
          best = null;
          bestAccuracy = 0f;
          bestId = -1;

          experimentId = 0;
          for (SuggestionChangesExperiment experiment : experiments) {
            experimentId++;
            Pair<SuggestionChangesExperiment, SuggestionChangesDataset> source = Pair.of(experiment, dataset);
            int correct = datasetCorrectSuggestions.getOrDefault(source, 0);
            int score = datasetSuggestionPosSum.getOrDefault(source, 0);
            int notFound = datasetNotFoundSuggestions.getOrDefault(source, 0);
            int total = datasetNumSamples.getOrDefault(source, 0);
            double accuracy = (double) correct / total * 100.0;
            double speed = (double) datasetTextSize.getOrDefault(source, 0) /
              datasetComputationTime.getOrDefault(source, 0L) * 1000.0;
            if (accuracy > bestAccuracy) {
              best = experiment;
              bestAccuracy = accuracy;
              bestId = experimentId;
            }
            report.append(String.format("Experiment #%d (%s): %d / %d correct suggestions-> %f%% accuracy;" +
              " score (less = better): %d; not found: %d; processed %f chars/second.%n",
              experimentId, experiment, correct, total, accuracy, score, notFound, speed));
          }
          report.append(String.format("%nBest experiment: #%d (%s) @ %f%% accuracy%n", bestId, best, bestAccuracy));
        }
        System.out.println(report);
        reportWriter.write(report.toString());
        reportWriter.close();
      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    
<no_super_class>