// Path: core/src/main/java/com/github/phantomthief/util/ThrowableConsumer.java
// @FunctionalInterface
// public interface ThrowableConsumer<T, X extends Throwable> {
// 
//     void accept(T t) throws X;
// 
//     default ThrowableConsumer<T, X> andThen(ThrowableConsumer<? super T, X> after) {
//         requireNonNull(after);
//         return t -> {
//             accept(t);
//             after.accept(t);
//         };
//     }
// }
// 
// Path: core/src/main/java/com/github/phantomthief/util/ThrowableFunction.java
// @FunctionalInterface
// public interface ThrowableFunction<T, R, X extends Throwable> {
// 
//     static <T, X extends Throwable> ThrowableFunction<T, T, X> identity() {
//         return t -> t;
//     }
// 
//     R apply(T t) throws X;
// 
//     default <V> ThrowableFunction<V, R, X>
//             compose(ThrowableFunction<? super V, ? extends T, X> before) {
//         requireNonNull(before);
//         return (V v) -> apply(before.apply(v));
//     }
// 
//     default <V> ThrowableFunction<T, V, X>
//             andThen(ThrowableFunction<? super R, ? extends V, X> after) {
//         requireNonNull(after);
//         return (T t) -> after.apply(apply(t));
//     }
// }
// 
// Path: core/src/main/java/com/github/phantomthief/util/ThrowableRunnable.java
// @FunctionalInterface
// public interface ThrowableRunnable<X extends Throwable> {
// 
//     void run() throws X;
// }


import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
import static java.lang.System.nanoTime;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.time.Duration;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.phantomthief.util.ThrowableConsumer;
import com.github.phantomthief.util.ThrowableFunction;
import com.github.phantomthief.util.ThrowableRunnable;
import com.google.common.util.concurrent.AbstractFuture;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.ExecutionError;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.common.util.concurrent.UncheckedTimeoutException;
    public interface Scheduled {

        /**
         * @return a delay for next run. {@code null} means stop.
         */
        @Nullable
        Duration run();
    }

    private static class ScheduledTaskImpl implements Runnable {

        private final ScheduledExecutorService executorService;
        private final Scheduled scheduled;
        private final AtomicBoolean canceled;

        private ScheduledTaskImpl(ScheduledExecutorService executorService, Scheduled scheduled,
                AtomicBoolean canceled) {
            this.executorService = executorService;
            this.scheduled = scheduled;
            this.canceled = canceled;
        }

        @Override
        public void run() {
            if (canceled.get()) {
                return;
            }
            try {
                Duration delay = scheduled.run();
                if (!canceled.get() && delay != null) {
// Path: core/src/main/java/com/github/phantomthief/util/ThrowableConsumer.java
// @FunctionalInterface
// public interface ThrowableConsumer<T, X extends Throwable> {
// 
//     void accept(T t) throws X;
// 
//     default ThrowableConsumer<T, X> andThen(ThrowableConsumer<? super T, X> after) {
//         requireNonNull(after);
//         return t -> {
//             accept(t);
//             after.accept(t);
//         };
//     }
// }
// 
// Path: core/src/main/java/com/github/phantomthief/util/ThrowableFunction.java
// @FunctionalInterface
// public interface ThrowableFunction<T, R, X extends Throwable> {
// 
//     static <T, X extends Throwable> ThrowableFunction<T, T, X> identity() {
//         return t -> t;
//     }
// 
//     R apply(T t) throws X;
// 
//     default <V> ThrowableFunction<V, R, X>
//             compose(ThrowableFunction<? super V, ? extends T, X> before) {
//         requireNonNull(before);
//         return (V v) -> apply(before.apply(v));
//     }
// 
//     default <V> ThrowableFunction<T, V, X>
//             andThen(ThrowableFunction<? super R, ? extends V, X> after) {
//         requireNonNull(after);
//         return (T t) -> after.apply(apply(t));
//     }
// }
// 
// Path: core/src/main/java/com/github/phantomthief/util/ThrowableRunnable.java
// @FunctionalInterface
// public interface ThrowableRunnable<X extends Throwable> {
// 
//     void run() throws X;
// }


// Path: core/src/main/java/com/github/phantomthief/concurrent/MoreFutures.java
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
import static java.lang.System.nanoTime;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.time.Duration;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.phantomthief.util.ThrowableConsumer;
import com.github.phantomthief.util.ThrowableFunction;
import com.github.phantomthief.util.ThrowableRunnable;
import com.google.common.util.concurrent.AbstractFuture;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.ExecutionError;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.common.util.concurrent.UncheckedTimeoutException;

    public interface Scheduled {

        /**
         * @return a delay for next run. {@code null} means stop.
         */
        @Nullable
        Duration run();
    }

    private static class ScheduledTaskImpl implements Runnable {

        private final ScheduledExecutorService executorService;
        private final Scheduled scheduled;
        private final AtomicBoolean canceled;

        private ScheduledTaskImpl(ScheduledExecutorService executorService, Scheduled scheduled,
                AtomicBoolean canceled) {
            this.executorService = executorService;
            this.scheduled = scheduled;
            this.canceled = canceled;
        }

        @Override
        public void run() {
            if (canceled.get()) {
                return;
            }
            try {
                Duration delay = scheduled.run();
                if (!canceled.get() && delay != null) {
                    executorService.schedule(this, delay.toMillis(), MILLISECONDS);