// Path: src/main/java/co/unruly/control/pair/Pair.java
// public class Pair<L, R> {
// 
//     public final L left;
//     public final R right;
// 
//     public Pair(L left, R right) {
//         this.left = left;
//         this.right = right;
//     }
// 
//     public static <L, R> Pair<L, R> of(L left, R right) {
//         return new Pair<>(left, right);
//     }
// 
//     /**
//      * Gets the left element. Note that Pair also supports direct member access, but this is useful when you need
//      * a method reference to extract one side of the pair.
//      */
//     public L left() {
//         return left;
//     }
// 
//     /**
//      * Gets the right element. Note that Pair also supports direct member access, but this is useful when you need
//      * a method reference to extract one side of the pair.
//      */
//     public R right() {
//         return right;
// 
//     }
// 
//     /**
//      * Applies the given function to this pair.
//      */
//     public <T> T then(Function<Pair<L, R>, T> function) {
//         return function.apply(this);
//     }
// 
//     /**
//      * Applies the given bifunction to this pair, using left for the first argument and right for the second
//      */
//     public <T> T then(BiFunction<L, R, T> function) {
//         return function.apply(this.left, this.right);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
//         Pair<?, ?> pair = (Pair<?, ?>) o;
//         return Objects.equals(left, pair.left) &&
//                 Objects.equals(right, pair.right);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(left, right);
//     }
// 
//     @Override
//     public String toString() {
//         return "Pair{" +
//                 "left=" + left +
//                 ", right=" + right +
//                 '}';
//     }
// }


import co.unruly.control.pair.Pair;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Stream.iterate;
package co.unruly.control;




public interface HigherOrderFunctions {

    /**
     * Takes a BiFunction, and reverses the order of the arguments
     */
    static <A, B, R> BiFunction<B, A, R> flip(BiFunction<A, B, R> f) {
        return (a, b) -> f.apply(b, a);
    }

    /**
     * Takes a list of functions (which take and return the same type) and composes
     * them into a single function, applying the provided functions in order
     */
    static <T> Function<T, T> compose(Function<T, T>... functions) {
        return compose(Stream.of(functions));
    }

    /**
     * Takes a Stream of functions (which take and return the same type) and composes
     * them into a single function, applying the provided functions in order
     */
    static <T> Function<T, T> compose(Stream<Function<T, T>> functions) {
        return functions.reduce(identity(), Function::andThen);
    }

    /**
     * Takes a list of predicates and composes them into a single predicate, which
     * passes when all passed-in predicates pass
     */
    static <T> Predicate<T> compose(Predicate<T>... functions) {
        return Stream.of(functions).reduce(__ -> true, Predicate::and);
    }

    /**
     * Turns a Consumer into a Function which applies the consumer and returns the input
     */
    static <T> Function<T, T> peek(Consumer<T> action) {
        return t -> {
            action.accept(t);
            return t;
        };
    }

// Path: src/main/java/co/unruly/control/pair/Pair.java
// public class Pair<L, R> {
// 
//     public final L left;
//     public final R right;
// 
//     public Pair(L left, R right) {
//         this.left = left;
//         this.right = right;
//     }
// 
//     public static <L, R> Pair<L, R> of(L left, R right) {
//         return new Pair<>(left, right);
//     }
// 
//     /**
//      * Gets the left element. Note that Pair also supports direct member access, but this is useful when you need
//      * a method reference to extract one side of the pair.
//      */
//     public L left() {
//         return left;
//     }
// 
//     /**
//      * Gets the right element. Note that Pair also supports direct member access, but this is useful when you need
//      * a method reference to extract one side of the pair.
//      */
//     public R right() {
//         return right;
// 
//     }
// 
//     /**
//      * Applies the given function to this pair.
//      */
//     public <T> T then(Function<Pair<L, R>, T> function) {
//         return function.apply(this);
//     }
// 
//     /**
//      * Applies the given bifunction to this pair, using left for the first argument and right for the second
//      */
//     public <T> T then(BiFunction<L, R, T> function) {
//         return function.apply(this.left, this.right);
//     }
// 
//     @Override
//     public boolean equals(Object o) {
//         if (this == o) return true;
//         if (o == null || getClass() != o.getClass()) return false;
//         Pair<?, ?> pair = (Pair<?, ?>) o;
//         return Objects.equals(left, pair.left) &&
//                 Objects.equals(right, pair.right);
//     }
// 
//     @Override
//     public int hashCode() {
//         return Objects.hash(left, right);
//     }
// 
//     @Override
//     public String toString() {
//         return "Pair{" +
//                 "left=" + left +
//                 ", right=" + right +
//                 '}';
//     }
// }


// Path: src/main/java/co/unruly/control/HigherOrderFunctions.java
import co.unruly.control.pair.Pair;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Stream.iterate;

package co.unruly.control;




public interface HigherOrderFunctions {

    /**
     * Takes a BiFunction, and reverses the order of the arguments
     */
    static <A, B, R> BiFunction<B, A, R> flip(BiFunction<A, B, R> f) {
        return (a, b) -> f.apply(b, a);
    }

    /**
     * Takes a list of functions (which take and return the same type) and composes
     * them into a single function, applying the provided functions in order
     */
    static <T> Function<T, T> compose(Function<T, T>... functions) {
        return compose(Stream.of(functions));
    }

    /**
     * Takes a Stream of functions (which take and return the same type) and composes
     * them into a single function, applying the provided functions in order
     */
    static <T> Function<T, T> compose(Stream<Function<T, T>> functions) {
        return functions.reduce(identity(), Function::andThen);
    }

    /**
     * Takes a list of predicates and composes them into a single predicate, which
     * passes when all passed-in predicates pass
     */
    static <T> Predicate<T> compose(Predicate<T>... functions) {
        return Stream.of(functions).reduce(__ -> true, Predicate::and);
    }

    /**
     * Turns a Consumer into a Function which applies the consumer and returns the input
     */
    static <T> Function<T, T> peek(Consumer<T> action) {
        return t -> {
            action.accept(t);
            return t;
        };
    }

    static <T> Stream<Pair<Integer, T>> withIndices(Stream<T> items) {