@Override
  public void analyzeResults(final Flux<PushNotificationExperimentSample<DeviceLastSeenState>> samples) {
    final Map<Population, Map<Outcome, Integer>> contingencyTable = new EnumMap<>(Population.class);

    samples.doOnNext(sample ->
            contingencyTable.computeIfAbsent(getPopulation(sample), ignored -> new EnumMap<>(Outcome.class))
                .merge(getOutcome(sample), 1, Integer::sum))
        .then()
        .block();

    final StringBuilder reportBuilder = new StringBuilder("population,deleted,uninstalled,reactivated,unchanged\n");

    for (final Population population : Population.values()) {
      final Map<Outcome, Integer> countsByOutcome = contingencyTable.getOrDefault(population, Collections.emptyMap());

      reportBuilder.append(population.name());
      reportBuilder.append(",");
      reportBuilder.append(countsByOutcome.getOrDefault(Outcome.DELETED, 0));
      reportBuilder.append(",");
      reportBuilder.append(countsByOutcome.getOrDefault(Outcome.UNINSTALLED, 0));
      reportBuilder.append(",");
      reportBuilder.append(countsByOutcome.getOrDefault(Outcome.REACTIVATED, 0));
      reportBuilder.append(",");
      reportBuilder.append(countsByOutcome.getOrDefault(Outcome.UNCHANGED, 0));
      reportBuilder.append("\n");
    }

    log.info(reportBuilder.toString());
  }
@Test
  void analyzeResults() {
    assertDoesNotThrow(() -> getExperiment().analyzeResults(
        Flux.just(new PushNotificationExperimentSample<>(UUID.randomUUID(), Device.PRIMARY_ID, true,
            new DeviceLastSeenState(true, 0, true, 0, DeviceLastSeenState.PushTokenType.APNS),
            new DeviceLastSeenState(true, 0, true, 0, DeviceLastSeenState.PushTokenType.APNS)))));
  }