// Path: mug/src/main/java/com/google/mu/util/stream/MoreStreams.java
// public static <T> Iterable<T> iterateOnce(Stream<T> stream) {
//   return stream::iterator;
// }


import static com.google.mu.util.stream.MoreStreams.iterateOnce;
import static java.util.Objects.requireNonNull;
import java.time.Duration;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
   * @throws InterruptedException if the thread is interrupted while waiting.
   * @throws TimeoutException if timeout exceeded while waiting.
   */
  public void parallelize(
      Stream<? extends Runnable> tasks, Duration heartbeatTimeout)
      throws TimeoutException, InterruptedException {
    parallelize(tasks, heartbeatTimeout.toMillis(), TimeUnit.MILLISECONDS);
  }

  /**
   * Runs {@code tasks} in parallel and blocks uninterruptibly until either all tasks have finished,
   * timeout is triggered, or any exception is thrown upon which all pending tasks are canceled
   * (but the method returns without waiting for the tasks to respond to cancellation).
   *
   * <p>The {@code tasks} stream is consumed only in the calling thread in iteration order.
   *
   * @param tasks the tasks to be parallelized
   * @param heartbeatTimeout at least one task needs to complete every {@code heartbeatTimeout}.
   * @param timeUnit the unit of {@code heartbeatTimeout}
   * @throws InterruptedException if the thread is interrupted while waiting.
   * @throws TimeoutException if timeout exceeded while waiting.
   */
  public void parallelize(
      Stream<? extends Runnable> tasks, long heartbeatTimeout, TimeUnit timeUnit)
      throws TimeoutException, InterruptedException {
    requireNonNull(tasks);
    requireNonNull(timeUnit);
    if (heartbeatTimeout <= 0) throw new IllegalArgumentException("timeout = " + heartbeatTimeout);
    Flight flight = new Flight();
    try {
// Path: mug/src/main/java/com/google/mu/util/stream/MoreStreams.java
// public static <T> Iterable<T> iterateOnce(Stream<T> stream) {
//   return stream::iterator;
// }


// Path: mug/src/main/java/com/google/mu/util/concurrent/Parallelizer.java
import static com.google.mu.util.stream.MoreStreams.iterateOnce;
import static java.util.Objects.requireNonNull;
import java.time.Duration;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

   * @throws InterruptedException if the thread is interrupted while waiting.
   * @throws TimeoutException if timeout exceeded while waiting.
   */
  public void parallelize(
      Stream<? extends Runnable> tasks, Duration heartbeatTimeout)
      throws TimeoutException, InterruptedException {
    parallelize(tasks, heartbeatTimeout.toMillis(), TimeUnit.MILLISECONDS);
  }

  /**
   * Runs {@code tasks} in parallel and blocks uninterruptibly until either all tasks have finished,
   * timeout is triggered, or any exception is thrown upon which all pending tasks are canceled
   * (but the method returns without waiting for the tasks to respond to cancellation).
   *
   * <p>The {@code tasks} stream is consumed only in the calling thread in iteration order.
   *
   * @param tasks the tasks to be parallelized
   * @param heartbeatTimeout at least one task needs to complete every {@code heartbeatTimeout}.
   * @param timeUnit the unit of {@code heartbeatTimeout}
   * @throws InterruptedException if the thread is interrupted while waiting.
   * @throws TimeoutException if timeout exceeded while waiting.
   */
  public void parallelize(
      Stream<? extends Runnable> tasks, long heartbeatTimeout, TimeUnit timeUnit)
      throws TimeoutException, InterruptedException {
    requireNonNull(tasks);
    requireNonNull(timeUnit);
    if (heartbeatTimeout <= 0) throw new IllegalArgumentException("timeout = " + heartbeatTimeout);
    Flight flight = new Flight();
    try {
      for (Runnable task : iterateOnce(tasks)) {