// Path: api/src/main/java/com/vlkan/hrrs/api/HttpRequestRecord.java
// public interface HttpRequestRecord {
// 
//     String getId();
// 
//     Date getTimestamp();
// 
//     String getGroupName();
// 
//     String getUri();
// 
//     HttpRequestMethod getMethod();
// 
//     List<HttpRequestHeader> getHeaders();
// 
//     HttpRequestPayload getPayload();
// 
//     Builder toBuilder();
// 
//     interface Builder {
// 
//         Builder setId(String id);
// 
//         Builder setTimestamp(Date timestamp);
// 
//         Builder setGroupName(String groupName);
// 
//         Builder setUri(String uri);
// 
//         Builder setMethod(HttpRequestMethod method);
// 
//         Builder setHeaders(List<HttpRequestHeader> headers);
// 
//         Builder setPayload(HttpRequestPayload payload);
// 
//         HttpRequestRecord build();
// 
//     }
// 
// }
// 
// Path: commons/src/main/java/com/vlkan/hrrs/commons/logger/LoggerLevelAccessor.java
// public interface LoggerLevelAccessor {
// 
//     String getRootLevel();
// 
//     void setRootLevel(String levelName);
// 
//     String getLevel(String loggerName);
// 
//     void setLevel(String loggerName, String levelName);
// 
// }
// 
// Path: commons/src/main/java/com/vlkan/hrrs/commons/logger/LoggerLevels.java
// public enum LoggerLevels {;
// 
//     public static void applyLoggerLevelSpecs(String loggerLevelSpecs, LoggerLevelAccessor loggerLevelAccessor) {
//         if (loggerLevelSpecs != null) {
//             for (String loggerNameAndLoggerLevel : loggerLevelSpecs.split(",")) {
//                 String[] fields = loggerNameAndLoggerLevel.split("=", 2);
//                 String loggerName = fields[0];
//                 String loggerLevel = fields[1];
//                 if ("*".equals(loggerName)) {
//                     loggerLevelAccessor.setRootLevel(loggerLevel);
//                 } else {
//                     loggerLevelAccessor.setLevel(loggerName, loggerLevel);
//                 }
//             }
//         }
//     }
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/executor/CloseableExecutor.java
// public interface CloseableExecutor extends Closeable, Executor {
// 
//     // Do nothing.
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/http/HttpRequestRecordReplayer.java
// public interface HttpRequestRecordReplayer extends Closeable {
// 
//     void replay(HttpRequestRecord record);
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/metric/MetricReporter.java
// public interface MetricReporter extends Closeable {
// 
//     void start();
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/record/HttpRequestRecordStream.java
// public interface HttpRequestRecordStream {
// 
//     void consumeWhile(URI inputUri, boolean replayOnce, Callable<Boolean> predicate, HttpRequestRecordStreamConsumer consumer);
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/record/HttpRequestRecordStreamConsumer.java
// public interface HttpRequestRecordStreamConsumer {
// 
//     void consume(HttpRequestRecord record);
// 
// }


import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricRegistry;
import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.RateLimiter;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.vlkan.hrrs.api.HttpRequestRecord;
import com.vlkan.hrrs.commons.logger.LoggerLevelAccessor;
import com.vlkan.hrrs.commons.logger.LoggerLevels;
import com.vlkan.hrrs.replayer.executor.CloseableExecutor;
import com.vlkan.hrrs.replayer.http.HttpRequestRecordReplayer;
import com.vlkan.hrrs.replayer.metric.MetricReporter;
import com.vlkan.hrrs.replayer.record.HttpRequestRecordStream;
import com.vlkan.hrrs.replayer.record.HttpRequestRecordStreamConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import static com.google.common.base.Preconditions.checkNotNull;
                long durationMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
                reportProgress(durationMillis);
                return !closed && durationMillis < totalDurationMillis;
            }

            private void reportProgress(long durationMillis) {
                if (progressReportRateLimiter.tryAcquire()) {
                    float durationPercentage = Math.max(100.0f, 100.0f * durationMillis / totalDurationMillis);
                    long recordCount = recordCounter.incrementAndGet();
                    System.out.format(
                            "\r%.1f%% (durationMillis=%d, recordCount=%d)",
                            durationPercentage, durationMillis, recordCount);
                }
            }

        };
    }

    private void reportMetric() {
        System.out.println();
        System.out.println();
        ConsoleReporter
                .forRegistry(metricRegistry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build()
                .report();
    }

    @Override
// Path: api/src/main/java/com/vlkan/hrrs/api/HttpRequestRecord.java
// public interface HttpRequestRecord {
// 
//     String getId();
// 
//     Date getTimestamp();
// 
//     String getGroupName();
// 
//     String getUri();
// 
//     HttpRequestMethod getMethod();
// 
//     List<HttpRequestHeader> getHeaders();
// 
//     HttpRequestPayload getPayload();
// 
//     Builder toBuilder();
// 
//     interface Builder {
// 
//         Builder setId(String id);
// 
//         Builder setTimestamp(Date timestamp);
// 
//         Builder setGroupName(String groupName);
// 
//         Builder setUri(String uri);
// 
//         Builder setMethod(HttpRequestMethod method);
// 
//         Builder setHeaders(List<HttpRequestHeader> headers);
// 
//         Builder setPayload(HttpRequestPayload payload);
// 
//         HttpRequestRecord build();
// 
//     }
// 
// }
// 
// Path: commons/src/main/java/com/vlkan/hrrs/commons/logger/LoggerLevelAccessor.java
// public interface LoggerLevelAccessor {
// 
//     String getRootLevel();
// 
//     void setRootLevel(String levelName);
// 
//     String getLevel(String loggerName);
// 
//     void setLevel(String loggerName, String levelName);
// 
// }
// 
// Path: commons/src/main/java/com/vlkan/hrrs/commons/logger/LoggerLevels.java
// public enum LoggerLevels {;
// 
//     public static void applyLoggerLevelSpecs(String loggerLevelSpecs, LoggerLevelAccessor loggerLevelAccessor) {
//         if (loggerLevelSpecs != null) {
//             for (String loggerNameAndLoggerLevel : loggerLevelSpecs.split(",")) {
//                 String[] fields = loggerNameAndLoggerLevel.split("=", 2);
//                 String loggerName = fields[0];
//                 String loggerLevel = fields[1];
//                 if ("*".equals(loggerName)) {
//                     loggerLevelAccessor.setRootLevel(loggerLevel);
//                 } else {
//                     loggerLevelAccessor.setLevel(loggerName, loggerLevel);
//                 }
//             }
//         }
//     }
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/executor/CloseableExecutor.java
// public interface CloseableExecutor extends Closeable, Executor {
// 
//     // Do nothing.
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/http/HttpRequestRecordReplayer.java
// public interface HttpRequestRecordReplayer extends Closeable {
// 
//     void replay(HttpRequestRecord record);
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/metric/MetricReporter.java
// public interface MetricReporter extends Closeable {
// 
//     void start();
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/record/HttpRequestRecordStream.java
// public interface HttpRequestRecordStream {
// 
//     void consumeWhile(URI inputUri, boolean replayOnce, Callable<Boolean> predicate, HttpRequestRecordStreamConsumer consumer);
// 
// }
// 
// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/record/HttpRequestRecordStreamConsumer.java
// public interface HttpRequestRecordStreamConsumer {
// 
//     void consume(HttpRequestRecord record);
// 
// }


// Path: replayer/src/main/java/com/vlkan/hrrs/replayer/cli/Replayer.java
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricRegistry;
import com.google.common.base.Stopwatch;
import com.google.common.util.concurrent.RateLimiter;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.vlkan.hrrs.api.HttpRequestRecord;
import com.vlkan.hrrs.commons.logger.LoggerLevelAccessor;
import com.vlkan.hrrs.commons.logger.LoggerLevels;
import com.vlkan.hrrs.replayer.executor.CloseableExecutor;
import com.vlkan.hrrs.replayer.http.HttpRequestRecordReplayer;
import com.vlkan.hrrs.replayer.metric.MetricReporter;
import com.vlkan.hrrs.replayer.record.HttpRequestRecordStream;
import com.vlkan.hrrs.replayer.record.HttpRequestRecordStreamConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import static com.google.common.base.Preconditions.checkNotNull;

                long durationMillis = stopwatch.elapsed(TimeUnit.MILLISECONDS);
                reportProgress(durationMillis);
                return !closed && durationMillis < totalDurationMillis;
            }

            private void reportProgress(long durationMillis) {
                if (progressReportRateLimiter.tryAcquire()) {
                    float durationPercentage = Math.max(100.0f, 100.0f * durationMillis / totalDurationMillis);
                    long recordCount = recordCounter.incrementAndGet();
                    System.out.format(
                            "\r%.1f%% (durationMillis=%d, recordCount=%d)",
                            durationPercentage, durationMillis, recordCount);
                }
            }

        };
    }

    private void reportMetric() {
        System.out.println();
        System.out.println();
        ConsoleReporter
                .forRegistry(metricRegistry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build()
                .report();
    }

    @Override
    public void consume(final HttpRequestRecord record) {