// Path: mug/src/main/java/com/google/mu/util/stream/MoreCollectors.java
// public static <T, A, B, R> Collector<T, ?, R> mapping(
//     Function<? super T, ? extends Both<? extends A, ? extends B>> mapper,
//     BiCollector<A, B, R> downstream) {
//   return Collectors.mapping(
//       requireNonNull(mapper), downstream.splitting(BiStream::left, BiStream::right));
// }
// 
// Path: mug/src/main/java/com/google/mu/util/Both.java
// @FunctionalInterface
// public interface Both<A, B> {
//   /**
//    * Returns an instance with both {@code a} and {@code b}.
//    *
//    * @since 5.8
//    */
//   public static <A, B> Both<A, B> of(A a, B b) {
//     return new BiOptional.Present<>(a, b);
//   }
// 
//   /**
//    * Applies the {@code mapper} function with this pair of two things as arguments.
//    *
//    * @throws NullPointerException if {@code mapper} is null
//    */
//   <T> T andThen(BiFunction<? super A, ? super B, T> mapper);
// 
//   /**
//    * If the pair {@link #matches matches()} {@code condition}, returns a {@link BiOptional} containing
//    * the pair, or else returns empty.
//    *
//    * @throws NullPointerException if {@code condition} is null, or if {@code condition} matches but
//    *     either value in this pair is null
//    */
//   default BiOptional<A, B> filter(BiPredicate<? super A, ? super B> condition) {
//     requireNonNull(condition);
//     return andThen((a, b) -> condition.test(a, b) ? BiOptional.of(a, b) : BiOptional.empty());
//   }
// 
//   /**
//    * Returns true if the pair matches {@code condition}.
//    *
//    * @throws NullPointerException if {@code condition} is null
//    */
//   default boolean matches(BiPredicate<? super A, ? super B> condition) {
//     return andThen(condition::test);
//   }
// 
//   /**
//    * Invokes {@code consumer} with this pair and returns this object as is.
//    *
//    * @throws NullPointerException if {@code consumer} is null
//    */
//   default Both<A, B> peek(BiConsumer<? super A, ? super B> consumer) {
//     requireNonNull(consumer);
//     return andThen((a, b) -> {
//       consumer.accept(a, b);
//       return this;
//     });
//   }
// }


import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.mu.util.stream.MoreCollectors.mapping;
import static java.util.Objects.requireNonNull;
import static java.util.function.Function.identity;
import java.util.Comparator;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToIntFunction;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Multiset;
import com.google.common.collect.Tables;
import com.google.mu.util.Both;
        BiCollectors.groupingBy(identity(), valueCollector),
        stream -> stream.collect(toImmutableMap()));
  }

  /**
   * Returns a {@link BiCollector} that collects the key-value pairs into an {@link
   * ImmutableSortedMap} according to {@code comparator}, using {@code valueMerger} to merge values
   * of duplicate keys.
   */
  public static <K, V> BiCollector<K, V, ImmutableSortedMap<K, V>> toImmutableSortedMap(
      Comparator<? super K> comparator, BinaryOperator<V> valueMerger) {
    requireNonNull(comparator);
    requireNonNull(valueMerger);
    return new BiCollector<K, V, ImmutableSortedMap<K, V>>() {
      @Override
      public <E> Collector<E, ?, ImmutableSortedMap<K, V>> splitting(
          Function<E, K> toKey, Function<E, V> toValue) {
        return ImmutableSortedMap.toImmutableSortedMap(comparator, toKey, toValue, valueMerger);
      }
    };
  }

  /**
   * Returns a {@link BiCollector} that collects the key-value pairs into an {@link
   * ImmutableSortedMap} according to {@code comparator}.
   */
  public static <K, V> BiCollector<K, V, ImmutableSortedMap<K, V>> toImmutableSortedMap(
      Comparator<? super K> comparator) {
    requireNonNull(comparator);
    return new BiCollector<K, V, ImmutableSortedMap<K, V>>() {
// Path: mug/src/main/java/com/google/mu/util/stream/MoreCollectors.java
// public static <T, A, B, R> Collector<T, ?, R> mapping(
//     Function<? super T, ? extends Both<? extends A, ? extends B>> mapper,
//     BiCollector<A, B, R> downstream) {
//   return Collectors.mapping(
//       requireNonNull(mapper), downstream.splitting(BiStream::left, BiStream::right));
// }
// 
// Path: mug/src/main/java/com/google/mu/util/Both.java
// @FunctionalInterface
// public interface Both<A, B> {
//   /**
//    * Returns an instance with both {@code a} and {@code b}.
//    *
//    * @since 5.8
//    */
//   public static <A, B> Both<A, B> of(A a, B b) {
//     return new BiOptional.Present<>(a, b);
//   }
// 
//   /**
//    * Applies the {@code mapper} function with this pair of two things as arguments.
//    *
//    * @throws NullPointerException if {@code mapper} is null
//    */
//   <T> T andThen(BiFunction<? super A, ? super B, T> mapper);
// 
//   /**
//    * If the pair {@link #matches matches()} {@code condition}, returns a {@link BiOptional} containing
//    * the pair, or else returns empty.
//    *
//    * @throws NullPointerException if {@code condition} is null, or if {@code condition} matches but
//    *     either value in this pair is null
//    */
//   default BiOptional<A, B> filter(BiPredicate<? super A, ? super B> condition) {
//     requireNonNull(condition);
//     return andThen((a, b) -> condition.test(a, b) ? BiOptional.of(a, b) : BiOptional.empty());
//   }
// 
//   /**
//    * Returns true if the pair matches {@code condition}.
//    *
//    * @throws NullPointerException if {@code condition} is null
//    */
//   default boolean matches(BiPredicate<? super A, ? super B> condition) {
//     return andThen(condition::test);
//   }
// 
//   /**
//    * Invokes {@code consumer} with this pair and returns this object as is.
//    *
//    * @throws NullPointerException if {@code consumer} is null
//    */
//   default Both<A, B> peek(BiConsumer<? super A, ? super B> consumer) {
//     requireNonNull(consumer);
//     return andThen((a, b) -> {
//       consumer.accept(a, b);
//       return this;
//     });
//   }
// }


// Path: mug-guava/src/main/java/com/google/mu/util/stream/GuavaCollectors.java
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.mu.util.stream.MoreCollectors.mapping;
import static java.util.Objects.requireNonNull;
import static java.util.function.Function.identity;
import java.util.Comparator;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.ToIntFunction;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Multiset;
import com.google.common.collect.Tables;
import com.google.mu.util.Both;

        BiCollectors.groupingBy(identity(), valueCollector),
        stream -> stream.collect(toImmutableMap()));
  }

  /**
   * Returns a {@link BiCollector} that collects the key-value pairs into an {@link
   * ImmutableSortedMap} according to {@code comparator}, using {@code valueMerger} to merge values
   * of duplicate keys.
   */
  public static <K, V> BiCollector<K, V, ImmutableSortedMap<K, V>> toImmutableSortedMap(
      Comparator<? super K> comparator, BinaryOperator<V> valueMerger) {
    requireNonNull(comparator);
    requireNonNull(valueMerger);
    return new BiCollector<K, V, ImmutableSortedMap<K, V>>() {
      @Override
      public <E> Collector<E, ?, ImmutableSortedMap<K, V>> splitting(
          Function<E, K> toKey, Function<E, V> toValue) {
        return ImmutableSortedMap.toImmutableSortedMap(comparator, toKey, toValue, valueMerger);
      }
    };
  }

  /**
   * Returns a {@link BiCollector} that collects the key-value pairs into an {@link
   * ImmutableSortedMap} according to {@code comparator}.
   */
  public static <K, V> BiCollector<K, V, ImmutableSortedMap<K, V>> toImmutableSortedMap(
      Comparator<? super K> comparator) {
    requireNonNull(comparator);
    return new BiCollector<K, V, ImmutableSortedMap<K, V>>() {
      @Override