class RetryStrategies {

    public static BiIntFunction<Throwable, Completable> retryWithExponentialBackoffAndJitter(
            final int maxRetries,
            final Predicate<Throwable> causeFilter,
            final Duration initialDelay,
            final Executor timerExecutor) {

        checkMaxRetries(maxRetries);
        requireNonNull(timerExecutor);
        requireNonNull(causeFilter);
        final long initialDelayNanos = initialDelay.toNanos();
        return (retryCount, cause) -> {
            if (retryCount > maxRetries || !causeFilter.test(cause)) {
                return failed(cause);
            }
            return timerExecutor.timer(ThreadLocalRandom.current().nextLong(0, initialDelayNanos << (retryCount - 1)),
                    NANOSECONDS);
        };
    }

    private  RetryStrategies();

}