package com.example.algoview.ui.algoview

import java.util.*
import kotlin.math.abs
import kotlin.math.sqrt

class Edge(var destination: Vertex, var weight: Double)
class Vertex(
    var id: Int,
    var i: Int, var j: Int
) : Comparable<Vertex> {
    var parent: Vertex? = null
    var distance = Double.POSITIVE_INFINITY
    var edges: LinkedList<Edge> = LinkedList<Edge>()
    var discovered = false
    var heuristic = 0.0

    var f = Double.POSITIVE_INFINITY

    override operator fun compareTo(other: Vertex): Int {
        return distance.compareTo(other.distance)
    }
}

class Graph(heuristicType: Heuristic) {
    private var heuristicType: Heuristic
    private var vertex = ArrayList<Vertex>()
    init {
        this.heuristicType=heuristicType
    }
    fun addVertex(id: Int, i: Int, j: Int) {
        val v1 = Vertex(id, i, j)
        vertex.add(v1)
    }

    fun addEdge(source: Vertex, destination: Vertex?, weight: Double) {
        source.edges.add(Edge(destination!!, weight))
    }

    fun getVertex(i: Int, j: Int): Vertex? {
        for (c in vertex.indices) if (vertex[c].i == i && vertex[c].j == j) return vertex[c]
        return null
    }

    fun heuristic(v: Vertex, destination: Vertex) {
        if (heuristicType == Heuristic.EUCLIDEAN){
            v.heuristic = sqrt(((v.i - destination.i) * (v.i - destination.i) + (v.j - destination.j) * (v.j - destination.j)).toDouble())
        }
        else{
            v.heuristic = abs(destination.i.toDouble() - v.i.toDouble()) + abs(destination.j.toDouble() - v.j.toDouble())
        }
    }
}

enum class Algorithm(val type: Int) {
    DIJKSTRA(1),
    ASTAR(2)
}
enum class Heuristic {
    MANHATTAN,
    EUCLIDEAN
}

Compiled from "Graph.kt"
public final class com.example.algoview.ui.algoview.Graph {
  private com.example.algoview.ui.algoview.Heuristic heuristicType;

  private java.util.ArrayList<com.example.algoview.ui.algoview.Vertex> vertex;

  public com.example.algoview.ui.algoview.Graph(com.example.algoview.ui.algoview.Heuristic);
    Code:
       0: aload_1
       1: ldc           #9                  // String heuristicType
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokespecial #18                 // Method java/lang/Object."<init>":()V
      10: aload_0
      11: new           #20                 // class java/util/ArrayList
      14: dup
      15: invokespecial #21                 // Method java/util/ArrayList."<init>":()V
      18: putfield      #25                 // Field vertex:Ljava/util/ArrayList;
      21: nop
      22: aload_0
      23: aload_1
      24: putfield      #28                 // Field heuristicType:Lcom/example/algoview/ui/algoview/Heuristic;
      27: nop
      28: return

  public final void addVertex(int, int, int);
    Code:
       0: new           #34                 // class com/example/algoview/ui/algoview/Vertex
       3: dup
       4: iload_1
       5: iload_2
       6: iload_3
       7: invokespecial #36                 // Method com/example/algoview/ui/algoview/Vertex."<init>":(III)V
      10: astore        4
      12: aload_0
      13: getfield      #25                 // Field vertex:Ljava/util/ArrayList;
      16: aload         4
      18: invokevirtual #40                 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      21: pop
      22: return

  public final void addEdge(com.example.algoview.ui.algoview.Vertex, com.example.algoview.ui.algoview.Vertex, double);
    Code:
       0: aload_1
       1: ldc           #51                 // String source
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: invokevirtual #55                 // Method com/example/algoview/ui/algoview/Vertex.getEdges:()Ljava/util/LinkedList;
      10: new           #57                 // class com/example/algoview/ui/algoview/Edge
      13: dup
      14: aload_2
      15: dup
      16: invokestatic  #61                 // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;)V
      19: dload_3
      20: invokespecial #64                 // Method com/example/algoview/ui/algoview/Edge."<init>":(Lcom/example/algoview/ui/algoview/Vertex;D)V
      23: invokevirtual #67                 // Method java/util/LinkedList.add:(Ljava/lang/Object;)Z
      26: pop
      27: return

  public final com.example.algoview.ui.algoview.Vertex getVertex(int, int);
    Code:
       0: iconst_0
       1: istore_3
       2: aload_0
       3: getfield      #25                 // Field vertex:Ljava/util/ArrayList;
       6: checkcast     #74                 // class java/util/Collection
       9: invokeinterface #78,  1           // InterfaceMethod java/util/Collection.size:()I
      14: istore        4
      16: iload_3
      17: iload         4
      19: if_icmpge     76
      22: aload_0
      23: getfield      #25                 // Field vertex:Ljava/util/ArrayList;
      26: iload_3
      27: invokevirtual #82                 // Method java/util/ArrayList.get:(I)Ljava/lang/Object;
      30: checkcast     #34                 // class com/example/algoview/ui/algoview/Vertex
      33: invokevirtual #85                 // Method com/example/algoview/ui/algoview/Vertex.getI:()I
      36: iload_1
      37: if_icmpne     70
      40: aload_0
      41: getfield      #25                 // Field vertex:Ljava/util/ArrayList;
      44: iload_3
      45: invokevirtual #82                 // Method java/util/ArrayList.get:(I)Ljava/lang/Object;
      48: checkcast     #34                 // class com/example/algoview/ui/algoview/Vertex
      51: invokevirtual #88                 // Method com/example/algoview/ui/algoview/Vertex.getJ:()I
      54: iload_2
      55: if_icmpne     70
      58: aload_0
      59: getfield      #25                 // Field vertex:Ljava/util/ArrayList;
      62: iload_3
      63: invokevirtual #82                 // Method java/util/ArrayList.get:(I)Ljava/lang/Object;
      66: checkcast     #34                 // class com/example/algoview/ui/algoview/Vertex
      69: areturn
      70: iinc          3, 1
      73: goto          16
      76: aconst_null
      77: areturn

  public final void heuristic(com.example.algoview.ui.algoview.Vertex, com.example.algoview.ui.algoview.Vertex);
    Code:
       0: aload_1
       1: ldc           #93                 // String v
       3: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_2
       7: ldc           #94                 // String destination
       9: invokestatic  #15                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_0
      13: getfield      #28                 // Field heuristicType:Lcom/example/algoview/ui/algoview/Heuristic;
      16: getstatic     #99                 // Field com/example/algoview/ui/algoview/Heuristic.EUCLIDEAN:Lcom/example/algoview/ui/algoview/Heuristic;
      19: if_acmpne     72
      22: aload_1
      23: aload_1
      24: invokevirtual #85                 // Method com/example/algoview/ui/algoview/Vertex.getI:()I
      27: aload_2
      28: invokevirtual #85                 // Method com/example/algoview/ui/algoview/Vertex.getI:()I
      31: isub
      32: aload_1
      33: invokevirtual #85                 // Method com/example/algoview/ui/algoview/Vertex.getI:()I
      36: aload_2
      37: invokevirtual #85                 // Method com/example/algoview/ui/algoview/Vertex.getI:()I
      40: isub
      41: imul
      42: aload_1
      43: invokevirtual #88                 // Method com/example/algoview/ui/algoview/Vertex.getJ:()I
      46: aload_2
      47: invokevirtual #88                 // Method com/example/algoview/ui/algoview/Vertex.getJ:()I
      50: isub
      51: aload_1
      52: invokevirtual #88                 // Method com/example/algoview/ui/algoview/Vertex.getJ:()I
      55: aload_2
      56: invokevirtual #88                 // Method com/example/algoview/ui/algoview/Vertex.getJ:()I
      59: isub
      60: imul
      61: iadd
      62: i2d
      63: invokestatic  #105                // Method java/lang/Math.sqrt:(D)D
      66: invokevirtual #109                // Method com/example/algoview/ui/algoview/Vertex.setHeuristic:(D)V
      69: goto          105
      72: aload_1
      73: aload_2
      74: invokevirtual #85                 // Method com/example/algoview/ui/algoview/Vertex.getI:()I
      77: i2d
      78: aload_1
      79: invokevirtual #85                 // Method com/example/algoview/ui/algoview/Vertex.getI:()I
      82: i2d
      83: dsub
      84: invokestatic  #112                // Method java/lang/Math.abs:(D)D
      87: aload_2
      88: invokevirtual #88                 // Method com/example/algoview/ui/algoview/Vertex.getJ:()I
      91: i2d
      92: aload_1
      93: invokevirtual #88                 // Method com/example/algoview/ui/algoview/Vertex.getJ:()I
      96: i2d
      97: dsub
      98: invokestatic  #112                // Method java/lang/Math.abs:(D)D
     101: dadd
     102: invokevirtual #109                // Method com/example/algoview/ui/algoview/Vertex.setHeuristic:(D)V
     105: return
}


package io.github.tomplum.libs.algorithm

import java.util.*

/**
 * A single node in a graph traversed by Dijkstra's algorithm.
 *
 * @param value The value of the node. Usually contains cartesian positional information.
 * @param distance The distance to this node from the starting point.
 */
data class Node<T>(val value: T, val distance: Int): Comparable<Node<T>> {
    override fun compareTo(other: Node<T>): Int {
        return distance.compareTo(other.distance)
    }
}

/**
 * Calculates the shortest distance to all nodes in a weighted-graph from the given [startingPositions]
 * and terminates based on the given [terminates] predicate.
 *
 * @param startingPositions A collection of nodes to start from.
 * @param evaluateAdjacency A function that is passed an instance of the current node and should return a collection of all adjacent nodes or "neighbours" that should be evaluated as part of the pathfinding.
 * @param processNode An optional function that is applied after the adjacency evaluation for each neighbouring node. Can be used to mutate the state of the node before evaluation.
 * @param terminates A boolean predicate used to determine when the destination node has been reached. When it evaluates as true, the algorithm is terminated and the shortest path for the current node is returned.
 * @return The shortest path from the starting nodes to the node that produces true when passed into the [terminates] predicate.
 */
fun <N> dijkstraShortestPath(
    startingPositions: Collection<N>,
    evaluateAdjacency: (currentNode: Node<N>) -> Collection<Node<N>>,
    processNode: (currentNode: Node<N>, adjacentNode: Node<N>) -> Node<N>,
    terminates: (currentNode: Node<N>) -> Boolean
): Int {
    // A map of nodes and the shortest distance from the given starting positions to it
    val distance = mutableMapOf<N, Int>()

    // Unsettled nodes that are yet to be evaluated. Prioritised by their distance from the start
    val next = PriorityQueue<Node<N>>()

    // Settled nodes whose shortest path has been calculated and need not be evaluated again
    val settled = mutableSetOf<N>()

    startingPositions.forEach { startingPosition ->
        next.offer(Node(startingPosition, 0))
    }

    while(next.isNotEmpty()) {
        // Take the next node from the queue, ready for evaluation
        val currentNode = next.poll()

        // Considered the current node settled now
        settled.add(currentNode.value)

        // If the terminal condition has been met
        // (I.e. the current node is the location we want to find the shortest path to)
        // then we stop and return the current known shortest distance to it
        if (terminates(currentNode)) {
            return currentNode.distance
        }

        // Find all the adjacent nodes to the current one (as per the given predicate)
        // and evaluate each one
        evaluateAdjacency(currentNode).forEach { adjacentNode ->
            // Perform any additional processing on the adjacent node before evaluation
            val evaluationNode = processNode(currentNode, adjacentNode)

            if (!settled.contains(evaluationNode.value)) {
                // The new shortest path to the adjacent node is the current nodes distance
                // plus the weight of the node being evaluated
                val updatedDistance = currentNode.distance + evaluationNode.distance

                // If the distance of this new path is shorter than the shortest path we're
                // already aware of, then we can update it since we've found a shorter one
                if (updatedDistance < distance.getOrDefault(evaluationNode.value, Int.MAX_VALUE)) {
                    // Track the new shortest path
                    distance[evaluationNode.value] = updatedDistance

                    // Queue up the adjacent node to continue down that path
                    next.add(Node(evaluationNode.value, updatedDistance))
                }
            }
        }
    }

    val message = "Could not find a path from the given starting positions to the node indicated by the terminates predicate."
    throw IllegalStateException(message)
}

Compiled from "DijkstrasAlgorithm.kt"
public final class io.github.tomplum.libs.algorithm.DijkstrasAlgorithmKt {
  public static final <N> int dijkstraShortestPath(java.util.Collection<? extends N>, kotlin.jvm.functions.Function1<? super io.github.tomplum.libs.algorithm.Node<N>, ? extends java.util.Collection<io.github.tomplum.libs.algorithm.Node<N>>>, kotlin.jvm.functions.Function2<? super io.github.tomplum.libs.algorithm.Node<N>, ? super io.github.tomplum.libs.algorithm.Node<N>, io.github.tomplum.libs.algorithm.Node<N>>, kotlin.jvm.functions.Function1<? super io.github.tomplum.libs.algorithm.Node<N>, java.lang.Boolean>);
    Code:
       0: aload_0
       1: ldc           #10                 // String startingPositions
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #18                 // String evaluateAdjacency
       9: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_2
      13: ldc           #20                 // String processNode
      15: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      18: aload_3
      19: ldc           #22                 // String terminates
      21: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      24: new           #24                 // class java/util/LinkedHashMap
      27: dup
      28: invokespecial #28                 // Method java/util/LinkedHashMap."<init>":()V
      31: checkcast     #30                 // class java/util/Map
      34: astore        4
      36: new           #32                 // class java/util/PriorityQueue
      39: dup
      40: invokespecial #33                 // Method java/util/PriorityQueue."<init>":()V
      43: astore        5
      45: new           #35                 // class java/util/LinkedHashSet
      48: dup
      49: invokespecial #36                 // Method java/util/LinkedHashSet."<init>":()V
      52: checkcast     #38                 // class java/util/Set
      55: astore        6
      57: aload_0
      58: checkcast     #40                 // class java/lang/Iterable
      61: astore        7
      63: iconst_0
      64: istore        8
      66: aload         7
      68: invokeinterface #44,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      73: astore        9
      75: aload         9
      77: invokeinterface #50,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      82: ifeq          122
      85: aload         9
      87: invokeinterface #54,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      92: astore        10
      94: aload         10
      96: astore        11
      98: iconst_0
      99: istore        12
     101: aload         5
     103: new           #56                 // class io/github/tomplum/libs/algorithm/Node
     106: dup
     107: aload         11
     109: iconst_0
     110: invokespecial #59                 // Method io/github/tomplum/libs/algorithm/Node."<init>":(Ljava/lang/Object;I)V
     113: invokevirtual #63                 // Method java/util/PriorityQueue.offer:(Ljava/lang/Object;)Z
     116: pop
     117: nop
     118: nop
     119: goto          75
     122: nop
     123: aload         5
     125: checkcast     #65                 // class java/util/Collection
     128: invokeinterface #68,  1           // InterfaceMethod java/util/Collection.isEmpty:()Z
     133: ifne          140
     136: iconst_1
     137: goto          141
     140: iconst_0
     141: ifeq          371
     144: aload         5
     146: invokevirtual #71                 // Method java/util/PriorityQueue.poll:()Ljava/lang/Object;
     149: checkcast     #56                 // class io/github/tomplum/libs/algorithm/Node
     152: astore        7
     154: aload         6
     156: aload         7
     158: invokevirtual #74                 // Method io/github/tomplum/libs/algorithm/Node.getValue:()Ljava/lang/Object;
     161: invokeinterface #77,  2           // InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
     166: pop
     167: aload_3
     168: aload         7
     170: invokestatic  #81                 // Method kotlin/jvm/internal/Intrinsics.checkNotNull:(Ljava/lang/Object;)V
     173: aload         7
     175: invokeinterface #87,  2           // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
     180: checkcast     #89                 // class java/lang/Boolean
     183: invokevirtual #92                 // Method java/lang/Boolean.booleanValue:()Z
     186: ifeq          195
     189: aload         7
     191: invokevirtual #96                 // Method io/github/tomplum/libs/algorithm/Node.getDistance:()I
     194: ireturn
     195: aload_1
     196: aload         7
     198: invokeinterface #87,  2           // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
     203: checkcast     #40                 // class java/lang/Iterable
     206: astore        8
     208: iconst_0
     209: istore        9
     211: aload         8
     213: invokeinterface #44,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     218: astore        10
     220: aload         10
     222: invokeinterface #50,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     227: ifeq          367
     230: aload         10
     232: invokeinterface #54,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     237: astore        11
     239: aload         11
     241: checkcast     #56                 // class io/github/tomplum/libs/algorithm/Node
     244: astore        12
     246: iconst_0
     247: istore        13
     249: aload_2
     250: aload         7
     252: aload         12
     254: invokeinterface #101,  3          // InterfaceMethod kotlin/jvm/functions/Function2.invoke:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     259: checkcast     #56                 // class io/github/tomplum/libs/algorithm/Node
     262: astore        14
     264: aload         6
     266: aload         14
     268: invokevirtual #74                 // Method io/github/tomplum/libs/algorithm/Node.getValue:()Ljava/lang/Object;
     271: invokeinterface #104,  2          // InterfaceMethod java/util/Set.contains:(Ljava/lang/Object;)Z
     276: ifne          362
     279: aload         7
     281: invokevirtual #96                 // Method io/github/tomplum/libs/algorithm/Node.getDistance:()I
     284: aload         14
     286: invokevirtual #96                 // Method io/github/tomplum/libs/algorithm/Node.getDistance:()I
     289: iadd
     290: istore        15
     292: iload         15
     294: aload         4
     296: aload         14
     298: invokevirtual #74                 // Method io/github/tomplum/libs/algorithm/Node.getValue:()Ljava/lang/Object;
     301: ldc           #105                // int 2147483647
     303: invokestatic  #111                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     306: invokeinterface #114,  3          // InterfaceMethod java/util/Map.getOrDefault:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     311: checkcast     #116                // class java/lang/Number
     314: invokevirtual #119                // Method java/lang/Number.intValue:()I
     317: if_icmpge     362
     320: iload         15
     322: invokestatic  #111                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     325: astore        16
     327: aload         4
     329: aload         14
     331: invokevirtual #74                 // Method io/github/tomplum/libs/algorithm/Node.getValue:()Ljava/lang/Object;
     334: aload         16
     336: invokeinterface #122,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     341: pop
     342: aload         5
     344: new           #56                 // class io/github/tomplum/libs/algorithm/Node
     347: dup
     348: aload         14
     350: invokevirtual #74                 // Method io/github/tomplum/libs/algorithm/Node.getValue:()Ljava/lang/Object;
     353: iload         15
     355: invokespecial #59                 // Method io/github/tomplum/libs/algorithm/Node."<init>":(Ljava/lang/Object;I)V
     358: invokevirtual #123                // Method java/util/PriorityQueue.add:(Ljava/lang/Object;)Z
     361: pop
     362: nop
     363: nop
     364: goto          220
     367: nop
     368: goto          123
     371: ldc           #125                // String Could not find a path from the given starting positions to the node indicated by the terminates predicate.
     373: astore        7
     375: new           #127                // class java/lang/IllegalStateException
     378: dup
     379: aload         7
     381: invokespecial #130                // Method java/lang/IllegalStateException."<init>":(Ljava/lang/String;)V
     384: athrow
}


package io.github.tomplum.libs.extensions

import kotlin.math.pow

/**
 * Returns the product of all the integers in the given list.
 */
fun List<Int>.product(): Int = if (isNotEmpty()) reduce { product, next -> product * next } else 0
fun List<Long>.product(): Long = if (isNotEmpty()) reduce { product, next -> product * next } else 0

/**
 * Converts the [IntArray] into its decimal equivalent.
 * This assumes the array contains only 1s and 0s.
 * @return The decimal representation.
 */
fun IntArray.toDecimal(): Long = reversed()
    .mapIndexed { i, bit -> if (bit == 1) 2.0.pow(i) else 0 }
    .sumOf { integer -> integer.toLong() }

/**
 * For two sets A and B, the Cartesian product of A and B is denoted by A×B and defined as:
 * A×B = { (a,b) | aϵA and bϵB }
 *
 * Put simply, the Cartesian Product is the multiplication of two sets to form the set of all ordered pairs.
 * This function returns the cartesian product of itself and the given set, meaning A and B are [this] and [other].
 *
 * @see cartesianProductQuadratic for a variant that returns the product of itself.
 */
fun <S, T> List<S>.cartesianProduct(other: List<T>): List<Pair<S, T>> = this.flatMap { value ->
    List(other.size){ i -> Pair(value, other[i]) }
}

/**
 * For two sets A and B, the Cartesian product of A and B is denoted by A×B and defined as:
 * A×B = { (a,b) | aϵA and bϵB }
 *
 * Put simply, the Cartesian Product is the multiplication of two sets to form the set of all ordered pairs.
 * This function returns the cartesian product of itself, meaning both A and B are simply [this].
 *
 * @see cartesianProductCubic for a variant that accepts another set.
 */
fun <T> List<T>.cartesianProductQuadratic(): List<Pair<T, T>> = this.flatMap { value ->
    List(this.size){ i -> Pair(value, this[i]) }
}

/**
 * For three sets A, B and C, the Cartesian product of A, B and C is denoted by A×B×C and defined as:
 * A×B×C = { (p, q, r) | pϵA and qϵB and rϵC }
 *
 * Put simply, the Cartesian Product is the multiplication of three sets to form the set of all ordered pairs.
 * This function returns the cartesian product of itself and the given sets, meaning that A, B & C are all [this].
 *
 * @see cartesianProductQuadratic for a variation that simply finds the product of itself.
 */
fun <T> List<T>.cartesianProductCubic(): List<Triple<T, T, T>> = cartesianProduct(this, this, this).map { set ->
    Triple(set[0], set[1], set[2])
}

/**
 * For three sets A, B and C, the Cartesian product of A, B and C is denoted by A×B×C and defined as:
 * A×B×C = { (p, q, r) | pϵA and qϵB and rϵC }
 *
 * Put simply, the Cartesian Product is the multiplication of three sets to form the set of all ordered pairs.
 * This function returns the cartesian product of itself and the given sets, meaning both A, B and C are [this],
 * [second] and [third] respectively.
 */
fun <T> List<T>.cartesianProductCubic(second: List<T>, third: List<T>): List<Triple<T, T, T>> =
    cartesianProduct(this, second, third).map { set -> Triple(set[0], set[1], set[2]) }

/**
 * Finds the Cartesian Product of any number of given [sets].
 */
private fun <T> cartesianProduct(vararg sets: List<T>): List<List<T>> = sets.fold(listOf(listOf())) { acc, set ->
    acc.flatMap { list -> set.map { element -> list + element } }
}

/**
 * Produces a list of all distinct pairs of elements from the given collection.
 * Pairs are considered distinct irrespective of their order.
 *
 * For example, given a collection of [A, B, C]:
 * - [A, A] is NOT considered distinct
 * - [A, B] and [B, A] are considered equal
 * - The output for this collection would be [[A, B], [A, C], [B, C]].
 *
 * @return A list of all distinct pairs of elements.
 */
fun <T> Collection<T>.distinctPairs(): List<Pair<T, T>> = this.flatMapIndexed { i, element ->
    this.drop(i + 1).map { otherElement ->
        element to otherElement
    }
}

/**
 * Splits a collection based on the given [predicate].
 * @param predicate A boolean predicate to determine when to split the list.
 * @return A collection of collections after splitting.
 */
fun <T> Collection<T>.split(predicate: (element: T) -> Boolean): Collection<Collection<T>> {
    var i = 0
    val data = mutableMapOf<Int, List<T>>()
    var current = mutableListOf<T>()

    this.forEachIndexed { index, element ->
        if (index == this.size - 1) {
            current.add(element)
            data[i] = current
        } else if (predicate(element)) {
            data[i] = current
            i++
            current = mutableListOf()
        } else {
            current.add(element)
        }
    }

    return data.values.toList()
}

/**
 * Calculates the lowest common multiple of
 * all the long values of this given list.
 */
fun List<Long>.lcm(): Long {
    if (this.isNotEmpty()) {
        var result = this[0]
        this.forEachIndexed { i, _ -> result = lcm(result, this[i]) }
        return result
    }

    throw IllegalArgumentException("Cannot find the LCM of an empty list.")
}

private fun lcm(a: Long, b: Long) = a * (b / gcd(a, b))

private fun gcd(a: Long, b: Long): Long {
    var n1 = a
    var n2 = b
    while (n1 != n2) {
        if (n1 > n2) n1 -= n2 else n2 -= n1
    }
    return n1
}

Compiled from "CollectionExtensions.kt"
public final class io.github.tomplum.libs.extensions.CollectionExtensionsKt {
  public static final int product(java.util.List<java.lang.Integer>);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #18                 // class java/util/Collection
      10: invokeinterface #22,  1           // InterfaceMethod java/util/Collection.isEmpty:()Z
      15: ifne          22
      18: iconst_1
      19: goto          23
      22: iconst_0
      23: ifeq          127
      26: aload_0
      27: checkcast     #24                 // class java/lang/Iterable
      30: astore_1
      31: iconst_0
      32: istore_2
      33: aload_1
      34: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      39: astore_3
      40: aload_3
      41: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      46: ifne          59
      49: new           #35                 // class java/lang/UnsupportedOperationException
      52: dup
      53: ldc           #37                 // String Empty collection can\'t be reduced.
      55: invokespecial #41                 // Method java/lang/UnsupportedOperationException."<init>":(Ljava/lang/String;)V
      58: athrow
      59: aload_3
      60: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      65: astore        4
      67: aload_3
      68: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      73: ifeq          116
      76: aload         4
      78: aload_3
      79: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      84: checkcast     #47                 // class java/lang/Number
      87: invokevirtual #51                 // Method java/lang/Number.intValue:()I
      90: istore        5
      92: checkcast     #47                 // class java/lang/Number
      95: invokevirtual #51                 // Method java/lang/Number.intValue:()I
      98: istore        6
     100: iconst_0
     101: istore        7
     103: iload         6
     105: iload         5
     107: imul
     108: invokestatic  #57                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     111: astore        4
     113: goto          67
     116: aload         4
     118: checkcast     #47                 // class java/lang/Number
     121: invokevirtual #51                 // Method java/lang/Number.intValue:()I
     124: goto          128
     127: iconst_0
     128: ireturn

  public static final long product(java.util.List<java.lang.Long>);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #18                 // class java/util/Collection
      10: invokeinterface #22,  1           // InterfaceMethod java/util/Collection.isEmpty:()Z
      15: ifne          22
      18: iconst_1
      19: goto          23
      22: iconst_0
      23: ifeq          127
      26: aload_0
      27: checkcast     #24                 // class java/lang/Iterable
      30: astore_1
      31: iconst_0
      32: istore_2
      33: aload_1
      34: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      39: astore_3
      40: aload_3
      41: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      46: ifne          59
      49: new           #35                 // class java/lang/UnsupportedOperationException
      52: dup
      53: ldc           #37                 // String Empty collection can\'t be reduced.
      55: invokespecial #41                 // Method java/lang/UnsupportedOperationException."<init>":(Ljava/lang/String;)V
      58: athrow
      59: aload_3
      60: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      65: astore        4
      67: aload_3
      68: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      73: ifeq          116
      76: aload         4
      78: aload_3
      79: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      84: checkcast     #47                 // class java/lang/Number
      87: invokevirtual #76                 // Method java/lang/Number.longValue:()J
      90: lstore        5
      92: checkcast     #47                 // class java/lang/Number
      95: invokevirtual #76                 // Method java/lang/Number.longValue:()J
      98: lstore        7
     100: iconst_0
     101: istore        9
     103: lload         7
     105: lload         5
     107: lmul
     108: invokestatic  #81                 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
     111: astore        4
     113: goto          67
     116: aload         4
     118: checkcast     #47                 // class java/lang/Number
     121: invokevirtual #76                 // Method java/lang/Number.longValue:()J
     124: goto          128
     127: lconst_0
     128: lreturn

  public static final long toDecimal(int[]);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokestatic  #91                 // Method kotlin/collections/ArraysKt.reversed:([I)Ljava/util/List;
      10: checkcast     #24                 // class java/lang/Iterable
      13: astore_1
      14: nop
      15: iconst_0
      16: istore_2
      17: aload_1
      18: astore_3
      19: new           #93                 // class java/util/ArrayList
      22: dup
      23: aload_1
      24: bipush        10
      26: invokestatic  #99                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      29: invokespecial #102                // Method java/util/ArrayList."<init>":(I)V
      32: checkcast     #18                 // class java/util/Collection
      35: astore        4
      37: iconst_0
      38: istore        5
      40: iconst_0
      41: istore        6
      43: aload_3
      44: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      49: astore        7
      51: aload         7
      53: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      58: ifeq          143
      61: aload         7
      63: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      68: astore        8
      70: aload         4
      72: iload         6
      74: iinc          6, 1
      77: istore        9
      79: iload         9
      81: ifge          87
      84: invokestatic  #106                // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
      87: iload         9
      89: aload         8
      91: checkcast     #47                 // class java/lang/Number
      94: invokevirtual #51                 // Method java/lang/Number.intValue:()I
      97: istore        10
      99: istore        11
     101: astore        13
     103: iconst_0
     104: istore        12
     106: iload         10
     108: iconst_1
     109: if_icmpne     127
     112: ldc2_w        #107                // double 2.0d
     115: iload         11
     117: i2d
     118: invokestatic  #114                // Method java/lang/Math.pow:(DD)D
     121: invokestatic  #119                // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
     124: goto          131
     127: iconst_0
     128: invokestatic  #57                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     131: aload         13
     133: swap
     134: invokeinterface #123,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     139: pop
     140: goto          51
     143: aload         4
     145: checkcast     #70                 // class java/util/List
     148: nop
     149: checkcast     #24                 // class java/lang/Iterable
     152: astore_1
     153: lconst_0
     154: lstore_2
     155: aload_1
     156: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     161: astore        4
     163: aload         4
     165: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     170: ifeq          211
     173: aload         4
     175: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     180: astore        5
     182: lload_2
     183: aload         5
     185: astore        6
     187: lstore        13
     189: iconst_0
     190: istore        7
     192: aload         6
     194: checkcast     #47                 // class java/lang/Number
     197: invokevirtual #76                 // Method java/lang/Number.longValue:()J
     200: lstore        15
     202: lload         13
     204: lload         15
     206: ladd
     207: lstore_2
     208: goto          163
     211: lload_2
     212: lreturn

  public static final <S, T> java.util.List<kotlin.Pair<S, T>> cartesianProduct(java.util.List<? extends S>, java.util.List<? extends T>);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #144                // String other
       9: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_0
      13: checkcast     #24                 // class java/lang/Iterable
      16: astore_2
      17: iconst_0
      18: istore_3
      19: aload_2
      20: astore        4
      22: new           #93                 // class java/util/ArrayList
      25: dup
      26: invokespecial #146                // Method java/util/ArrayList."<init>":()V
      29: checkcast     #18                 // class java/util/Collection
      32: astore        5
      34: iconst_0
      35: istore        6
      37: aload         4
      39: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      44: astore        7
      46: aload         7
      48: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      53: ifeq          168
      56: aload         7
      58: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      63: astore        8
      65: aload         8
      67: astore        9
      69: iconst_0
      70: istore        10
      72: aload_1
      73: invokeinterface #149,  1          // InterfaceMethod java/util/List.size:()I
      78: istore        11
      80: new           #93                 // class java/util/ArrayList
      83: dup
      84: iload         11
      86: invokespecial #102                // Method java/util/ArrayList."<init>":(I)V
      89: astore        12
      91: iconst_0
      92: istore        13
      94: iload         13
      96: iload         11
      98: if_icmpge     146
     101: iload         13
     103: istore        14
     105: aload         12
     107: iload         14
     109: istore        15
     111: astore        16
     113: iconst_0
     114: istore        17
     116: new           #151                // class kotlin/Pair
     119: dup
     120: aload         9
     122: aload_1
     123: iload         15
     125: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     130: invokespecial #158                // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
     133: aload         16
     135: swap
     136: invokevirtual #159                // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
     139: pop
     140: iinc          13, 1
     143: goto          94
     146: aload         12
     148: checkcast     #70                 // class java/util/List
     151: checkcast     #24                 // class java/lang/Iterable
     154: nop
     155: astore        9
     157: aload         5
     159: aload         9
     161: invokestatic  #163                // Method kotlin/collections/CollectionsKt.addAll:(Ljava/util/Collection;Ljava/lang/Iterable;)Z
     164: pop
     165: goto          46
     168: aload         5
     170: checkcast     #70                 // class java/util/List
     173: nop
     174: areturn

  public static final <T> java.util.List<kotlin.Pair<T, T>> cartesianProductQuadratic(java.util.List<? extends T>);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #24                 // class java/lang/Iterable
      10: astore_1
      11: iconst_0
      12: istore_2
      13: aload_1
      14: astore_3
      15: new           #93                 // class java/util/ArrayList
      18: dup
      19: invokespecial #146                // Method java/util/ArrayList."<init>":()V
      22: checkcast     #18                 // class java/util/Collection
      25: astore        4
      27: iconst_0
      28: istore        5
      30: aload_3
      31: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      36: astore        6
      38: aload         6
      40: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      45: ifeq          160
      48: aload         6
      50: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      55: astore        7
      57: aload         7
      59: astore        8
      61: iconst_0
      62: istore        9
      64: aload_0
      65: invokeinterface #149,  1          // InterfaceMethod java/util/List.size:()I
      70: istore        10
      72: new           #93                 // class java/util/ArrayList
      75: dup
      76: iload         10
      78: invokespecial #102                // Method java/util/ArrayList."<init>":(I)V
      81: astore        11
      83: iconst_0
      84: istore        12
      86: iload         12
      88: iload         10
      90: if_icmpge     138
      93: iload         12
      95: istore        13
      97: aload         11
      99: iload         13
     101: istore        14
     103: astore        15
     105: iconst_0
     106: istore        16
     108: new           #151                // class kotlin/Pair
     111: dup
     112: aload         8
     114: aload_0
     115: iload         14
     117: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     122: invokespecial #158                // Method kotlin/Pair."<init>":(Ljava/lang/Object;Ljava/lang/Object;)V
     125: aload         15
     127: swap
     128: invokevirtual #159                // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
     131: pop
     132: iinc          12, 1
     135: goto          86
     138: aload         11
     140: checkcast     #70                 // class java/util/List
     143: checkcast     #24                 // class java/lang/Iterable
     146: nop
     147: astore        8
     149: aload         4
     151: aload         8
     153: invokestatic  #163                // Method kotlin/collections/CollectionsKt.addAll:(Ljava/util/Collection;Ljava/lang/Iterable;)Z
     156: pop
     157: goto          38
     160: aload         4
     162: checkcast     #70                 // class java/util/List
     165: nop
     166: areturn

  public static final <T> java.util.List<kotlin.Triple<T, T, T>> cartesianProductCubic(java.util.List<? extends T>);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: iconst_3
       7: anewarray     #70                 // class java/util/List
      10: astore_1
      11: aload_1
      12: iconst_0
      13: aload_0
      14: aastore
      15: aload_1
      16: iconst_1
      17: aload_0
      18: aastore
      19: aload_1
      20: iconst_2
      21: aload_0
      22: aastore
      23: aload_1
      24: invokestatic  #184                // Method cartesianProduct:([Ljava/util/List;)Ljava/util/List;
      27: checkcast     #24                 // class java/lang/Iterable
      30: astore_1
      31: iconst_0
      32: istore_2
      33: aload_1
      34: astore_3
      35: new           #93                 // class java/util/ArrayList
      38: dup
      39: aload_1
      40: bipush        10
      42: invokestatic  #99                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      45: invokespecial #102                // Method java/util/ArrayList."<init>":(I)V
      48: checkcast     #18                 // class java/util/Collection
      51: astore        4
      53: iconst_0
      54: istore        5
      56: aload_3
      57: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      62: astore        6
      64: aload         6
      66: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      71: ifeq          140
      74: aload         6
      76: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      81: astore        7
      83: aload         4
      85: aload         7
      87: checkcast     #70                 // class java/util/List
      90: astore        8
      92: astore        10
      94: iconst_0
      95: istore        9
      97: new           #186                // class kotlin/Triple
     100: dup
     101: aload         8
     103: iconst_0
     104: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     109: aload         8
     111: iconst_1
     112: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     117: aload         8
     119: iconst_2
     120: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     125: invokespecial #189                // Method kotlin/Triple."<init>":(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
     128: aload         10
     130: swap
     131: invokeinterface #123,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     136: pop
     137: goto          64
     140: aload         4
     142: checkcast     #70                 // class java/util/List
     145: nop
     146: areturn

  public static final <T> java.util.List<kotlin.Triple<T, T, T>> cartesianProductCubic(java.util.List<? extends T>, java.util.List<? extends T>, java.util.List<? extends T>);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #200                // String second
       9: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: aload_2
      13: ldc           #202                // String third
      15: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      18: iconst_3
      19: anewarray     #70                 // class java/util/List
      22: astore_3
      23: aload_3
      24: iconst_0
      25: aload_0
      26: aastore
      27: aload_3
      28: iconst_1
      29: aload_1
      30: aastore
      31: aload_3
      32: iconst_2
      33: aload_2
      34: aastore
      35: aload_3
      36: invokestatic  #184                // Method cartesianProduct:([Ljava/util/List;)Ljava/util/List;
      39: checkcast     #24                 // class java/lang/Iterable
      42: astore_3
      43: iconst_0
      44: istore        4
      46: aload_3
      47: astore        5
      49: new           #93                 // class java/util/ArrayList
      52: dup
      53: aload_3
      54: bipush        10
      56: invokestatic  #99                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
      59: invokespecial #102                // Method java/util/ArrayList."<init>":(I)V
      62: checkcast     #18                 // class java/util/Collection
      65: astore        6
      67: iconst_0
      68: istore        7
      70: aload         5
      72: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      77: astore        8
      79: aload         8
      81: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      86: ifeq          155
      89: aload         8
      91: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      96: astore        9
      98: aload         6
     100: aload         9
     102: checkcast     #70                 // class java/util/List
     105: astore        10
     107: astore        12
     109: iconst_0
     110: istore        11
     112: new           #186                // class kotlin/Triple
     115: dup
     116: aload         10
     118: iconst_0
     119: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     124: aload         10
     126: iconst_1
     127: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     132: aload         10
     134: iconst_2
     135: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     140: invokespecial #189                // Method kotlin/Triple."<init>":(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
     143: aload         12
     145: swap
     146: invokeinterface #123,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     151: pop
     152: goto          79
     155: aload         6
     157: checkcast     #70                 // class java/util/List
     160: nop
     161: areturn

  private static final <T> java.util.List<java.util.List<T>> cartesianProduct(java.util.List<? extends T>...);
    Code:
       0: aload_0
       1: astore_1
       2: invokestatic  #208                // Method kotlin/collections/CollectionsKt.emptyList:()Ljava/util/List;
       5: invokestatic  #212                // Method kotlin/collections/CollectionsKt.listOf:(Ljava/lang/Object;)Ljava/util/List;
       8: astore_2
       9: iconst_0
      10: istore_3
      11: aload_2
      12: astore        4
      14: iconst_0
      15: istore        5
      17: aload_1
      18: arraylength
      19: istore        6
      21: iload         5
      23: iload         6
      25: if_icmpge     247
      28: aload_1
      29: iload         5
      31: aaload
      32: astore        7
      34: aload         4
      36: aload         7
      38: astore        8
      40: astore        9
      42: iconst_0
      43: istore        10
      45: aload         9
      47: checkcast     #24                 // class java/lang/Iterable
      50: astore        11
      52: iconst_0
      53: istore        12
      55: aload         11
      57: astore        13
      59: new           #93                 // class java/util/ArrayList
      62: dup
      63: invokespecial #146                // Method java/util/ArrayList."<init>":()V
      66: checkcast     #18                 // class java/util/Collection
      69: astore        14
      71: iconst_0
      72: istore        15
      74: aload         13
      76: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      81: astore        16
      83: aload         16
      85: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      90: ifeq          232
      93: aload         16
      95: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     100: astore        17
     102: aload         17
     104: checkcast     #70                 // class java/util/List
     107: astore        18
     109: iconst_0
     110: istore        19
     112: aload         8
     114: checkcast     #24                 // class java/lang/Iterable
     117: astore        20
     119: iconst_0
     120: istore        21
     122: aload         20
     124: astore        22
     126: new           #93                 // class java/util/ArrayList
     129: dup
     130: aload         20
     132: bipush        10
     134: invokestatic  #99                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     137: invokespecial #102                // Method java/util/ArrayList."<init>":(I)V
     140: checkcast     #18                 // class java/util/Collection
     143: astore        23
     145: iconst_0
     146: istore        24
     148: aload         22
     150: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     155: astore        25
     157: aload         25
     159: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     164: ifeq          209
     167: aload         25
     169: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     174: astore        26
     176: aload         23
     178: aload         26
     180: astore        27
     182: astore        28
     184: iconst_0
     185: istore        29
     187: aload         18
     189: checkcast     #18                 // class java/util/Collection
     192: aload         27
     194: invokestatic  #216                // Method kotlin/collections/CollectionsKt.plus:(Ljava/util/Collection;Ljava/lang/Object;)Ljava/util/List;
     197: aload         28
     199: swap
     200: invokeinterface #123,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     205: pop
     206: goto          157
     209: aload         23
     211: checkcast     #70                 // class java/util/List
     214: nop
     215: checkcast     #24                 // class java/lang/Iterable
     218: nop
     219: astore        18
     221: aload         14
     223: aload         18
     225: invokestatic  #163                // Method kotlin/collections/CollectionsKt.addAll:(Ljava/util/Collection;Ljava/lang/Iterable;)Z
     228: pop
     229: goto          83
     232: aload         14
     234: checkcast     #70                 // class java/util/List
     237: nop
     238: nop
     239: astore        4
     241: iinc          5, 1
     244: goto          21
     247: aload         4
     249: areturn

  public static final <T> java.util.List<kotlin.Pair<T, T>> distinctPairs(java.util.Collection<? extends T>);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #24                 // class java/lang/Iterable
      10: astore_1
      11: new           #93                 // class java/util/ArrayList
      14: dup
      15: invokespecial #146                // Method java/util/ArrayList."<init>":()V
      18: checkcast     #18                 // class java/util/Collection
      21: astore_2
      22: iconst_0
      23: istore_3
      24: aload_1
      25: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      30: astore        4
      32: aload         4
      34: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      39: ifeq          198
      42: aload         4
      44: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      49: astore        5
      51: iload_3
      52: iinc          3, 1
      55: istore        6
      57: iload         6
      59: ifge          65
      62: invokestatic  #106                // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
      65: iload         6
      67: aload         5
      69: astore        7
      71: istore        8
      73: iconst_0
      74: istore        9
      76: aload_0
      77: checkcast     #24                 // class java/lang/Iterable
      80: iload         8
      82: iconst_1
      83: iadd
      84: invokestatic  #237                // Method kotlin/collections/CollectionsKt.drop:(Ljava/lang/Iterable;I)Ljava/util/List;
      87: checkcast     #24                 // class java/lang/Iterable
      90: astore        10
      92: iconst_0
      93: istore        11
      95: aload         10
      97: astore        12
      99: new           #93                 // class java/util/ArrayList
     102: dup
     103: aload         10
     105: bipush        10
     107: invokestatic  #99                 // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     110: invokespecial #102                // Method java/util/ArrayList."<init>":(I)V
     113: checkcast     #18                 // class java/util/Collection
     116: astore        13
     118: iconst_0
     119: istore        14
     121: aload         12
     123: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     128: astore        15
     130: aload         15
     132: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
     137: ifeq          179
     140: aload         15
     142: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     147: astore        16
     149: aload         13
     151: aload         16
     153: astore        17
     155: astore        18
     157: iconst_0
     158: istore        19
     160: aload         7
     162: aload         17
     164: invokestatic  #243                // Method kotlin/TuplesKt.to:(Ljava/lang/Object;Ljava/lang/Object;)Lkotlin/Pair;
     167: aload         18
     169: swap
     170: invokeinterface #123,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     175: pop
     176: goto          130
     179: aload         13
     181: checkcast     #70                 // class java/util/List
     184: nop
     185: checkcast     #24                 // class java/lang/Iterable
     188: nop
     189: aload_2
     190: swap
     191: invokestatic  #163                // Method kotlin/collections/CollectionsKt.addAll:(Ljava/util/Collection;Ljava/lang/Iterable;)Z
     194: pop
     195: goto          32
     198: aload_2
     199: checkcast     #70                 // class java/util/List
     202: areturn

  public static final <T> java.util.Collection<java.util.Collection<T>> split(java.util.Collection<? extends T>, kotlin.jvm.functions.Function1<? super T, java.lang.Boolean>);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: ldc           #252                // String predicate
       9: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
      12: iconst_0
      13: istore_2
      14: new           #254                // class java/util/LinkedHashMap
      17: dup
      18: invokespecial #255                // Method java/util/LinkedHashMap."<init>":()V
      21: checkcast     #257                // class java/util/Map
      24: astore_3
      25: aconst_null
      26: astore        4
      28: new           #93                 // class java/util/ArrayList
      31: dup
      32: invokespecial #146                // Method java/util/ArrayList."<init>":()V
      35: checkcast     #70                 // class java/util/List
      38: astore        4
      40: aload_0
      41: checkcast     #24                 // class java/lang/Iterable
      44: astore        5
      46: iconst_0
      47: istore        6
      49: iconst_0
      50: istore        7
      52: aload         5
      54: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      59: astore        8
      61: aload         8
      63: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      68: ifeq          209
      71: aload         8
      73: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      78: astore        9
      80: iload         7
      82: iinc          7, 1
      85: istore        10
      87: iload         10
      89: ifge          95
      92: invokestatic  #106                // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
      95: iload         10
      97: aload         9
      99: astore        11
     101: istore        12
     103: iconst_0
     104: istore        13
     106: iload         12
     108: aload_0
     109: invokeinterface #258,  1          // InterfaceMethod java/util/Collection.size:()I
     114: iconst_1
     115: isub
     116: if_icmpne     145
     119: aload         4
     121: aload         11
     123: invokeinterface #259,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     128: pop
     129: aload_3
     130: iload_2
     131: invokestatic  #57                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     134: aload         4
     136: invokeinterface #263,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     141: pop
     142: goto          204
     145: aload_1
     146: aload         11
     148: invokeinterface #269,  2          // InterfaceMethod kotlin/jvm/functions/Function1.invoke:(Ljava/lang/Object;)Ljava/lang/Object;
     153: checkcast     #271                // class java/lang/Boolean
     156: invokevirtual #274                // Method java/lang/Boolean.booleanValue:()Z
     159: ifeq          194
     162: aload_3
     163: iload_2
     164: invokestatic  #57                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     167: aload         4
     169: invokeinterface #263,  3          // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
     174: pop
     175: iload_2
     176: iconst_1
     177: iadd
     178: istore_2
     179: new           #93                 // class java/util/ArrayList
     182: dup
     183: invokespecial #146                // Method java/util/ArrayList."<init>":()V
     186: checkcast     #70                 // class java/util/List
     189: astore        4
     191: goto          204
     194: aload         4
     196: aload         11
     198: invokeinterface #259,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     203: pop
     204: nop
     205: nop
     206: goto          61
     209: nop
     210: aload_3
     211: invokeinterface #278,  1          // InterfaceMethod java/util/Map.values:()Ljava/util/Collection;
     216: checkcast     #24                 // class java/lang/Iterable
     219: invokestatic  #282                // Method kotlin/collections/CollectionsKt.toList:(Ljava/lang/Iterable;)Ljava/util/List;
     222: checkcast     #18                 // class java/util/Collection
     225: areturn

  public static final long lcm(java.util.List<java.lang.Long>);
    Code:
       0: aload_0
       1: ldc           #10                 // String <this>
       3: invokestatic  #16                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: checkcast     #18                 // class java/util/Collection
      10: invokeinterface #22,  1           // InterfaceMethod java/util/Collection.isEmpty:()Z
      15: ifne          22
      18: iconst_1
      19: goto          23
      22: iconst_0
      23: ifeq          139
      26: lconst_0
      27: lstore        9
      29: aload_0
      30: iconst_0
      31: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      36: checkcast     #47                 // class java/lang/Number
      39: invokevirtual #76                 // Method java/lang/Number.longValue:()J
      42: lstore        9
      44: aload_0
      45: checkcast     #24                 // class java/lang/Iterable
      48: astore_1
      49: iconst_0
      50: istore_2
      51: iconst_0
      52: istore_3
      53: aload_1
      54: invokeinterface #28,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      59: astore        4
      61: aload         4
      63: invokeinterface #33,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      68: ifeq          135
      71: aload         4
      73: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      78: astore        5
      80: iload_3
      81: iinc          3, 1
      84: istore        6
      86: iload         6
      88: ifge          94
      91: invokestatic  #106                // Method kotlin/collections/CollectionsKt.throwIndexOverflow:()V
      94: iload         6
      96: aload         5
      98: checkcast     #47                 // class java/lang/Number
     101: invokevirtual #76                 // Method java/lang/Number.longValue:()J
     104: pop2
     105: istore        7
     107: iconst_0
     108: istore        8
     110: lload         9
     112: aload_0
     113: iload         7
     115: invokeinterface #155,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     120: checkcast     #47                 // class java/lang/Number
     123: invokevirtual #76                 // Method java/lang/Number.longValue:()J
     126: invokestatic  #297                // Method lcm:(JJ)J
     129: lstore        9
     131: nop
     132: goto          61
     135: nop
     136: lload         9
     138: lreturn
     139: new           #299                // class java/lang/IllegalArgumentException
     142: dup
     143: ldc_w         #301                // String Cannot find the LCM of an empty list.
     146: invokespecial #302                // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
     149: athrow

  private static final long lcm(long, long);
    Code:
       0: lload_0
       1: lload_2
       2: lload_0
       3: lload_2
       4: invokestatic  #308                // Method gcd:(JJ)J
       7: ldiv
       8: lmul
       9: lreturn

  private static final long gcd(long, long);
    Code:
       0: lload_0
       1: lstore        4
       3: lload_2
       4: lstore        6
       6: lload         4
       8: lload         6
      10: lcmp
      11: ifeq          42
      14: lload         4
      16: lload         6
      18: lcmp
      19: ifle          32
      22: lload         4
      24: lload         6
      26: lsub
      27: lstore        4
      29: goto          6
      32: lload         6
      34: lload         4
      36: lsub
      37: lstore        6
      39: goto          6
      42: lload         4
      44: lreturn
}