// 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
// static <T> Stream<Pair<Integer, T>> withIndices(Stream<T> items) {
//     return zip(iterate(0, x -> x + 1), items);
// }
// 
// Path: src/main/java/co/unruly/control/HigherOrderFunctions.java
// static <A, B> Stream<Pair<A, B>> zip(Stream<A> a, Stream<B> b) {
//     return zip(a, b, Pair::of);
// }


import co.unruly.control.pair.Pair;
import org.junit.Test;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static co.unruly.control.HigherOrderFunctions.withIndices;
import static co.unruly.control.HigherOrderFunctions.zip;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
package co.unruly.control;




public class ZipTest {

    @Test
    public void zipsItemsTogether() {
// 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
// static <T> Stream<Pair<Integer, T>> withIndices(Stream<T> items) {
//     return zip(iterate(0, x -> x + 1), items);
// }
// 
// Path: src/main/java/co/unruly/control/HigherOrderFunctions.java
// static <A, B> Stream<Pair<A, B>> zip(Stream<A> a, Stream<B> b) {
//     return zip(a, b, Pair::of);
// }


// Path: src/test/java/co/unruly/control/ZipTest.java
import co.unruly.control.pair.Pair;
import org.junit.Test;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static co.unruly.control.HigherOrderFunctions.withIndices;
import static co.unruly.control.HigherOrderFunctions.zip;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;

package co.unruly.control;




public class ZipTest {

    @Test
    public void zipsItemsTogether() {
        List<Pair<String, String>> pairs = zip(