// 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 java.util.Objects.requireNonNull;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.DoubleSummaryStatistics;
import java.util.IntSummaryStatistics;
import java.util.LinkedHashMap;
import java.util.LongSummaryStatistics;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.ToDoubleBiFunction;
import java.util.function.ToIntBiFunction;
import java.util.function.ToLongBiFunction;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.mu.util.Both;

  /**
   * Returns a {@link BiCollector} that first maps the input pair using {@code keyMapper} and {@code valueMapper}
   * respectively, then collects the results using {@code downstream} collector.
   *
   * @since 3.6
   */
  public static <K, V, K1, V1, R> BiCollector<K, V, R> mapping(
      BiFunction<? super K, ? super V, ? extends K1> keyMapper,
      BiFunction<? super K, ? super V, ? extends V1> valueMapper,
      BiCollector<K1, V1, R> downstream) {
    requireNonNull(keyMapper);
    requireNonNull(valueMapper);
    requireNonNull(downstream);
    return new BiCollector<K, V, R>() {
      @Override public <E> Collector<E, ?, R> splitting(Function<E, K> toKey, Function<E, V> toValue) {
        return downstream.splitting(
            e -> keyMapper.apply(toKey.apply(e), toValue.apply(e)),
            e -> valueMapper.apply(toKey.apply(e), toValue.apply(e)));
      }
    };
  }

  /**
   * Returns a {@link BiCollector} that first maps the input pair into another pair using {@code mapper}.
   * and then collects the results using {@code downstream} collector.
   *
   * @since 5.2
   */
  public static <K, V, K1, V1, R> BiCollector<K, V, R> mapping(
// 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/src/main/java/com/google/mu/util/stream/BiCollectors.java
import static java.util.Objects.requireNonNull;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.DoubleSummaryStatistics;
import java.util.IntSummaryStatistics;
import java.util.LinkedHashMap;
import java.util.LongSummaryStatistics;
import java.util.Map;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.ToDoubleBiFunction;
import java.util.function.ToIntBiFunction;
import java.util.function.ToLongBiFunction;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.google.mu.util.Both;


  /**
   * Returns a {@link BiCollector} that first maps the input pair using {@code keyMapper} and {@code valueMapper}
   * respectively, then collects the results using {@code downstream} collector.
   *
   * @since 3.6
   */
  public static <K, V, K1, V1, R> BiCollector<K, V, R> mapping(
      BiFunction<? super K, ? super V, ? extends K1> keyMapper,
      BiFunction<? super K, ? super V, ? extends V1> valueMapper,
      BiCollector<K1, V1, R> downstream) {
    requireNonNull(keyMapper);
    requireNonNull(valueMapper);
    requireNonNull(downstream);
    return new BiCollector<K, V, R>() {
      @Override public <E> Collector<E, ?, R> splitting(Function<E, K> toKey, Function<E, V> toValue) {
        return downstream.splitting(
            e -> keyMapper.apply(toKey.apply(e), toValue.apply(e)),
            e -> valueMapper.apply(toKey.apply(e), toValue.apply(e)));
      }
    };
  }

  /**
   * Returns a {@link BiCollector} that first maps the input pair into another pair using {@code mapper}.
   * and then collects the results using {@code downstream} collector.
   *
   * @since 5.2
   */
  public static <K, V, K1, V1, R> BiCollector<K, V, R> mapping(
      BiFunction<? super K, ? super V, ? extends Both<? extends K1, ? extends V1>> mapper,