package be.amedee.adventofcode.aoc2015.day02

import java.io.BufferedReader
import java.io.InputStreamReader

fun getSurfaceArea(
    length: Int,
    width: Int,
    height: Int,
) = 2 * ((length * width) + (width * height) + (height * length))

fun getSlack(
    length: Int,
    width: Int,
    height: Int,
) = minOf(length * width, width * height, height * length)

fun calculateWrappingPaperOrder(presentDimensions: List<Triple<Int, Int, Int>>): Int {
    var totalSquareFeet = 0

    presentDimensions.forEach { (l, w, h) ->
        val surfaceArea = getSurfaceArea(l, w, h)
        val slack = getSlack(l, w, h)
        totalSquareFeet += surfaceArea + slack
    }

    return totalSquareFeet
}

class Day02 {
    fun readPresentDimensionsFromFile(fileName: String): List<Triple<Int, Int, Int>> {
        val packageName = javaClass.`package`.name.replace(".", "/")
        val filePath = "/$packageName/$fileName"
        val inputStream = javaClass.getResourceAsStream(filePath)

        val presentDimensions = mutableListOf<Triple<Int, Int, Int>>()

        if (inputStream != null) {
            BufferedReader(InputStreamReader(inputStream)).useLines { lines ->
                lines.forEach { line ->
                    val dimensions = line.split("x").map { it.toInt() }
                    if (dimensions.size == 3) {
                        presentDimensions.add(Triple(dimensions[0], dimensions[1], dimensions[2]))
                    }
                }
            }
        }

        return presentDimensions
    }
}

fun main() {
    val inputFile = "input"
    val presentDimensions = Day02().readPresentDimensionsFromFile(inputFile)

    val totalSquareFeet = calculateWrappingPaperOrder(presentDimensions)
    println("Elves should order ${"%,d".format(totalSquareFeet)} square feet of wrapping paper.")
}

Compiled from "Day02.kt"
public final class be.amedee.adventofcode.aoc2015.day02.Day02Kt {
  public static final int getSurfaceArea(int, int, int);
    Code:
       0: iconst_2
       1: iload_0
       2: iload_1
       3: imul
       4: iload_1
       5: iload_2
       6: imul
       7: iadd
       8: iload_2
       9: iload_0
      10: imul
      11: iadd
      12: imul
      13: ireturn

  public static final int getSlack(int, int, int);
    Code:
       0: iload_0
       1: iload_1
       2: imul
       3: iload_1
       4: iload_2
       5: imul
       6: iload_2
       7: iload_0
       8: imul
       9: invokestatic  #17                 // Method java/lang/Math.min:(II)I
      12: invokestatic  #17                 // Method java/lang/Math.min:(II)I
      15: ireturn

  public static final int calculateWrappingPaperOrder(java.util.List<kotlin.Triple<java.lang.Integer, java.lang.Integer, java.lang.Integer>>);
    Code:
       0: aload_0
       1: ldc           #23                 // String presentDimensions
       3: invokestatic  #29                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: iconst_0
       7: istore_1
       8: aload_0
       9: checkcast     #31                 // class java/lang/Iterable
      12: astore_2
      13: iconst_0
      14: istore_3
      15: aload_2
      16: invokeinterface #35,  1           // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
      21: astore        4
      23: aload         4
      25: invokeinterface #41,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      30: ifeq          126
      33: aload         4
      35: invokeinterface #45,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      40: astore        5
      42: aload         5
      44: checkcast     #47                 // class kotlin/Triple
      47: astore        6
      49: iconst_0
      50: istore        7
      52: aload         6
      54: invokevirtual #50                 // Method kotlin/Triple.component1:()Ljava/lang/Object;
      57: checkcast     #52                 // class java/lang/Number
      60: invokevirtual #56                 // Method java/lang/Number.intValue:()I
      63: istore        8
      65: aload         6
      67: invokevirtual #59                 // Method kotlin/Triple.component2:()Ljava/lang/Object;
      70: checkcast     #52                 // class java/lang/Number
      73: invokevirtual #56                 // Method java/lang/Number.intValue:()I
      76: istore        9
      78: aload         6
      80: invokevirtual #62                 // Method kotlin/Triple.component3:()Ljava/lang/Object;
      83: checkcast     #52                 // class java/lang/Number
      86: invokevirtual #56                 // Method java/lang/Number.intValue:()I
      89: istore        10
      91: iload         8
      93: iload         9
      95: iload         10
      97: invokestatic  #64                 // Method getSurfaceArea:(III)I
     100: istore        11
     102: iload         8
     104: iload         9
     106: iload         10
     108: invokestatic  #66                 // Method getSlack:(III)I
     111: istore        12
     113: iload_1
     114: iload         11
     116: iload         12
     118: iadd
     119: iadd
     120: istore_1
     121: nop
     122: nop
     123: goto          23
     126: nop
     127: iload_1
     128: ireturn

  public static final void main();
    Code:
       0: ldc           #85                 // String input
       2: astore_0
       3: new           #87                 // class be/amedee/adventofcode/aoc2015/day02/Day02
       6: dup
       7: invokespecial #90                 // Method be/amedee/adventofcode/aoc2015/day02/Day02."<init>":()V
      10: aload_0
      11: invokevirtual #94                 // Method be/amedee/adventofcode/aoc2015/day02/Day02.readPresentDimensionsFromFile:(Ljava/lang/String;)Ljava/util/List;
      14: astore_1
      15: aload_1
      16: invokestatic  #96                 // Method calculateWrappingPaperOrder:(Ljava/util/List;)I
      19: istore_2
      20: new           #98                 // class java/lang/StringBuilder
      23: dup
      24: invokespecial #99                 // Method java/lang/StringBuilder."<init>":()V
      27: ldc           #101                // String Elves should order
      29: invokevirtual #105                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      32: ldc           #107                // String %,d
      34: astore_3
      35: iconst_1
      36: anewarray     #4                  // class java/lang/Object
      39: astore        4
      41: aload         4
      43: iconst_0
      44: iload_2
      45: invokestatic  #113                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
      48: aastore
      49: aload         4
      51: astore        4
      53: aload_3
      54: aload         4
      56: aload         4
      58: arraylength
      59: invokestatic  #119                // Method java/util/Arrays.copyOf:([Ljava/lang/Object;I)[Ljava/lang/Object;
      62: invokestatic  #125                // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
      65: dup
      66: ldc           #127                // String format(...)
      68: invokestatic  #130                // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
      71: invokevirtual #105                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      74: ldc           #132                // String  square feet of wrapping paper.
      76: invokevirtual #105                // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      79: invokevirtual #136                // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      82: getstatic     #142                // Field java/lang/System.out:Ljava/io/PrintStream;
      85: swap
      86: invokevirtual #148                // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
      89: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #153                // Method main:()V
       3: return
}

Compiled from "Day02.kt"
public final class be.amedee.adventofcode.aoc2015.day02.Day02 {
  public be.amedee.adventofcode.aoc2015.day02.Day02();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public final java.util.List<kotlin.Triple<java.lang.Integer, java.lang.Integer, java.lang.Integer>> readPresentDimensionsFromFile(java.lang.String);
    Code:
       0: aload_1
       1: ldc           #18                 // String fileName
       3: invokestatic  #24                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokevirtual #28                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      10: invokevirtual #34                 // Method java/lang/Class.getPackage:()Ljava/lang/Package;
      13: invokevirtual #40                 // Method java/lang/Package.getName:()Ljava/lang/String;
      16: dup
      17: ldc           #42                 // String getName(...)
      19: invokestatic  #45                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullExpressionValue:(Ljava/lang/Object;Ljava/lang/String;)V
      22: ldc           #47                 // String .
      24: ldc           #49                 // String /
      26: iconst_0
      27: iconst_4
      28: aconst_null
      29: invokestatic  #55                 // Method kotlin/text/StringsKt.replace$default:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)Ljava/lang/String;
      32: astore_2
      33: new           #57                 // class java/lang/StringBuilder
      36: dup
      37: invokespecial #58                 // Method java/lang/StringBuilder."<init>":()V
      40: bipush        47
      42: invokevirtual #62                 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      45: aload_2
      46: invokevirtual #65                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      49: bipush        47
      51: invokevirtual #62                 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      54: aload_1
      55: invokevirtual #65                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      58: invokevirtual #68                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      61: astore_3
      62: aload_0
      63: invokevirtual #28                 // Method java/lang/Object.getClass:()Ljava/lang/Class;
      66: aload_3
      67: invokevirtual #72                 // Method java/lang/Class.getResourceAsStream:(Ljava/lang/String;)Ljava/io/InputStream;
      70: astore        4
      72: new           #74                 // class java/util/ArrayList
      75: dup
      76: invokespecial #75                 // Method java/util/ArrayList."<init>":()V
      79: checkcast     #77                 // class java/util/List
      82: astore        5
      84: aload         4
      86: ifnull        425
      89: new           #79                 // class java/io/BufferedReader
      92: dup
      93: new           #81                 // class java/io/InputStreamReader
      96: dup
      97: aload         4
      99: invokespecial #84                 // Method java/io/InputStreamReader."<init>":(Ljava/io/InputStream;)V
     102: checkcast     #86                 // class java/io/Reader
     105: invokespecial #89                 // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V
     108: checkcast     #86                 // class java/io/Reader
     111: astore        6
     113: iconst_0
     114: istore        7
     116: aload         6
     118: astore        8
     120: aload         8
     122: checkcast     #79                 // class java/io/BufferedReader
     125: checkcast     #91                 // class java/io/Closeable
     128: astore        8
     130: aconst_null
     131: astore        9
     133: nop
     134: aload         8
     136: checkcast     #79                 // class java/io/BufferedReader
     139: astore        10
     141: iconst_0
     142: istore        11
     144: aload         10
     146: invokestatic  #97                 // Method kotlin/io/TextStreamsKt.lineSequence:(Ljava/io/BufferedReader;)Lkotlin/sequences/Sequence;
     149: astore        12
     151: iconst_0
     152: istore        13
     154: aload         12
     156: astore        14
     158: iconst_0
     159: istore        15
     161: aload         14
     163: invokeinterface #103,  1          // InterfaceMethod kotlin/sequences/Sequence.iterator:()Ljava/util/Iterator;
     168: astore        16
     170: aload         16
     172: invokeinterface #109,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     177: ifeq          386
     180: aload         16
     182: invokeinterface #113,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     187: astore        17
     189: aload         17
     191: checkcast     #115                // class java/lang/String
     194: astore        18
     196: iconst_0
     197: istore        19
     199: aload         18
     201: checkcast     #117                // class java/lang/CharSequence
     204: iconst_1
     205: anewarray     #115                // class java/lang/String
     208: astore        20
     210: aload         20
     212: iconst_0
     213: ldc           #119                // String x
     215: aastore
     216: aload         20
     218: iconst_0
     219: iconst_0
     220: bipush        6
     222: aconst_null
     223: invokestatic  #123                // Method kotlin/text/StringsKt.split$default:(Ljava/lang/CharSequence;[Ljava/lang/String;ZIILjava/lang/Object;)Ljava/util/List;
     226: checkcast     #125                // class java/lang/Iterable
     229: astore        20
     231: iconst_0
     232: istore        21
     234: aload         20
     236: astore        22
     238: new           #74                 // class java/util/ArrayList
     241: dup
     242: aload         20
     244: bipush        10
     246: invokestatic  #131                // Method kotlin/collections/CollectionsKt.collectionSizeOrDefault:(Ljava/lang/Iterable;I)I
     249: invokespecial #134                // Method java/util/ArrayList."<init>":(I)V
     252: checkcast     #136                // class java/util/Collection
     255: astore        23
     257: iconst_0
     258: istore        24
     260: aload         22
     262: invokeinterface #137,  1          // InterfaceMethod java/lang/Iterable.iterator:()Ljava/util/Iterator;
     267: astore        25
     269: aload         25
     271: invokeinterface #109,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
     276: ifeq          323
     279: aload         25
     281: invokeinterface #113,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
     286: astore        26
     288: aload         23
     290: aload         26
     292: checkcast     #115                // class java/lang/String
     295: astore        27
     297: astore        28
     299: iconst_0
     300: istore        29
     302: aload         27
     304: invokestatic  #143                // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
     307: nop
     308: invokestatic  #147                // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
     311: aload         28
     313: swap
     314: invokeinterface #151,  2          // InterfaceMethod java/util/Collection.add:(Ljava/lang/Object;)Z
     319: pop
     320: goto          269
     323: aload         23
     325: checkcast     #77                 // class java/util/List
     328: nop
     329: astore        30
     331: aload         30
     333: invokeinterface #155,  1          // InterfaceMethod java/util/List.size:()I
     338: iconst_3
     339: if_icmpne     381
     342: aload         5
     344: new           #157                // class kotlin/Triple
     347: dup
     348: aload         30
     350: iconst_0
     351: invokeinterface #161,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     356: aload         30
     358: iconst_1
     359: invokeinterface #161,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     364: aload         30
     366: iconst_2
     367: invokeinterface #161,  2          // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
     372: invokespecial #164                // Method kotlin/Triple."<init>":(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
     375: invokeinterface #165,  2          // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
     380: pop
     381: nop
     382: nop
     383: goto          170
     386: nop
     387: nop
     388: getstatic     #171                // Field kotlin/Unit.INSTANCE:Lkotlin/Unit;
     391: astore        10
     393: aload         8
     395: aload         9
     397: invokestatic  #177                // Method kotlin/io/CloseableKt.closeFinally:(Ljava/io/Closeable;Ljava/lang/Throwable;)V
     400: goto          424
     403: astore        11
     405: aload         11
     407: astore        9
     409: aload         11
     411: athrow
     412: astore        11
     414: aload         8
     416: aload         9
     418: invokestatic  #177                // Method kotlin/io/CloseableKt.closeFinally:(Ljava/io/Closeable;Ljava/lang/Throwable;)V
     421: aload         11
     423: athrow
     424: nop
     425: aload         5
     427: areturn
    Exception table:
       from    to  target type
         133   393   403   Class java/lang/Throwable
         133   393   412   any
         403   412   412   any
         412   414   412   any
}


package com.seanshubin.factor.analysis.ratio

data class Ratio(val numerator: Int, val denominator: Int) : Comparable<Ratio> {
    init {
        require(denominator != 0){
            "Denominator must not be zero in $numerator/$denominator"
        }
    }
    operator fun plus(that: Ratio): Ratio {
        val lcm = leastCommonMultiple(denominator, that.denominator)
        return Ratio(numerator * lcm / denominator + that.numerator * lcm / that.denominator, lcm).simplify()
    }

    operator fun minus(that: Ratio): Ratio = (this + -that).simplify()
    operator fun times(that: Ratio): Ratio = Ratio(numerator * that.numerator, denominator * that.denominator).simplify()
    operator fun times(that: Int): Ratio = this * Ratio(that,1)
    operator fun div(that: Ratio): Ratio = (this * that.recriprocal()).simplify()
    operator fun unaryMinus(): Ratio = Ratio(-numerator, denominator).simplify()
    fun recriprocal(): Ratio = Ratio(denominator, numerator).simplify()
    fun withDenominator(newDenominator: Int): Ratio = Ratio(numerator * newDenominator / denominator, newDenominator)
    override fun compareTo(that: Ratio): Int {
        val lcm = leastCommonMultiple(denominator, that.denominator)
        return (numerator * lcm / denominator).compareTo(that.numerator * lcm / that.denominator)
    }

    override fun toString(): String = if(denominator == 1) "$numerator" else "$numerator/$denominator"

    fun simplify(): Ratio = simplifyFactor().simplifySign()
    private fun simplifySign(): Ratio =
        if (denominator < 0) Ratio(-numerator, -denominator)
        else this

    private fun simplifyFactor(): Ratio {
        val gcf = greatestCommonFactor(numerator, denominator)
        return Ratio(numerator / gcf, denominator / gcf)
    }

    companion object {
        val ZERO = Ratio(0,1)
        val ONE = Ratio(1,1)
        fun greatestCommonFactor(a: Int, b: Int): Int =
            if (b == 0) a
            else greatestCommonFactor(b, a % b)

        fun leastCommonMultiple(a: Int, b: Int): Int =
            if (a == 0 && b == 0) 0
            else a * b / greatestCommonFactor(a, b)

        val regex = Regex("""(-?\d+)/(-?\d+)""")

        fun parse(s: String): Ratio {
            val matchResult = regex.matchEntire(s)
            if (matchResult == null) throw RuntimeException("Value '$s' could did not match expression $regex")
            val numerator = matchResult.groupValues[1].toInt()
            val denominator = matchResult.groupValues[2].toInt()
            return Ratio(numerator, denominator).simplify()
        }
        fun Int.toRatio():Ratio = Ratio(this, 1)
        fun List<Ratio>.toRatioArray():Array<Ratio> = toTypedArray()
        operator fun Int.div(x:Ratio):Ratio = ONE / x
        fun List<Ratio>.sum():Ratio {
                var sum: Ratio = ZERO
                for (element in this) {
                    sum += element
                }
                return sum
        }
    }

    val toDouble: Double get() = numerator.toDouble() / denominator.toDouble()
}

Compiled from "Ratio.kt"
public final class com.seanshubin.factor.analysis.ratio.Ratio implements java.lang.Comparable<com.seanshubin.factor.analysis.ratio.Ratio> {
  public static final com.seanshubin.factor.analysis.ratio.Ratio$Companion Companion;

  private final int numerator;

  private final int denominator;

  private static final com.seanshubin.factor.analysis.ratio.Ratio ZERO;

  private static final com.seanshubin.factor.analysis.ratio.Ratio ONE;

  private static final kotlin.text.Regex regex;

  public com.seanshubin.factor.analysis.ratio.Ratio(int, int);
    Code:
       0: aload_0
       1: invokespecial #12                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iload_1
       6: putfield      #16                 // Field numerator:I
       9: aload_0
      10: iload_2
      11: putfield      #19                 // Field denominator:I
      14: nop
      15: aload_0
      16: getfield      #19                 // Field denominator:I
      19: ifeq          26
      22: iconst_1
      23: goto          27
      26: iconst_0
      27: ifne          79
      30: iconst_0
      31: istore_3
      32: new           #21                 // class java/lang/StringBuilder
      35: dup
      36: invokespecial #22                 // Method java/lang/StringBuilder."<init>":()V
      39: ldc           #24                 // String Denominator must not be zero in
      41: invokevirtual #28                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      44: aload_0
      45: getfield      #16                 // Field numerator:I
      48: invokevirtual #31                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      51: bipush        47
      53: invokevirtual #34                 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      56: aload_0
      57: getfield      #19                 // Field denominator:I
      60: invokevirtual #31                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      63: invokevirtual #38                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      66: astore_3
      67: new           #40                 // class java/lang/IllegalArgumentException
      70: dup
      71: aload_3
      72: invokevirtual #41                 // Method java/lang/Object.toString:()Ljava/lang/String;
      75: invokespecial #44                 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
      78: athrow
      79: nop
      80: return

  public final int getNumerator();
    Code:
       0: aload_0
       1: getfield      #16                 // Field numerator:I
       4: ireturn

  public final int getDenominator();
    Code:
       0: aload_0
       1: getfield      #19                 // Field denominator:I
       4: ireturn

  public final com.seanshubin.factor.analysis.ratio.Ratio plus(com.seanshubin.factor.analysis.ratio.Ratio);
    Code:
       0: aload_1
       1: ldc           #55                 // String that
       3: invokestatic  #61                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: getstatic     #65                 // Field Companion:Lcom/seanshubin/factor/analysis/ratio/Ratio$Companion;
       9: aload_0
      10: getfield      #19                 // Field denominator:I
      13: aload_1
      14: getfield      #19                 // Field denominator:I
      17: invokevirtual #71                 // Method com/seanshubin/factor/analysis/ratio/Ratio$Companion.leastCommonMultiple:(II)I
      20: istore_2
      21: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
      24: dup
      25: aload_0
      26: getfield      #16                 // Field numerator:I
      29: iload_2
      30: imul
      31: aload_0
      32: getfield      #19                 // Field denominator:I
      35: idiv
      36: aload_1
      37: getfield      #16                 // Field numerator:I
      40: iload_2
      41: imul
      42: aload_1
      43: getfield      #19                 // Field denominator:I
      46: idiv
      47: iadd
      48: iload_2
      49: invokespecial #73                 // Method "<init>":(II)V
      52: invokevirtual #77                 // Method simplify:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      55: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio minus(com.seanshubin.factor.analysis.ratio.Ratio);
    Code:
       0: aload_1
       1: ldc           #55                 // String that
       3: invokestatic  #61                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_1
       8: invokevirtual #82                 // Method unaryMinus:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      11: invokevirtual #84                 // Method plus:(Lcom/seanshubin/factor/analysis/ratio/Ratio;)Lcom/seanshubin/factor/analysis/ratio/Ratio;
      14: invokevirtual #77                 // Method simplify:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      17: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio times(com.seanshubin.factor.analysis.ratio.Ratio);
    Code:
       0: aload_1
       1: ldc           #55                 // String that
       3: invokestatic  #61                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
       9: dup
      10: aload_0
      11: getfield      #16                 // Field numerator:I
      14: aload_1
      15: getfield      #16                 // Field numerator:I
      18: imul
      19: aload_0
      20: getfield      #19                 // Field denominator:I
      23: aload_1
      24: getfield      #19                 // Field denominator:I
      27: imul
      28: invokespecial #73                 // Method "<init>":(II)V
      31: invokevirtual #77                 // Method simplify:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      34: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio times(int);
    Code:
       0: aload_0
       1: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
       4: dup
       5: iload_1
       6: iconst_1
       7: invokespecial #73                 // Method "<init>":(II)V
      10: invokevirtual #88                 // Method times:(Lcom/seanshubin/factor/analysis/ratio/Ratio;)Lcom/seanshubin/factor/analysis/ratio/Ratio;
      13: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio div(com.seanshubin.factor.analysis.ratio.Ratio);
    Code:
       0: aload_1
       1: ldc           #55                 // String that
       3: invokestatic  #61                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: aload_1
       8: invokevirtual #92                 // Method recriprocal:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      11: invokevirtual #88                 // Method times:(Lcom/seanshubin/factor/analysis/ratio/Ratio;)Lcom/seanshubin/factor/analysis/ratio/Ratio;
      14: invokevirtual #77                 // Method simplify:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      17: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio unaryMinus();
    Code:
       0: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
       3: dup
       4: aload_0
       5: getfield      #16                 // Field numerator:I
       8: ineg
       9: aload_0
      10: getfield      #19                 // Field denominator:I
      13: invokespecial #73                 // Method "<init>":(II)V
      16: invokevirtual #77                 // Method simplify:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      19: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio recriprocal();
    Code:
       0: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
       3: dup
       4: aload_0
       5: getfield      #19                 // Field denominator:I
       8: aload_0
       9: getfield      #16                 // Field numerator:I
      12: invokespecial #73                 // Method "<init>":(II)V
      15: invokevirtual #77                 // Method simplify:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      18: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio withDenominator(int);
    Code:
       0: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
       3: dup
       4: aload_0
       5: getfield      #16                 // Field numerator:I
       8: iload_1
       9: imul
      10: aload_0
      11: getfield      #19                 // Field denominator:I
      14: idiv
      15: iload_1
      16: invokespecial #73                 // Method "<init>":(II)V
      19: areturn

  public int compareTo(com.seanshubin.factor.analysis.ratio.Ratio);
    Code:
       0: aload_1
       1: ldc           #55                 // String that
       3: invokestatic  #61                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: getstatic     #65                 // Field Companion:Lcom/seanshubin/factor/analysis/ratio/Ratio$Companion;
       9: aload_0
      10: getfield      #19                 // Field denominator:I
      13: aload_1
      14: getfield      #19                 // Field denominator:I
      17: invokevirtual #71                 // Method com/seanshubin/factor/analysis/ratio/Ratio$Companion.leastCommonMultiple:(II)I
      20: istore_2
      21: aload_0
      22: getfield      #16                 // Field numerator:I
      25: iload_2
      26: imul
      27: aload_0
      28: getfield      #19                 // Field denominator:I
      31: idiv
      32: aload_1
      33: getfield      #16                 // Field numerator:I
      36: iload_2
      37: imul
      38: aload_1
      39: getfield      #19                 // Field denominator:I
      42: idiv
      43: invokestatic  #99                 // Method kotlin/jvm/internal/Intrinsics.compare:(II)I
      46: ireturn

  public java.lang.String toString();
    Code:
       0: aload_0
       1: getfield      #19                 // Field denominator:I
       4: iconst_1
       5: if_icmpne     18
       8: aload_0
       9: getfield      #16                 // Field numerator:I
      12: invokestatic  #105                // Method java/lang/String.valueOf:(I)Ljava/lang/String;
      15: goto          47
      18: new           #21                 // class java/lang/StringBuilder
      21: dup
      22: invokespecial #22                 // Method java/lang/StringBuilder."<init>":()V
      25: aload_0
      26: getfield      #16                 // Field numerator:I
      29: invokevirtual #31                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      32: bipush        47
      34: invokevirtual #34                 // Method java/lang/StringBuilder.append:(C)Ljava/lang/StringBuilder;
      37: aload_0
      38: getfield      #19                 // Field denominator:I
      41: invokevirtual #31                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
      44: invokevirtual #38                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      47: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio simplify();
    Code:
       0: aload_0
       1: invokespecial #108                // Method simplifyFactor:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
       4: invokespecial #111                // Method simplifySign:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
       7: areturn

  private final com.seanshubin.factor.analysis.ratio.Ratio simplifySign();
    Code:
       0: aload_0
       1: getfield      #19                 // Field denominator:I
       4: ifge          27
       7: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
      10: dup
      11: aload_0
      12: getfield      #16                 // Field numerator:I
      15: ineg
      16: aload_0
      17: getfield      #19                 // Field denominator:I
      20: ineg
      21: invokespecial #73                 // Method "<init>":(II)V
      24: goto          28
      27: aload_0
      28: areturn

  private final com.seanshubin.factor.analysis.ratio.Ratio simplifyFactor();
    Code:
       0: getstatic     #65                 // Field Companion:Lcom/seanshubin/factor/analysis/ratio/Ratio$Companion;
       3: aload_0
       4: getfield      #16                 // Field numerator:I
       7: aload_0
       8: getfield      #19                 // Field denominator:I
      11: invokevirtual #114                // Method com/seanshubin/factor/analysis/ratio/Ratio$Companion.greatestCommonFactor:(II)I
      14: istore_1
      15: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
      18: dup
      19: aload_0
      20: getfield      #16                 // Field numerator:I
      23: iload_1
      24: idiv
      25: aload_0
      26: getfield      #19                 // Field denominator:I
      29: iload_1
      30: idiv
      31: invokespecial #73                 // Method "<init>":(II)V
      34: areturn

  public final double getToDouble();
    Code:
       0: aload_0
       1: getfield      #16                 // Field numerator:I
       4: i2d
       5: aload_0
       6: getfield      #19                 // Field denominator:I
       9: i2d
      10: ddiv
      11: dreturn

  public final int component1();
    Code:
       0: aload_0
       1: getfield      #16                 // Field numerator:I
       4: ireturn

  public final int component2();
    Code:
       0: aload_0
       1: getfield      #19                 // Field denominator:I
       4: ireturn

  public final com.seanshubin.factor.analysis.ratio.Ratio copy(int, int);
    Code:
       0: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
       3: dup
       4: iload_1
       5: iload_2
       6: invokespecial #73                 // Method "<init>":(II)V
       9: areturn

  public static com.seanshubin.factor.analysis.ratio.Ratio copy$default(com.seanshubin.factor.analysis.ratio.Ratio, int, int, int, java.lang.Object);
    Code:
       0: iload_3
       1: iconst_1
       2: iand
       3: ifeq          11
       6: aload_0
       7: getfield      #16                 // Field numerator:I
      10: istore_1
      11: iload_3
      12: iconst_2
      13: iand
      14: ifeq          22
      17: aload_0
      18: getfield      #19                 // Field denominator:I
      21: istore_2
      22: aload_0
      23: iload_1
      24: iload_2
      25: invokevirtual #125                // Method copy:(II)Lcom/seanshubin/factor/analysis/ratio/Ratio;
      28: areturn

  public int hashCode();
    Code:
       0: aload_0
       1: getfield      #16                 // Field numerator:I
       4: invokestatic  #131                // Method java/lang/Integer.hashCode:(I)I
       7: istore_1
       8: iload_1
       9: bipush        31
      11: imul
      12: aload_0
      13: getfield      #19                 // Field denominator:I
      16: invokestatic  #131                // Method java/lang/Integer.hashCode:(I)I
      19: iadd
      20: istore_1
      21: iload_1
      22: ireturn

  public boolean equals(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: if_acmpne     7
       5: iconst_1
       6: ireturn
       7: aload_1
       8: instanceof    #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
      11: ifne          16
      14: iconst_0
      15: ireturn
      16: aload_1
      17: checkcast     #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
      20: astore_2
      21: aload_0
      22: getfield      #16                 // Field numerator:I
      25: aload_2
      26: getfield      #16                 // Field numerator:I
      29: if_icmpeq     34
      32: iconst_0
      33: ireturn
      34: aload_0
      35: getfield      #19                 // Field denominator:I
      38: aload_2
      39: getfield      #19                 // Field denominator:I
      42: if_icmpeq     47
      45: iconst_0
      46: ireturn
      47: iconst_1
      48: ireturn

  public int compareTo(java.lang.Object);
    Code:
       0: aload_0
       1: aload_1
       2: checkcast     #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
       5: invokevirtual #140                // Method compareTo:(Lcom/seanshubin/factor/analysis/ratio/Ratio;)I
       8: ireturn

  public static final com.seanshubin.factor.analysis.ratio.Ratio access$getZERO$cp();
    Code:
       0: getstatic     #144                // Field ZERO:Lcom/seanshubin/factor/analysis/ratio/Ratio;
       3: areturn

  public static final com.seanshubin.factor.analysis.ratio.Ratio access$getONE$cp();
    Code:
       0: getstatic     #148                // Field ONE:Lcom/seanshubin/factor/analysis/ratio/Ratio;
       3: areturn

  public static final kotlin.text.Regex access$getRegex$cp();
    Code:
       0: getstatic     #154                // Field regex:Lkotlin/text/Regex;
       3: areturn

  static {};
    Code:
       0: new           #67                 // class com/seanshubin/factor/analysis/ratio/Ratio$Companion
       3: dup
       4: aconst_null
       5: invokespecial #158                // Method com/seanshubin/factor/analysis/ratio/Ratio$Companion."<init>":(Lkotlin/jvm/internal/DefaultConstructorMarker;)V
       8: putstatic     #65                 // Field Companion:Lcom/seanshubin/factor/analysis/ratio/Ratio$Companion;
      11: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
      14: dup
      15: iconst_0
      16: iconst_1
      17: invokespecial #73                 // Method "<init>":(II)V
      20: putstatic     #144                // Field ZERO:Lcom/seanshubin/factor/analysis/ratio/Ratio;
      23: new           #2                  // class com/seanshubin/factor/analysis/ratio/Ratio
      26: dup
      27: iconst_1
      28: iconst_1
      29: invokespecial #73                 // Method "<init>":(II)V
      32: putstatic     #148                // Field ONE:Lcom/seanshubin/factor/analysis/ratio/Ratio;
      35: new           #160                // class kotlin/text/Regex
      38: dup
      39: ldc           #162                // String (-?\\d+)/(-?\\d+)
      41: invokespecial #163                // Method kotlin/text/Regex."<init>":(Ljava/lang/String;)V
      44: putstatic     #154                // Field regex:Lkotlin/text/Regex;
      47: return
}

Compiled from "Ratio.kt"
public final class com.seanshubin.factor.analysis.ratio.Ratio$Companion {
  private com.seanshubin.factor.analysis.ratio.Ratio$Companion();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public final com.seanshubin.factor.analysis.ratio.Ratio getZERO();
    Code:
       0: invokestatic  #18                 // Method com/seanshubin/factor/analysis/ratio/Ratio.access$getZERO$cp:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
       3: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio getONE();
    Code:
       0: invokestatic  #22                 // Method com/seanshubin/factor/analysis/ratio/Ratio.access$getONE$cp:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
       3: areturn

  public final int greatestCommonFactor(int, int);
    Code:
       0: iload_2
       1: ifne          8
       4: iload_1
       5: goto          16
       8: aload_0
       9: iload_2
      10: iload_1
      11: iload_2
      12: irem
      13: invokevirtual #26                 // Method greatestCommonFactor:(II)I
      16: ireturn

  public final int leastCommonMultiple(int, int);
    Code:
       0: iload_1
       1: ifne          12
       4: iload_2
       5: ifne          12
       8: iconst_0
       9: goto          22
      12: iload_1
      13: iload_2
      14: imul
      15: aload_0
      16: iload_1
      17: iload_2
      18: invokevirtual #26                 // Method greatestCommonFactor:(II)I
      21: idiv
      22: ireturn

  public final kotlin.text.Regex getRegex();
    Code:
       0: invokestatic  #35                 // Method com/seanshubin/factor/analysis/ratio/Ratio.access$getRegex$cp:()Lkotlin/text/Regex;
       3: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio parse(java.lang.String);
    Code:
       0: aload_1
       1: ldc           #39                 // String s
       3: invokestatic  #45                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokevirtual #47                 // Method getRegex:()Lkotlin/text/Regex;
      10: aload_1
      11: checkcast     #49                 // class java/lang/CharSequence
      14: invokevirtual #55                 // Method kotlin/text/Regex.matchEntire:(Ljava/lang/CharSequence;)Lkotlin/text/MatchResult;
      17: astore_2
      18: aload_2
      19: ifnonnull     61
      22: new           #57                 // class java/lang/RuntimeException
      25: dup
      26: new           #59                 // class java/lang/StringBuilder
      29: dup
      30: invokespecial #60                 // Method java/lang/StringBuilder."<init>":()V
      33: ldc           #62                 // String Value \'
      35: invokevirtual #66                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      38: aload_1
      39: invokevirtual #66                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      42: ldc           #68                 // String \' could did not match expression
      44: invokevirtual #66                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      47: aload_0
      48: invokevirtual #47                 // Method getRegex:()Lkotlin/text/Regex;
      51: invokevirtual #71                 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      54: invokevirtual #75                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      57: invokespecial #78                 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
      60: athrow
      61: aload_2
      62: invokeinterface #84,  1           // InterfaceMethod kotlin/text/MatchResult.getGroupValues:()Ljava/util/List;
      67: iconst_1
      68: invokeinterface #90,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      73: checkcast     #92                 // class java/lang/String
      76: invokestatic  #98                 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
      79: istore_3
      80: aload_2
      81: invokeinterface #84,  1           // InterfaceMethod kotlin/text/MatchResult.getGroupValues:()Ljava/util/List;
      86: iconst_2
      87: invokeinterface #90,  2           // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
      92: checkcast     #92                 // class java/lang/String
      95: invokestatic  #98                 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
      98: istore        4
     100: new           #15                 // class com/seanshubin/factor/analysis/ratio/Ratio
     103: dup
     104: iload_3
     105: iload         4
     107: invokespecial #101                // Method com/seanshubin/factor/analysis/ratio/Ratio."<init>":(II)V
     110: invokevirtual #104                // Method com/seanshubin/factor/analysis/ratio/Ratio.simplify:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
     113: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio toRatio(int);
    Code:
       0: new           #15                 // class com/seanshubin/factor/analysis/ratio/Ratio
       3: dup
       4: iload_1
       5: iconst_1
       6: invokespecial #101                // Method com/seanshubin/factor/analysis/ratio/Ratio."<init>":(II)V
       9: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio[] toRatioArray(java.util.List<com.seanshubin.factor.analysis.ratio.Ratio>);
    Code:
       0: aload_1
       1: ldc           #117                // String <this>
       3: invokestatic  #45                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_1
       7: checkcast     #119                // class java/util/Collection
      10: astore_2
      11: iconst_0
      12: istore_3
      13: aload_2
      14: astore        4
      16: aload         4
      18: iconst_0
      19: anewarray     #15                 // class com/seanshubin/factor/analysis/ratio/Ratio
      22: invokeinterface #123,  2          // InterfaceMethod java/util/Collection.toArray:([Ljava/lang/Object;)[Ljava/lang/Object;
      27: checkcast     #125                // class "[Lcom/seanshubin/factor/analysis/ratio/Ratio;"
      30: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio div(int, com.seanshubin.factor.analysis.ratio.Ratio);
    Code:
       0: aload_2
       1: ldc           #135                // String x
       3: invokestatic  #45                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokevirtual #137                // Method getONE:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      10: aload_2
      11: invokevirtual #140                // Method com/seanshubin/factor/analysis/ratio/Ratio.div:(Lcom/seanshubin/factor/analysis/ratio/Ratio;)Lcom/seanshubin/factor/analysis/ratio/Ratio;
      14: areturn

  public final com.seanshubin.factor.analysis.ratio.Ratio sum(java.util.List<com.seanshubin.factor.analysis.ratio.Ratio>);
    Code:
       0: aload_1
       1: ldc           #117                // String <this>
       3: invokestatic  #45                 // Method kotlin/jvm/internal/Intrinsics.checkNotNullParameter:(Ljava/lang/Object;Ljava/lang/String;)V
       6: aload_0
       7: invokevirtual #147                // Method getZERO:()Lcom/seanshubin/factor/analysis/ratio/Ratio;
      10: astore_2
      11: aload_1
      12: invokeinterface #151,  1          // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
      17: astore_3
      18: aload_3
      19: invokeinterface #157,  1          // InterfaceMethod java/util/Iterator.hasNext:()Z
      24: ifeq          48
      27: aload_3
      28: invokeinterface #161,  1          // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      33: checkcast     #15                 // class com/seanshubin/factor/analysis/ratio/Ratio
      36: astore        4
      38: aload_2
      39: aload         4
      41: invokevirtual #164                // Method com/seanshubin/factor/analysis/ratio/Ratio.plus:(Lcom/seanshubin/factor/analysis/ratio/Ratio;)Lcom/seanshubin/factor/analysis/ratio/Ratio;
      44: astore_2
      45: goto          18
      48: aload_2
      49: areturn

  public com.seanshubin.factor.analysis.ratio.Ratio$Companion(kotlin.jvm.internal.DefaultConstructorMarker);
    Code:
       0: aload_0
       1: invokespecial #168                // Method "<init>":()V
       4: return
}