{"version":3,"sources":["~lib/rt/common.ts","~lib/shared/typeinfo.ts","~lib/rt/pure.ts","~lib/rt/tlsf.ts","~lib/gc.ts","core/constants.ts","core/config.ts","core/graphics/colors.constants.ts","core/graphics/colors.ts","core/graphics/palette.ts","core/graphics/tiles.ts","core/sound/channel1.ts","core/sound/channel2.ts","core/sound/channel3.ts","core/sound/channel4.ts","core/sound/accumulator.ts","core/sound/sound.ts","core/interrupts/interrupts.ts","core/timers/timers.ts","core/serial/serial.ts","core/joypad/joypad.ts","core/debug/breakpoints.ts","core/graphics/lcd.ts","core/graphics/graphics.ts","core/memory/memory.ts","core/cpu/cpu.ts","core/cycles.ts","core/execute.ts","core/core.ts","core/memory/load.ts","core/memory/memoryMap.ts","core/memory/banking.ts","core/memory/store.ts","core/memory/dma.ts","core/helpers/index.ts","core/cpu/opcodes.ts","core/portable/portable.ts","core/graphics/backgroundWindow.ts","core/graphics/priority.ts","core/graphics/sprites.ts","core/memory/readTraps.ts","core/sound/duty.ts","core/sound/registers.ts","core/memory/writeTraps.ts","core/cpu/flags.ts","core/cpu/instructions.ts","core/cpu/cbOpcodes.ts","core/debug/debug-cpu.ts","core/debug/debug-graphics.ts","core/debug/debug-timer.ts","core/debug/debug-memory.ts"],"names":[],"mappings":"o8HGoRa,AAAO,AADF,OACc,oBAEnB,AAAO,AAAyB,AADhC,EAAY,KAC2B,SAAhC,EAAQ,qBAI1B,AAAI,EAAO,MAET,AAAK,AAAM,EAAQ,MAInB,AAAK,AAAO,EAAS,AADhB,EAAM,AAAW,MACI,IAAa,KACvC,EAAM,MAEG,AAAO,AAAgB,EAAK,KAArB,EAAK,qBAIvB,AAAW,OACX,AAAI,AAFO,SAED,EAAY,MACtB,AAAI,IAAM,EAAY,MAGtB,AAAI,EArIJ,AACE,EAA2B,AAAC,AAAkB,EAAjB,EAAM,IAAyB,UAQ9D,AACE,EAA2B,AAAC,AAAkB,EAAjB,EAAM,IAAyB,IAC5D,KA8HA,AAAI,AAAC,KAEa,AA7JlB,EAA2B,EAAM,SA6JN,EAAO,MAAhC,AApJF,EACA,KAsJE,AAAI,AAAC,KAAO,OAAc,EAAO,gBAzG1B,AAAO,mBAEP,AAAO,AADF,OACc,oBAM9B,AAAI,AAHY,qBAGA,KAEd,AAAI,AADU,AAAC,EAAY,GAAc,GAAkB,EAAY,MACzD,SAIZ,EAHA,AAAY,EAAM,IAClB,EAAe,AAAY,AAA0B,EAAzB,EAAY,SAE5B,AAtHhB,AAAyB,EAA2B,GAAkB,KAAe,cA4HrF,AAAI,EAAY,KAQZ,EALS,AAAO,AADH,AApIjB,AAAmB,EAA2B,aAqIf,oBAEzB,AADU,AAAC,EAAW,GAAc,GAAkB,EAAY,MACxD,SACZ,AAAY,EAAM,IAClB,EAAc,AAAY,AAAyB,EAAxB,EAAW,SAC9B,UAKZ,EAAe,EAAY,MAKhB,AAAO,AAAyB,AADhC,EAAY,KAC2B,SAAhC,EAAQ,qBACf,AAAO,AAAoD,EAApD,AAA4C,EAA5C,EAA2B,qBAG7C,AAAa,EAA2B,GAAiB,KAIzD,AAAI,EAAO,MAET,AAAK,AAAM,EAAQ,MAInB,AAAK,AAAO,EAAS,AADhB,EAAM,AAAW,MACI,IAAa,KACvC,EAAM,MAEG,AAAO,AAAgB,EAAK,KAArB,EAAK,qBA5FvB,AACE,EAA2B,AAAC,AAAkB,EAAjB,EAAM,IAAyB,SA+F9D,EAAa,KACb,EAAa,KACb,AAAI,IAAM,EAAY,MAzFtB,AACE,EAA2B,AAAC,AAAkB,EAAjB,EAAM,IAAyB,IAC5D,KA2FF,OAAe,EAAK,OAhHpB,AACE,EAA2B,EAAM,MACjC,AAXF,AACE,KAyHiC,EAAK,aAkH7B,AAEP,AAEA,AAAE,EAAM,MAFR,AACA,AAAE,EAAQ,MADV,EAAS,sBAQb,AAAI,AAFO,AA7MT,UAgNW,AAAO,EAAS,EAA0B,oBAGrD,AAAI,AAA0B,EAA1B,EAAQ,MACV,EACA,AAAW,OADX,EAAS,QAON,AACE,EAAS,EAA0B,sBAK5C,AAAI,AADO,EAAM,KACN,OAOX,EAAc,AAAmB,EAAW,GAA9B,AAFC,EAAQ,GAEE,OACzB,EAAY,KACZ,EAAY,KAIZ,AADO,AAAkB,EAAQ,GAAO,KAC1B,KACd,AAtOE,EACA,MAuOF,AAAY,EAAM,UAuClB,AAAI,AAAC,AADM,OAKT,AAAI,EAAc,AAFA,OAEe,AAAY,EAAc,KAAe,WACnE,KACP,GAAa,KACb,UACwB,EAAK,KAC3B,cACK,AAAc,MAAG,EAAK,KACzB,AAAkB,EAAJ,SAAN,SAD0B,AAAE,WAFF,AAAE,WAY5B,GAAM,GAAU,EAAiB,KAE7C,AAAO,MAET,QAxKA,AAAI,EAAO,MAET,AAAK,AAAM,EAAQ,QAKD,EAAO,SAIb,AAHR,EAAQ,EAAM,EAAW,AAAW,MAAU,SAGtB,AADvB,EAAM,AAHO,MAIe,IAAa,KAC9C,EAAM,MAEG,AAAO,AAAgB,EAAK,KAArB,EAAK,qBAKlB,WAF0B,EAAM,QA7KrC,AACE,EAA2B,AAAC,AAAkB,AA0LZ,GA1LL,EAAM,IAAyB,QAiLvD,AADO,KAAc,EAAO,EAAK,SAMzB,AAAO,AA1MtB,AACE,EAA2B,AAuMpB,AAAW,KAvMe,4BA0MN,AAAS,2BAYtC,AAAgB,OACL,AAAS,EAAO,mBAI3B,AAAI,AADY,AAAC,EAAY,GAAc,KAC1B,KACf,EAAe,EAAQ,EAAY,OAGnC,AADY,AAA8D,EAA5C,EAA2B,MAC1C,AAAC,EAAY,GAAkB,MAC9C,AAAY,EAAM,KAIlB,EAAe,EAAY,MArR7B,AAAyB,EAA2B,KAAkB,KAAe,IAsRnF,cAA0B,aAyHjB,AAAQ,kBAvCnB,AAAI,AAwC0B,IAxClB,SAA+B,eA0CvC,AAAC,AADO,AAAY,EAAM,AAxC9B,AAAkB,AAAC,EAAO,GAAW,sBA2CtB,AAAc,IAEd,AAAc,IAEzB,AAAI,AAAC,AADG,AAAY,EAAM,SA1D9B,AAAkB,AAAO,AAAC,AARtB,EAAO,SAET,EAAQ,AAAC,EAAM,EAAW,AAAW,KAAU,QAKzC,EAAkB,AAAM,AAAC,AADf,IACqC,GAAM,GAAkB,AArQ7E,SAsQ+B,KAAU,KAAa,KAEpD,AAAY,AADM,EAAa,UACJ,KAC7B,AAAI,AAAY,IAAe,QAGvB,EAAM,EAAsB,GAAI,EAAqB,KAwD9C,AAAO,AADV,AAA8B,EAAM,yBASvC,AAAO,AAAC,KAAe,GAAe,mBACjD,EAAe,KACf,EAAa,KACb,EAAe,KACf,AAAY,EAAM,IAClB,AAAa,EAAM,EAAc,SAuEjC,AAAO,AACS,EAAmB,EAAM,IACrC,QDnUJ,AAAI,EAAM,MAtKV,AAAO,AAAC,AADG,AAuKsB,AAAkB,EAAM,UAtK1C,OAAoB,AAAC,EAAO,GAAK,wBAChD,EAAW,EAAO,MAEP,AAAS,KAAW,yBA0K/B,AAAI,EAAM,MAAa,AAAU,AAAkB,EAAM,+B4BlQjD,AADoB,EAAiB,qBAKzC,AAAI,KACF,AAAI,KAQF,AAAI,EAAgB,MAOpB,AAAI,AAA0B,EAAgB,MAA1C,EAAgB,QAGf,AAAI,EAAmB,EAAgB,IAAlC,SASP,EAAgB,QCsDa,EAAgB,OAAxD,AAAwC,EAA3B,AALT,EAAkB,AADI,MACrB,MACc,MAIN,ID/CiC,QAanC,OAA+D,AAPlE,KAEW,AD/DE,AAAkC,SC+DyB,OAKN,MAK/D,ACmCoC,EAAlC,AAAS,GAAT,YD9BF,SAkBA,EAAyE,AAAU,AAJ5D,EAH1B,KACW,AD1FE,AAAkC,SC0FyB,SAE/D,EAAa,IAIsD,WAhFpF,AAqFW,QAvEM,EAAgB,ULgHjC,AAAqB,KACrB,AAAgB,KAChB,AAAgB,KAChB,AAAgB,KAChB,AAAgB,KAChB,AAAgB,KAChB,AAAgB,KAChB,AAAgB,KAChB,AAAgB,KAChB,AAAmB,KACnB,AAAqB,KACrB,AAAoB,KACpB,AAAmB,KACnB,AAAmB,KACnB,AAAgB,KAChB,AAAgB,KAGhB,AAAI,OAIJ,AAAI,KAEF,AAAgB,KAChB,AAAgB,MAChB,AAAgB,KAChB,AAAgB,KAChB,AAAgB,MAChB,AAAgB,MAChB,AAAgB,KAChB,AAAgB,MAGhB,AAAgB,KAChB,AAAgB,MAChB,AAAgB,KAChB,AAAgB,KAChB,AAAgB,KAChB,AAAgB,MAChB,AAAgB,KAChB,AAAgB,OAIlB,AAAqB,MACrB,AAAmB,WjBjGnB,4BAAQ,mBAEJ,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,MAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,MAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,SAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,MACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,KACtB,AAAmB,OAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,OAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,MACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAInB,AAAiB,IACjB,AAAqB,MACrB,AAAoB,OACpB,AAAiB,OAEjB,AAAmB,IACnB,AAAuB,MACvB,AAAsB,OACtB,AAAmB,OAEnB,AAAmB,IACnB,AAAuB,MACvB,AAAsB,OACtB,AAAmB,UAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,KACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,MACtB,AAAmB,OAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,KACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,MACtB,AAAmB,OAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,SAWvB,wBAAQ,EACD,QAgBA,QAgBA,OAgBA,QAgBA,QACA,QAgBA,QACA,QAgBA,QACA,QACA,QACA,QAgBA,OACA,QACA,QACA,QAgBA,QAgBA,QAgBA,QAgBA,SAvLH,AAAiB,OACjB,AAAqB,OACrB,AAAoB,MACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,MACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,MACtB,AAAmB,OAGnB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,KACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,KACtB,AAAmB,OAGnB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,MACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAGnB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,IACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAEnB,AAAmB,IACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,UAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,QAInB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,MAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAMnB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,KAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,OAMnB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,MACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,KACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,SAGnB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,OAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,KACtB,AAAmB,OAGnB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,MACvB,AAAsB,OACtB,AAAmB,MAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,KACtB,AAAmB,OAGnB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,KACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,MACtB,AAAmB,OAGnB,AAAiB,OACjB,AAAqB,OACrB,AAAoB,OACpB,AAAiB,IAEjB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,OACtB,AAAmB,IAEnB,AAAmB,OACnB,AAAuB,OACvB,AAAsB,KACtB,AAAmB,WepXvB,AAAyB,KACzB,AAAgC,KAChC,AAA4B,KAC5B,AAAmB,KACnB,AAAmB,KACnB,AAAmB,KACnB,AAAmB,KAEnB,AAA4B,MAE5B,AAAI,KACF,AS/JQ,AAAkC,MAAgB,MTiK1D,ASjKQ,AAAkC,MAAgB,MTmK1D,ASnKQ,AAAkC,MAAgB,OTsK1D,AStKQ,AAAkC,MAAgB,MTwK1D,ASxKQ,AAAkC,MAAgB,MTyK1D,ASzKQ,AAAkC,MAAgB,MT0K1D,AS1KQ,AAAkC,MAAgB,MT2K1D,AS3KQ,AAAkC,MAAgB,OTkL5D,AAA4B,MAG5B,ASrLU,AAAkC,MAAgB,MTwL5D,ASxLU,AAAkC,MAAgB,KTyL5D,ASzLU,AAAkC,MAAgB,KT4L5D,AAAI,KACF,AAAI,KAEF,AAA4B,KAC5B,AShMM,AAAkC,MAAgB,KTiMxD,ASjMM,AAAkC,MAAgB,MTkMxD,ASlMM,AAAkC,MAAgB,MTqMxD,AAA4B,KAC5B,AStMM,AAAkC,MAAgB,KTuMxD,ASvMM,AAAkC,MAAgB,QxBgD5D,AAA6B,Ie2J7B,EfzJA,AAAI,KAKJ,EAAI,GACG,MAQF,AAAa,OAAQ,EAAK,MAC7B,EAAiB,AqBjEE,AAAkC,UrBgEhB,WAOvC,AAA2B,AADX,EAAgB,WQwIhC,AAAsB,KACtB,AAA4B,KAC5B,AAA6B,KAC7B,AAA0C,KAC1C,AAA0C,KAC1C,AAA0C,KAC1C,AAA0C,KAC1C,AAA2C,KAC3C,AAA2C,KAC3C,AAA2C,KAC3C,AAA2C,KAC3C,AAA2B,KAC3B,AAAkC,KAClC,AAA+B,KAC/B,AAAuB,KACvB,AAAwB,KLkEtB,AqB/RQ,AAAkC,MAAgB,MrBgS1D,AqBhSQ,AAAkC,MAAgB,MrBiS1D,AqBjSQ,AAAkC,MAAgB,MrBkS1D,AqBlSQ,AAAkC,MAAgB,MrBmS1D,AqBnSQ,AAAkC,MAAgB,MrBuS1D,AAAI,KACF,AqBxSM,AAAkC,MAAgB,KrBySxD,AqBzSM,AAAkC,MAAgB,KrB0SxD,AqB1SM,AAAkC,MAAgB,KrB2SxD,AqB3SM,AAAkC,MAAgB,OpB4O1D,AoB5OQ,AAAkC,MAAgB,MpB6O1D,AoB7OQ,AAAkC,MAAgB,KpB8O1D,AoB9OQ,AAAkC,MAAgB,KpB+O1D,AoB/OQ,AAAkC,MAAgB,KpBgP1D,AoBhPQ,AAAkC,MAAgB,MnB2P1D,AmB3PQ,AAAkC,MAAgB,MnB4P1D,AmB5PQ,AAAkC,MAAgB,MnB6P1D,AmB7PQ,AAAkC,MAAgB,MnB8P1D,AmB9PQ,AAAkC,MAAgB,KnB+P1D,AmB/PQ,AAAkC,MAAgB,MnBkQ1D,AAA6B,KClC7B,AkBhOQ,AAAkC,MAAgB,MlBiO1D,AkBjOQ,AAAkC,MAAgB,MlBkO1D,AkBlOQ,AAAkC,MAAgB,KlBmO1D,AkBnOQ,AAAkC,MAAgB,KlBoO1D,AkBpOQ,AAAkC,MAAgB,MhBsO5D,AgBtOU,AAAkC,MAAgB,MhB+C1D,AAA4B,KAC5B,AAA6B,KAwL/B,AgBxOU,AAAkC,MAAgB,MhB8D1D,AAA0C,KAC1C,AAA0C,KAC1C,AAA0C,KAC1C,AAA0C,KAC1C,AAA2C,KAC3C,AAA2C,KAC3C,AAA2C,KAC3C,AAA2C,KAqK7C,AgB1OU,AAAkC,MAAgB,MhB2O5D,AA/J6B,KAmK7B,AAAI,KACF,AgBhPQ,AAAkC,MAAgB,KhB+C1D,AAA4B,KAC5B,AAA6B,KAkM7B,AgBlPQ,AAAkC,MAAgB,KhB8D1D,AAA0C,KAC1C,AAA0C,KAC1C,AAA0C,KAC1C,AAA0C,KAC1C,AAA2C,KAC3C,AAA2C,KAC3C,AAA2C,KAC3C,AAA2C,KA+K3C,AgBpPQ,AAAkC,MAAgB,MhBqP1D,AAzK2B,MDrD7B,AAAkC,KAClC,AAAkC,KAClC,AAAkC,KAClC,AAAkC,KAClC,AAAsC,KACtC,AAAsC,KACtC,AAAsC,KACtC,AAAsC,KACtC,AAAiD,MACjD,AAAkD,MAClD,AAAsC,KACtC,AAAuC,KACvC,AAAsC,Wa6BtC,AAAI,AAHU,AC7DO,AAAkC,UDgEvC,SAAS,AAA8B,EAAY,MAA1C,MACvB,AAAiB,MAEjB,AAAiB,MAInB,KFpCA,AAA2B,SAC3B,AAAmB,KACnB,AAAgB,KCMhB,AAA0B,SAC1B,AAAmB,KACnB,AAAgB,KCgChB,AAAI,IACF,AAAqB,MAErB,AAAqB,MAMvB,EJiCA,AAA6B,KAC7B,AAA8B,KAO9B,AAAmB,AAHC,AK5HC,AAAkC,cLgIvD,AAAgB,AAAyB,EAAiB,KAA1C,EAAiB,OACjC,AAAgB,AAAyB,EAAiB,KAA1C,EAAiB,OACjC,AAAgB,AAAyB,EAAiB,KAA1C,EAAiB,OACjC,AAAgB,AAAyB,EAAiB,KAA1C,EAAiB,OAEjC,AAAwB,KACxB,AAAwB,KAGxB,AQzIU,AAAkC,MAAgB,KR0I5D,AQ1IU,AAAkC,MAAgB,KCG1D,ADHQ,AAAkC,MAAgB,MCI1D,ADJQ,AAAkC,MAAgB,MCK1D,ADLQ,AAAkC,MAAgB,MCM1D,ADNQ,AAAkC,MAAgB,MCO1D,ADPQ,AAAkC,MAAgB,MJyF5D,EnBzEA,AAAI,KAEF,AuBlBQ,AAAkC,MAAgB,MvBmB1D,AuBnBQ,AAAkC,MAAgB,MvBoB1D,AuBpBQ,AAAkC,MAAgB,MvBqB1D,AuBrBQ,AAAkC,MAAgB,MvBwB1D,AuBxBQ,AAAkC,MAAgB,MvByB1D,AuBzBQ,AAAkC,MAAgB,MvB0B1D,AuB1BQ,AAAkC,MAAgB,MvB2B1D,AuB3BQ,AAAkC,MAAgB,OvB+B5D,AAAI,AAAsB,KAAtB,MAEF,AuBjCQ,AAAkC,MAAgB,KvBkC1D,AuBlCQ,AAAkC,MAAgB,OJ2F5D,EXhEE,AAAsC,KACtC,AAAmC,KACnC,AAAqC,KACrC,AAAsC,KACtC,AAAsC,KAEtC,AAAoC,KejCtC,AAAU,AAAkC,MfmHyB,KAtEnE,AAAwC,KACxC,AAAqC,KACrC,AAAuC,KACvC,AAAwC,KACxC,AAAwC,KAExC,AAAsC,MenDxC,AAAU,AAAkC,MfuHyB,MC2DrE,AAAuB,KACvB,AAAyB,KACzB,AAAsB,KACtB,AAAqB,KACrB,AAAsB,KACtB,AAAyB,KACzB,AAAmC,KACnC,AAA8B,KAE1B,KAEF,Ac7LQ,AAAkC,MAAgB,Kd8L1D,AAAyB,OASzB,AcvMQ,AAAkC,MAAgB,MdwM1D,AAAyB,QALzB,AcnMQ,AAAkC,MAAgB,MdoM1D,AAAyB,MAc3B,AAAI,KACF,AAAI,MAKF,AcxNM,AAAkC,MAAgB,KdyNxD,AAAyB,OC1L7B,AAAuB,KACvB,AAAiC,KAE7B,KAEF,AapCQ,AAAkC,MAAgB,MboB1D,AAA0B,MAoB1B,AaxCQ,AAAkC,MAAgB,MboB1D,AAA0B,MAC1B,AAA2B,KS0E7B,AAKI,KAEF,AItGQ,AAAkC,MAAgB,MJuG1D,AIvGQ,AAAkC,MAAgB,MJwG1D,AIxGQ,AAAkC,MAAgB,MJyG1D,AIzGQ,AAAkC,MAAgB,MJ2G1D,AI3GQ,AAAkC,MAAgB,MJ+G1D,AI/GQ,AAAkC,MAAgB,MJgH1D,AIhHQ,AAAkC,MAAgB,OJkH1D,AIlHQ,AAAkC,MAAgB,MJmH1D,AInHQ,AAAkC,MAAgB,MJoH1D,AIpHQ,AAAkC,MAAgB,MJqH1D,AIrHQ,AAAkC,MAAgB,MJuH1D,AIvHQ,AAAkC,MAAgB,UJwC5D,AAAuB,EAAgB,KACvC,AAA6B,EAAsB,KACnD,AAA8B,EAAuB,KACrD,AAAiC,EAA0B,KAC3D,AAA+B,EAAwB,KACvD,AAA0C,EAAmC,KAC7E,AAAgC,EAAyB,KACzD,AAAuB,EAAgB,KACvC,AAAqB,EAAc,KACnC,AAA8B,EAAuB,KAErD,KAhCA,OZmGE,AAAW,GAAqD,MAChE,AAAW,GAAqD,MAGhE,AgBlFQ,GAAQ,AhBkFsE,SACtF,AgBnFQ,GAAQ,AhBmFsE,SACtF,AgBpFQ,GAAQ,AhBoFsE,SACtF,AgBrFQ,GAAQ,AhBqFsE,SACtF,AgBtFQ,GAAQ,AhBsFsE,SACtF,AgBvFQ,GAAQ,AhBuFsE,SACtF,AgBxFQ,GAAQ,AhBwFsE,SACtF,AgBzFQ,GAAQ,AhByFsE,SAGtF,AgB5FQ,GAAQ,AhB4FsE,SAGtF,AAAW,GAAqD,MAChE,AAAU,GAAqD,MAG/D,AAAU,GAAqD,MAG/D,AAAU,GAAqD,MAC/D,AAAU,GAAqD,MAC/D,AAAU,GAAqD,MAC/D,AAAU,GAAqD,MAC/D,AgB1GQ,GAAQ,AhB0GsE,SACtF,AgB3GQ,GAAQ,AhB2GsE,SACtF,AgB5GQ,GAAQ,AhB4GsE,SACtF,AgB7GQ,GAAQ,AhB6GsE,SACtF,AAAU,GAAqD,MAC/D,AAAU,GAAqD,MAC/D,AgBhHQ,GAAQ,AhBgHsE,SACtF,AgBjHQ,GAAQ,AhBiHsE,aLqCtF,AAAW,GAAwD,KAGnE,AAAU,GAAwD,KAClE,AqB1JQ,GAAQ,ArB0JyE,QACzF,AAAU,GAAwD,KAGlE,AAAU,GAAwD,KAClE,AAAW,GAAwD,KAGnE,AAAU,GAAwD,KAClE,AqBnKQ,GAAQ,ArBmKyE,QACzF,AAAU,GAAwD,KAGlE,AAAU,GAAwD,KAGlE,AqB1KQ,GAAQ,ArB0KyE,QACzF,AAAU,GAAwD,KAGlE,AqB9KQ,GAAQ,ArB8KyE,QACzF,AqB/KQ,GAAQ,ArB+KyE,QACzF,AAAW,GAAwD,KACnE,AAAW,GAAwD,KACnE,AAAW,GAAwD,KACnE,AqBnLQ,GAAQ,ArBmLyE,QACzF,AAAW,GAAwD,KACnE,AAAW,GAAwD,KAGnE,AAAU,GAAwD,KAClE,AAAU,GAAwD,KAGlE,AqB5LQ,GAAQ,ArB4LyE,QACzF,AAAW,GAAwD,KACnE,AAAW,GAAwD,KACnE,AqB/LQ,GAAQ,ArBiMd,YcnJF,AAAU,GAAmD,MAC7D,AAAU,GAAmD,MAC7D,AAAU,GAAmD,MAC7D,AAAU,GAAmD,MAC7D,AAAU,GAAmD,MAC7D,AAAU,GAAmD,MAC7D,AAAU,GAAmD,MAC7D,AAAU,GAAmD,MAE7D,AAAW,GAAmD,MAC9D,AAAW,GAAmD,MAE9D,AAAW,GAAmD,MAE9D,AO5DQ,GAAQ,AP4DoE,SACpF,AO7DQ,GAAQ,AP6DoE,SACpF,AO9DQ,GAAQ,AP8DoE,SACpF,AO/DQ,GAAQ,AP+DoE,SAEpF,AOjEQ,GAAQ,APiEoE,SACpF,AOlEQ,GAAQ,APkEoE,SACpF,AOnEQ,GAAQ,APmEoE,SFlBpF,AAAW,GAAwD,MACnE,AAAU,GAAwD,MAClE,AAAU,GAAwD,MAClE,AAAU,GAAwD,MAClE,AAAU,GAAwD,MAClE,AAAU,GAAwD,MAGlE,AAAU,GAAwD,MAClE,AAAU,GAAwD,MAClE,AS3DQ,GAAQ,AT2DyE,SACzF,AS5DQ,GAAQ,AT4DyE,SACzF,AS7DQ,GAAQ,AT6DyE,SACzF,AS9DQ,GAAQ,AT8DyE,SACzF,AS/DQ,GAAQ,AT+DyE,SACzF,AShEQ,GAAQ,ATgEyE,SACzF,ASjEQ,GAAQ,ATiEyE,SACzF,ASlEQ,GAAQ,ATkEyE,SNzCzF,AezBQ,GAAQ,AfyB2E,SAC3F,Ae1BQ,GAAQ,Af0B2E,SAG3F,AAAU,GAA0D,MACpE,Ae9BQ,GAAQ,Af8B2E,SAC3F,Ae/BQ,GAAQ,Af+B2E,SAC3F,AehCQ,GAAQ,AfgC2E,SAC3F,AejCQ,GAAQ,AfiC2E,SAC3F,AelCQ,GAAQ,AfkC2E,SAG3F,AAAU,GAA0D,MACpE,AetCQ,GAAQ,AfsC2E,SAC3F,AevCQ,GAAQ,AfuC2E,SAC3F,AexCQ,GAAQ,AfwC2E,SAC3F,AezCQ,GAAQ,AfyC2E,SAC3F,Ae1CQ,GAAQ,Af0C2E,SG1B3F,AAAW,GAAsD,MAEjE,AYlBQ,GAAQ,AZkBuE,SACvF,AYnBQ,GAAQ,AZmBuE,SIgBvF,AAAW,GAAsD,MACjE,AAAW,GAAsD,MAEjE,AQtCQ,GAAQ,ARsCuE,SACvF,AQvCQ,GAAQ,ARuCuE,SAEvF,AQzCQ,GAAQ,ARyCuE,SACvF,AQ1CQ,GAAQ,AR0CuE,SACvF,AQ3CQ,GAAQ,AR2CuE,SACvF,AQ5CQ,GAAQ,AR4CuE,SACvF,AQ7CQ,GAAQ,AR6CuE,SAEvF,AAAW,GAAsD,MACjE,AQhDQ,GAAQ,ARgDuE,SACvF,AAAW,GAAsD,MACjE,AAAW,GAAsD,MACjE,AAAW,GAAsD,MN0CjE,AAAW,GAAsD,MAGjE,AAAW,GAAsD,MAGjE,AAAW,GAAsD,MACjE,AcpGQ,GAAQ,AdoGuE,SACvF,AcrGQ,GAAQ,AdqGuE,SACvF,AAAW,GAAsD,MAGjE,AAAW,GAAsD,MAGjE,Ac5GQ,GAAQ,Ad4GuE,SACvF,AAAW,GAAsD,MUHnE,EACA,EhBaE,AAAW,GAAwD,KAMnE,AAAU,GAAwD,KAClE,AAAW,GAAwD,KAGnE,AAAU,GAAwD,KAClE,AoBnIQ,GAAQ,ApBmIyE,QACzF,AAAU,GAAwD,KAGlE,AAAU,GAAwD,KAGlE,AoB1IQ,GAAQ,ApB0IyE,QACzF,AAAU,GAAwD,KAGlE,AoB9IQ,GAAQ,ApB8IyE,QACzF,AoB/IQ,GAAQ,ApB+IyE,QACzF,AAAW,GAAwD,KACnE,AAAW,GAAwD,KACnE,AAAW,GAAwD,KACnE,AoBnJQ,GAAQ,ApBmJyE,QACzF,AAAW,GAAwD,KACnE,AAAW,GAAwD,KAGnE,AAAU,GAAwD,KAClE,AAAU,GAAwD,KC3ClE,AAAW,GAAwD,KAMnE,AAAW,GAAwD,KAGnE,AAAU,GAAwD,KAGlE,AAAU,GAAwD,KAGlE,AmB7HQ,GAAQ,AnB6HyE,QACzF,AAAU,GAAwD,KAGlE,AmBjIQ,GAAQ,AnBiIyE,QACzF,AmBlIQ,GAAQ,AnBkIyE,QACzF,AAAW,GAAwD,KACnE,AAAW,GAAwD,KAEnE,AAAW,GAAwD,MAGnE,AAAW,GAAwD,MACnE,AAAU,GAAwD,MAClE,AmB3IQ,GAAQ,AnB2IyE,SACzF,AAAW,GAAwD,MC5BnE,AAAW,GAAwD,MAMnE,AAAW,GAAwD,MAGnE,AAAU,GAAwD,MAClE,AkB1HQ,GAAQ,AlB0HyE,SACzF,AAAU,GAAwD,MAGlE,AAAU,GAAwD,MAClE,AkB/HQ,GAAQ,AlB+HyE,SACzF,AAAU,GAAwD,MAGlE,AkBnIQ,GAAQ,AlBmIyE,SAGzF,AkBtIQ,GAAQ,AlBsIyE,SACzF,AkBvIQ,GAAQ,AlBuIyE,SACzF,AAAW,GAAwD,MACnE,AAAW,GAAwD,MACnE,AkB1IQ,GAAQ,AlB0IyE,SACzF,AAAW,GAAwD,MACnE,AAAW,GAAwD,MAGnE,AAAW,GAAwD,Mc9BrE,QZgIA,AAAwB,SA1HtB,AAA4B,AAAU,SACtC,AAA6B,AAAU,SAGvC,AAA0C,AapIrC,AAAc,MAAU,MbqI7B,AAA0C,AarIrC,AAAc,MAAU,MbsI7B,AAA0C,AatIrC,AAAc,MAAU,MbuI7B,AAA0C,AavIrC,AAAc,MAAU,MbwI7B,AAA2C,AaxItC,AAAc,MAAU,MbyI7B,AAA2C,AazItC,AAAc,MAAU,Mb0I7B,AAA2C,Aa1ItC,AAAc,MAAU,Mb2I7B,AAA2C,Aa3ItC,AAAc,MAAU,Mb8I7B,AAA2B,Aa9ItB,AAAc,MAAU,MbiJ7B,AAAkC,AAAU,SAC5C,AAAuB,AAAS,SAGhC,AAA+B,AAAS,SAGxC,AAAkC,AAAS,SAC3C,AAAkC,AAAS,SAC3C,AAAkC,AAAS,SAC3C,AAAkC,AAAS,SAC3C,AAAsC,Aa5JjC,AAAc,MAAU,Mb6J7B,AAAsC,Aa7JjC,AAAc,MAAU,Mb8J7B,AAAsC,Aa9JjC,AAAc,MAAU,Mb+J7B,AAAsC,Aa/JjC,AAAc,MAAU,MbgK7B,AAAiD,AAAS,SAC1D,AAAkD,AAAS,SAC3D,AAAsC,AalKjC,AAAc,MAAU,MbmK7B,AAAuC,AanKlC,AAAc,MAAU,MbsK7B,AAoFsB,SLzCtB,AAAwB,AAAU,AiBzGK,AAAK,EAAL,GAAlC,SjB4GL,AAA2B,AAAS,QACpC,AAAsB,AkBrNjB,AAAc,MAAU,KlBsN7B,AAA0B,AAAS,QAGnC,AAAoB,AAAS,QAC7B,AAA0B,AAAU,QAGpC,AAA8B,AAAS,QACvC,AAA+B,AkB9N1B,AAAc,MAAU,KlB+N7B,AAA8B,AAAS,QAGvC,AAA4B,AAAS,QAGrC,AAA6B,AkBrOxB,AAAc,MAAU,KlBsO7B,AAA4B,AAAS,QAGrC,AAAqB,AkBzOhB,AAAc,MAAU,KlB0O7B,AAAwB,AkB1OnB,AAAc,MAAU,KlB2O7B,AAAqB,AAAU,QAC/B,AAA0B,AAAU,QACpC,AAA2B,AAAU,QACrC,AAAuC,AkB9OlC,AAAc,MAAU,KlB+O7B,AAAyB,AAAU,QACnC,AAAkB,AAAU,QAG5B,AAAqB,AAAS,QAC9B,AAAkC,AAAS,QAG3C,AAA0B,AkBvPrB,AAAc,MAAU,KlBwP7B,AAAwB,AAAS,QACjC,AAAgC,AAAS,QACzC,AAAkD,AkB1P7C,AAAc,MAAU,SjBwK7B,AAAwB,AAAU,AgBhEK,AAAK,EAAL,GAAlC,ShBsEL,AAAoB,AAAS,QAC7B,AAA0B,AAAU,QAGpC,AAA8B,AAAS,QACvC,AAA+B,AiBnL1B,AAAc,MAAU,KjBoL7B,AAA8B,AAAS,QAGvC,AAA4B,AAAS,QAGrC,AAA6B,AiB1LxB,AAAc,MAAU,KjB2L7B,AAA4B,AAAS,QAGrC,AAAqB,AiB9LhB,AAAc,MAAU,KjB+L7B,AAAwB,AiB/LnB,AAAc,MAAU,KjBgM7B,AAAqB,AAAU,QAC/B,AAA0B,AAAU,QACpC,AAA2B,AAAU,QACrC,AAAuC,AiBnMlC,AAAc,MAAU,KjBoM7B,AAAyB,AAAU,QACnC,AAAkB,AAAU,QAG5B,AAAqB,AAAS,QAC9B,AAAkC,AAAS,YavH3C,AAAgB,AAAS,SACzB,AAAgB,AAAS,SACzB,AAAgB,AAAS,SACzB,AAAgB,AAAS,SACzB,AAAgB,AAAS,SACzB,AAAgB,AAAS,SACzB,AAAgB,AAAS,SACzB,AAAgB,AAAS,SAEzB,AAAmB,AAAU,SAC7B,AAAqB,AAAU,SAE/B,AAAoB,AAAU,SAE9B,AAAmB,AIhGd,AAAc,MAAU,MJiG7B,AAAmB,AIjGd,AAAc,MAAU,MJkG7B,AAAgB,AIlGX,AAAc,MAAU,MJmG7B,AAAgB,AInGX,AAAc,MAAU,MJqG7B,AAAqB,AIrGhB,AAAc,MAAU,MJsG7B,AAAiB,AItGZ,AAAc,MAAU,MJuG7B,AAAqB,AIvGhB,AAAc,MAAU,MNiF7B,AAAgC,AAAU,SAC1C,AAA4B,AAAS,AKsBE,AAAK,GAAL,GAAlC,ULrBL,AAAmB,AAAS,SAC5B,AAAmB,AAAS,SAC5B,AAAmB,AAAS,SAC5B,AAAmB,AAAS,SAG5B,AAAqB,AAAS,SAC9B,AAAyB,AAAS,SAClC,AAAc,AM3FT,AAAc,MAAU,MN4F7B,AAAiC,AM5F5B,AAAc,MAAU,MN6F7B,AAA2B,AM7FtB,AAAc,MAAU,MN8F7B,AAA6B,AM9FxB,AAAc,MAAU,MN+F7B,AAA6B,AM/FxB,AAAc,MAAU,MNgG7B,AAAqB,AMhGhB,AAAc,MAAU,MNiG7B,AAA0B,AMjGrB,AAAc,MAAU,MNkG7B,AAAuB,AMlGlB,AAAc,MAAU,MZyD7B,AAAmC,AYzD9B,AAAc,MAAU,MZ0D7B,AAAwC,AY1DnC,AAAc,MAAU,MZ6D7B,AAAoC,AAAS,SAC7C,AAAsC,AY9DjC,AAAc,MAAU,MZ+D7B,AAAmC,AY/D9B,AAAc,MAAU,MZgE7B,AAAqC,AYhEhC,AAAc,MAAU,MZiE7B,AAAsC,AYjEjC,AAAc,MAAU,MZkE7B,AAAsC,AYlEjC,AAAc,MAAU,MZqE7B,AAAsC,AAAS,SAC/C,AAAwC,AYtEnC,AAAc,MAAU,MZuE7B,AAAqC,AYvEhC,AAAc,MAAU,MZwE7B,AAAuC,AYxElC,AAAc,MAAU,MZyE7B,AAAwC,AYzEnC,AAAc,MAAU,MZ0E7B,AAAwC,AY1EnC,AAAc,MAAU,MTiC7B,AAA+B,AAAU,SAEzC,AAAoB,ASnCf,AAAc,MAAU,MToC7B,AAAsB,ASpCjB,AAAc,MAAU,MLiE7B,AAAwB,AAAU,SAClC,AAAwB,AAAU,SAElC,AAA6B,AKpExB,AAAc,MAAU,MLqE7B,AAA8B,AKrEzB,AAAc,MAAU,MLuE7B,AAAmB,AKvEd,AAAc,MAAU,MLwE7B,AAAgB,AKxEX,AAAc,MAAU,MLyE7B,AAAgB,AKzEX,AAAc,MAAU,ML0E7B,AAAgB,AK1EX,AAAc,MAAU,ML2E7B,AAAgB,AK3EX,AAAc,MAAU,ML6E7B,AAAmB,AAAU,SAC7B,AAA4B,AK9EvB,AAAc,MAAU,ML+E7B,AAA2C,AAAU,SACrD,AAA0B,AAAU,SACpC,AAA+B,AAAU,SN2CzC,AAAuB,AAAU,SAGjC,AAAyB,AAAU,SAGnC,AAAsB,AAAU,SAChC,AAAmC,AWnI9B,AAAc,MAAU,MXoI7B,AAA8B,AWpIzB,AAAc,MAAU,MXqI7B,AAA0B,AAAU,SAGpC,AAAqB,AAAU,SAG/B,AAAsB,AW3IjB,AAAc,MAAU,MX4I7B,AAAyB,AAAU,SULrC,EACA,EACA,EfkBE,AAAwB,AAAU,AenDK,AAAK,EAAL,GAAlC,SfyDL,AAA0B,AAAU,QAGpC,AAA0B,AAAS,QAGnC,AAA4B,AAAS,QAGrC,AAA6B,AgB1KxB,AAAc,MAAU,KhB2K7B,AAA4B,AAAS,QAGrC,AAAqB,AgB9KhB,AAAc,MAAU,KhB+K7B,AAAwB,AgB/KnB,AAAc,MAAU,KhBgL7B,AAAqB,AAAU,QAC/B,AAA0B,AAAU,QAEpC,AAAyB,AAAU,SAGnC,AAA6B,AAAU,SACvC,AAAsB,AAAU,SAChC,AAA6B,AgBxLxB,AAAc,MAAU,MhByL7B,AAAwB,AAAU,SC3BlC,AAAwB,AAAU,ActDK,AAAK,GAAL,GAAlC,Ud4DL,AAA0B,AAAS,SAGnC,AAA8B,AAAS,SACvC,AAA+B,AexK1B,AAAc,MAAU,MfyK7B,AAA8B,AAAS,SAGvC,AAA0B,AAAS,SACnC,AAAyB,Ae7KpB,AAAc,MAAU,Mf8K7B,AAA2B,AAAS,SAGpC,AAA6B,AejLxB,AAAc,MAAU,MfoL7B,AAAqB,AepLhB,AAAc,MAAU,MfqL7B,AAAwB,AerLnB,AAAc,MAAU,MfsL7B,AAA0B,AAAU,SACpC,AAA2B,AAAU,SACrC,AAAuC,AexLlC,AAAc,MAAU,MfyL7B,AAAyB,AAAU,SACnC,AAAkB,AAAU,SAG5B,AAAuC,AAAU,Sc/CnD,KF1IA,AAA2B,SAC3B,AAAmB,KACnB,AAAgB,KCMhB,AAA0B,SAC1B,AAAmB,KACnB,AAAgB,QCiFhB,MD3GA,MAIA,MAIA,SU0UA,AAAI,AAA2E,EAAW,AADtD,OAChC,AAA4B,EAA2B,KAAvD,AAAc,EAAS,KAAvB,EAAS,QAEX,AAAqC,AHrT/B,ALlDa,AAAkC,AQuW2B,EAAiB,QHrTnF,GAAsB,KGsTpC,AAAuC,AHtTjC,ALlDa,AAAkC,OKkDvC,GAAsB,OGyTP,EAAiB,KAQ5C,AAAI,AAFO,EAAS,AAJpB,AACmB,EAAI,KADnB,EAAmC,SAM3B,MAkBV,EARA,AdhDI,AAAiB,AART,EAAV,EAAI,SAAW,KAQb,OAAmD,AcgDb,QAC1C,AdjDI,AAAiB,OAAkC,AciDb,QAC1C,AdlDI,AAAiB,OAAkC,AckDb,QAI1C,AC7XI,AAA2B,EAA3B,KAJV,AACmB,AJqCZ,AIvCc,AJ2Cd,AGsVwB,ACvXf,AAA2B,AAepC,EDwW4C,AAbxB,EAAU,EAAI,eHzU3B,KAJC,KAUP,EAAQ,OGmVV,SA1B6C,AAAE,YA+BnD,AAAmB,KAWrB,AAPI,EAAU,KACZ,AAAgC,EAAS,KAErC,EAAS,AADmB,AAAY,EAAsB,QAE/B,EAAjC,mB5BhUJ,AAAY,AAAC,AAAC,AoBlFO,AAAkC,OpBkFiB,EAAU,IAAM,KAIxF,AAAI,EAA0B,OAC5B,AAAW,IAEX,QAAQ,YAIJ,AAAW,OAGX,AAAW,OAGX,AAAW,MAGV,AAAI,EAA0B,OACnC,AAAW,IAEX,QAAQ,YAIJ,AAAW,OAGX,AAAW,OAGX,AAAW,MAIf,AAAW,IAEX,QAAQ,YAIJ,AAAW,OAGX,AAAW,OAGX,AAAW,OAKjB,Qc0M4G,EAAa,GAAvB,ObpSlG,AAAiC,AaqSjB,AADkF,EAA7E,AbhKW,AAX5B,IAA2B,OAI3B,EAAqB,IAErB,EAAqB,IwB3HjB,EAAQ,SxBgIoC,GAA7C,GApI6D,EAAY,iBAChF,AAAiC,AaoSjB,AADkF,EAA7E,AbnS6B,aAG7C,AAAQ,MAAgB,EAAK,KAIhC,AAAI,AADkB,EAAe,EAAI,MACnB,KAsFpB,EAnEE,AADF,AwBtBI,EAAQ,EAAK,AxBYA,EAAI,OADM,AwBXvB,EAAQ,IxBWR,EAAkB,WASH,QAGC,KwBvBhB,EAAQ,EAAK,OxBgCb,KAAmB,EAAwB,EAAoB,GAA5C,EAAmB,UAOxC,AAAgB,EAAkB,KAOlC,AAAM,AD2GL,AAJW,AATlB,AyB7LQ,AAAC,AzBuNO,AAJhB,AACE,AAJiB,AAvBsC,AAHtC,AC7FT,AALW,EAAoB,OAMrB,EAAmB,OD4FR,GAAI,EAAU,MAG2B,GAuBlC,KAIpB,KADd,GAIY,QyBvNa,GAAM,AzBuNnB,AAJhB,AACE,AAJiB,AAtBqC,EAsBlB,KAIpB,KADd,GAIY,WAjBa,GAIT,KC1Gd,AAAQ,AD0GP,AAJW,EAAW,IAAY,GAIrB,KAAb,AAJW,EAAW,KAAY,GAIrB,ICzFZ,AAAM,AFvCN,AEsCe,AAAkC,EAAgB,AAVnE,AACoB,MADhB,EAAmB,UF5Bb,MAAa,KEwCrB,AAAQ,AFpCR,EAAQ,KAAa,KAItB,EAAQ,OE0CX,AAAU,EAHO,AA+Bd,AAHsC,EAA5B,EAAc,IAGX,MA5B4B,KAC5C,EAA4C,KAC5C,EAA4C,KAW5C,A4BpIM,AAA2B,AAoBpB,EAAV,EAAI,KApBD,KAJV,AACmB,AJqCZ,AIvCc,EAAU,KJuChB,KItCX,AJgDI,EAAQ,MxBgFR,EAAmB,QAUvB,SA1F4C,AAAE,iB2BsOlD,AAAmB,AAAY,EAAsB,K3BtG9C,EAAyB,AAX5B,EAA2B,OAI3B,EAAqB,IAErB,EAAqB,IwB3HjB,EAAQ,SxBgIoC,M2BiHpD,AAAsC,AdgDtB,AADK,Ac/CkC,EHjP/C,AGmOmB,Ad8DX,AADK,YWhSL,MG0OC,EAAI,OAOmE,Wd+CU,AAAU,AchD3F,AHhPT,EAAQ,GAAsB,KXgS4D,ScTlG,AdI2B,AARnB,AAAU,EAAV,EAAI,KAAW,GAQb,KcTA,A5BzHH,AAJW,AATlB,AyB7LQ,AAAC,AzBuNO,AAPG,AAvBsC,AAHtC,A4BuIH,EAAkB,G5BvIH,GAAI,A4BiInC,AHtQQ,AGkP8B,Ad+CtB,AADK,Ac9CkC,Od8C2C,AAAU,EAAa,GAAvB,OWhSlF,EAAK,AGuPrB,AADA,AAAmB,AAAY,EAAsB,KAEpC,EAAI,GHxPb,EAAQ,UGoQG,QAGC,KHvQZ,EAAQ,EAAK,OzBqIwB,MAG2B,GAuBlC,GAOtB,QyBvNa,GAAM,AzBuNnB,AAPG,AAtBqC,EAsBlB,GAOtB,WAjBa,GAIT,M4B+HpB,AdGU,AAAiB,AARnB,AAAU,EAAV,EAAI,OAAW,UcAX,A5B1HL,AAJW,EAAW,IAAY,GAIrB,M4BgIpB,AdEU,AAAiB,OcPhB,A5B3HJ,AAJW,EAAW,KAAY,GAIrB,M4BsIpB,AC3UU,AAA2B,EAA3B,KAJV,AACmB,AJqCZ,AIvCc,EAAU,KJuChB,KAUP,EAAQ,YGyJhB,AAAsC,AdwItB,AADK,AbhKd,EAAyB,AAX5B,EAA2B,OAI3B,EAAqB,IAErB,EAAqB,IwB3HjB,EAAQ,SxBgIoC,I2BoBjC,AAAY,EAAsB,GAKmC,gBAsCxF,Ad4F2B,AARnB,IAAI,OAAW,KAQb,KAAmD,AflQrD,A6BqKY,AAAkC,AAdtD,AHhLQ,AG0J8B,AduItB,AcvIuC,UH1JvC,EAAK,AGmKN,EAAI,AADY,EAAsB,UAYlC,QAGC,KHjLZ,EAAQ,EAAK,WG8LiD,Q7BrKtD,MAAa,M6BuK7B,Ad2FU,AAAiB,OAAkC,Af9PrD,EAAQ,KAAa,M6BoK7B,Ad0FU,AAAiB,Of1PpB,K6BsKP,ACnPU,AAA2B,EAA3B,KALW,EAAU,YD4E/B,AAAyB,EAAuB,OAG3B,EAAI,MAyBF,EAAyB,EAAsB,MAlBpE,AAAI,AAHsB,EAAI,KAGH,MASF,AARvB,EAAuB,UAQuB,gBAehD,AAAoB,IACpB,AAAI,IAWF,AAAI,AAVmB,AACrB,EACA,EACA,EAEA,EAEA,MAGgB,KAChB,EACA,AAAgB,IADhB,EAAK,EAAc,SAKvB,AAAI,AAAwB,AAAC,KAAzB,SAsSN,AAAqB,AAAY,EAAsB,KAOrD,AADF,EACe,EAAuB,AAAC,EAAuB,GAAM,IADhE,KASJ,AAAsB,IAEtB,AAAI,KAQA,EALF,AAAa,AHzYP,AGwYY,AdvGJ,AADK,YWhSL,GAAsB,KG2YpC,AAGc,EAAI,KH9YZ,EAAQ,SG4FV,EAAK,AAZgB,AAoUzB,EACA,EACA,EACA,EAxBF,AACa,GAAM,KADf,EAAS,GAAI,KA0Bf,EACA,EACA,EACA,GACA,IAEA,EACA,EACA,MArUuB,MADjB,EAAc,OAGb,AAAI,AAAC,KACV,AAAI,KAEF,AACE,EACA,EACA,EACA,EACA,EACA,EACA,KAIF,AACE,EACA,EACA,EACA,EACA,EACA,OApFsB,AAAE,iBEpE3B,AAAQ,MAAI,EAAK,KAOpB,AAAsB,AVnBH,AAAkC,AUiBzC,AAA+C,AAHpC,EAAI,KAGf,cAGZ,AAAsB,AVpBH,AAAkC,AUoBN,EAAQ,UACvD,AAAmB,AVrBA,AAAkC,AUqBT,EAAQ,UAcpD,EAAmB,KAgBf,EAjBJ,EAAmB,KAKf,IAQF,EAAgB,EAAe,MAI+C,YAA5E,EAAoB,MAOtB,AAAgD,ALR5C,AKKmB,AVvDN,AAAkC,AUuD4C,cLLnF,IAAsB,KKYlC,AAAkB,ALZd,EAAQ,GAAsB,KKqClC,AAA2C,AhB4P/B,AADkF,AgB5PrD,ALpCrC,EAAQ,GAAsB,QKoCX,GhB4P8F,GAAvB,KAA7E,AgB/PO,A7B+FI,AAXhC,EAWoD,GAA7C,K6BhGuB,AAZ1B,AAIE,AAHoB,EAAe,AAJb,EAAmB,MAOpB,KLxBnB,EAAQ,KK4BU,iBAUtB,AAA2C,AhB2P/B,AADkF,EAA7E,AgB1P2C,aAGvD,AAAgB,MAAG,EAAa,KAsBnC,AAAI,AANJ,ALzDE,EAAQ,EAAK,AK4Cf,AAEuB,EAAC,AADtB,EAAsB,MADpB,SAWc,QAGC,KL1DjB,EAAQ,EAAK,SKmEb,AAAI,AAAyC,AADN,EAAmB,EAAI,MACmB,MAA7E,EAAoC,MAQtC,AAAgC,IAChC,IAEA,AAAI,AAAC,AAJ4B,AAAkB,AAAC,SAAnB,QAY/B,AAAI,AAA6C,AAHnB,AAFT,ADxHjB,AAA2B,AAe1B,EAAV,EAAI,KAfK,UC0H2C,KAG4B,KAAvE,KAEF,AAA4B,KACvB,AAA2D,EAA0B,KLzFhG,EAAQ,KKyFO,WAMb,AAAI,EAA+B,EAA8B,AAAC,GAA9B,GAAhC,KACF,AAAK,KA8BH,AhB6JJ,AAAiB,AART,EAAV,EAAI,KAAW,KAQb,KgBlKc,A9BgCjB,AAJW,AATlB,AyB7LQ,AAAC,AzBuNO,AAPG,AAvBsC,AAHtC,A8BlBW,EAAmB,G9BkBlB,GAAI,EAAU,MAG2B,GAuBlC,WyBhNT,GAAM,AzBuNnB,AAPG,AAtBqC,EAsBlB,cAVT,GAIT,M8B1BN,AhB4JJ,OgBjKgB,A9B+BnB,AAJW,EAAW,IAAY,GAIrB,M8BzBN,AhB2JJ,AAAiB,OgBhKF,A9B8BlB,AAJW,EAAW,KAAY,GAIrB,O8B9CN,AhBgLJ,AAAiB,IARf,KAAW,KAQb,KAAmD,AflQrD,A+B+EqB,AAAkC,EAHvB,QLrGhC,EAAQ,Q1ByBA,MAAa,M+BmFf,AhB+KJ,AAAiB,OAAkC,Af9PrD,EAAQ,KAAa,M+BgFf,AhB8KJ,AAAiB,Of1PpB,S+BQqC,AAAE,YA/ErB,AAAE,iBhBiQzB,AADF,AAC2B,QADvB,MAWJ,AAAI,EAAkB,GAAlB,MAQF,Ac9P2B,EAAkB,EAAwB,Ad0P3C,QADtB,IczPwF,AAH9F,AAL+B,EAAmB,IAK3B,IAG4F,EAAG,MdmQtH,AAAI,KAQF,Ac7PE,EAAmB,AALJ,QAsBnB,AAA6B,EAAkB,EAAwB,AdwO3C,QADtB,IcvOwF,AARpE,EAAmB,GAQsE,AAXnH,GAAW,KAWiH,EAHjG,OdkP3B,AAAI,KAEF,AAAc,EAAkB,SNnElC,AAAsC,AAFnB,AiBpMZ,ALxCc,AAAkC,SKwCxC,EAAQ,SjBwMvB,AehPU,AAAkC,MAAgB,WrBwb1D,AAAI,AAAuB,AAAC,KAAvB,OAML,AAAI,AADe,EAAwB,KACvB,KAIlB,AAAI,IAKF,AAAwB,IAWxB,EAmGN,AAAmB,AADA,IACgB,KAkB1B,EAfL,IACF,AAAkD,IACnC,EAAe,IAEf,AAAe,EAAf,MAUK,OAItB,KAvHQ,AAAqB,KAGvB,AAAI,EAA0B,KAkElC,AAAgC,IAUhC,AAAe,AAAe,AAPA,AAAC,EAAa,GAAK,KAOlC,AADI,AkBjiBA,AAAkC,SlBiiBtB,OAI/B,AqBriBQ,AAAkC,MAAgB,ArB4hB7B,EAAY,SAUzC,AqBtiBQ,AAAkC,MAAgB,KrByiB1D,AAA4B,IAC5B,AAA4B,IAC5B,AAAqB,AAAmC,EAAlC,EAA6B,MAlF7C,EA4FR,AAAmB,AADA,IACgB,KAkB1B,EAfL,IACF,AAAkD,IACnC,EAAe,IAEf,AAAe,EAAf,IAUK,OAItB,KAhHU,AAAqB,OAtBzB,AAAwB,MA2B1B,AAAwB,WK/G5B,AAAI,AAD4B,AAAkC,EAAlC,MACC,AAFJ,AAvRpB,IAAS,SA6RhB,AAAkC,AADlC,EAA6B,MAO7B,YAAQ,AAFa,AAAC,GAAuB,GAAK,iBL6GlD,AAAI,AAAqB,IAArB,AADgB,IACA,MAGlB,AAAI,AAFJ,EAAiB,QAGf,AAAqB,MAGzB,AAAyB,ICvIzB,EAJA,AAAI,AAAqB,IAArB,AADgB,IACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,KAEvB,AAAyB,ICwCzB,EAJA,AAAI,AAAqB,IAArB,AADgB,KACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,KAEvB,AAAyB,KCrCzB,EAJA,AAAI,AAAqB,KAArB,AADgB,KACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,MAEvB,AAAyB,QHoHzB,AAAI,AAAqB,IAArB,AADgB,IACA,MAGlB,AAAI,AAFJ,EAAiB,QAGf,AAAqB,MAGzB,AAAyB,ICvIzB,EAJA,AAAI,AAAqB,IAArB,AADgB,IACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,KAEvB,AAAyB,ICwCzB,EAJA,AAAI,AAAqB,IAArB,AADgB,KACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,KAEvB,AAAyB,KCrCzB,EAJA,AAAI,AAAqB,KAArB,AADgB,KACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,MAEvB,AAAyB,KEyBrB,KL2FJ,AAAI,AAAqB,IAArB,AADgB,IACA,MAGlB,AAAI,AAFJ,EAAiB,QAGf,AAAqB,MAGzB,AAAyB,ICvIzB,EAJA,AAAI,AAAqB,IAArB,AADgB,IACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,KAEvB,AAAyB,ICwCzB,EAJA,AAAI,AAAqB,IAArB,AADgB,KACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,KAEvB,AAAyB,KCrCzB,EAJA,AAAI,AAAqB,KAArB,AADgB,KACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,MAEvB,AAAyB,QHoHzB,AAAI,AAAqB,IAArB,AADgB,IACA,MAGlB,AAAI,AAFJ,EAAiB,QAGf,AAAqB,MAGzB,AAAyB,ICvIzB,EAJA,AAAI,AAAqB,IAArB,AADgB,IACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,KAEvB,AAAyB,ICwCzB,EAJA,AAAI,AAAqB,IAArB,AADgB,KACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,KAEvB,AAAyB,KCrCzB,EAJA,AAAI,AAAqB,KAArB,AADgB,KACA,MAIhB,AAHF,EAAiB,YAIjB,AAAqB,MAEvB,AAAyB,KE2CrB,KLqFJ,AAAI,AADkB,EAA2B,KAC1B,KAIrB,AAAI,IAQF,AAAI,AAAyB,IAAzB,AALc,OAmBhB,AAAI,AAHK,AAPT,AACE,AAJW,IAID,GAEV,EAAU,GAHR,GAOc,KAGL,KACX,AAAkB,KAElB,AAAuC,OAxB3C,AAAkB,MA6BtB,AAA2B,ICtK3B,AAAI,AADkB,EAA2B,KAC1B,KAIrB,AAAI,IAOF,AAAI,AAAyB,IAAzB,AAJc,OAkBhB,AAAI,AAHK,AAPT,AACE,AAJW,IAID,GAEV,EAAU,GAHR,GAOc,KAGL,KACX,AAAkB,KAElB,AAAuC,OAvB3C,AAAkB,MA4BtB,AAA2B,IExB3B,AAAI,AADkB,GAA2B,KAC1B,KAIrB,AAAI,KAOF,AAAI,AAAyB,KAAzB,AAJc,QAkBhB,AAAI,AAHK,AAPT,AACE,AAJW,KAID,GAEV,EAAU,GAHR,IAOc,KAGL,KACX,AAAkB,MAElB,AAAuC,QAvB3C,AAAkB,MA4BtB,AAA2B,MEgB3B,AAAuB,KAChB,IAEP,AAAkC,cLtGlC,EAAkB,KAClB,EAAO,EAAkB,KAPzB,AAHA,AACmB,AAJE,AAAC,GAAO,GAAuB,KAIf,KADjC,MAmBF,EAAkB,AAPO,gBAYzB,AAAkC,AAAC,EAAkC,GAAK,SAG5E,AAA0B,IAQtB,AAAsB,IAAtB,KAGa,EAAkB,IAI1B,MAYT,EAPsE,Y8BvWhE,YAGG,AP4CH,AAAQ,EAAK,GAAb,IAA8B,MOzC3B,APyCH,AAAQ,EAAK,GAAb,IAA8B,MOtC3B,APsCH,AAAQ,EAAK,GAAb,IAA8B,MAA9B,AAAQ,EAAK,GAAb,SvByTK,MAMD,SC5GV,EAAkB,KAClB,EAAO,EAAkB,KAOvB,AAdwB,AAHJ,GAAO,GAAuB,GAGP,MAgB3C,EAAkB,AAPO,gBAYzB,AAAkC,AAAC,EAAkC,GAAK,SAG5E,AAA0B,IAQtB,AAAsB,IAAtB,KAGa,EAAkB,IAI1B,MAYT,EAPsE,Y6BxShE,YAGG,AP4CH,AAAQ,EAAK,GAAb,IAA8B,MOzC3B,APyCH,AAAQ,EAAK,GAAb,IAA8B,MOtC3B,APsCH,AAAQ,EAAK,GAAb,IAA8B,MAA9B,AAAQ,EAAK,GAAb,StB0PK,MAMD,SC5BV,AAAI,AAAuB,AAAC,KAAvB,KAGI,IAKT,AAAiB,KACjB,AAAI,KAIF,AAAsB,AADT,AADA,AgBjSI,AAAkC,ShBiSxB,QAG3B,AAA6B,MAI/B,AAAa,AA2If,AADA,GAAW,AAAC,AAAO,GAA6B,IAAc,IACpD,KArIR,UAAQ,SAEJ,EAAW,QAIX,AAAe,OAGf,EAAW,KACX,AAAe,OAGf,EAAW,KACX,AAAe,KAOnB,AAFS,EAAe,KAAI,EAAS,IAAe,GAE1C,KAIV,EAAkB,KAClB,EAAO,EAAkB,KAOvB,AA9DwB,AAHJ,GAAO,GAAuB,GAGP,MAgE3C,EAAkB,AAPO,gBAiF7B,GAAqB,KACrB,EAAO,EAAqB,KAC1B,EAAqB,SAEvB,AAA6B,KAI7B,AAQA,AgB3aqB,AAAkC,AhByaW,AAD7B,GAA8B,GACpC,iBAlF7B,AAA0B,YClG1B,AAAI,AAJJ,GAAkB,KAII,KAMpB,AA0GK,AADQ,GAAoB,IACf,IA1GA,AAJO,gBA4BzB,AALA,AAGgC,AADA,AALF,AARb,AAFiB,KAEc,KAQa,AANrC,AAHN,EAA8B,GAGV,AADzB,EAAa,MAOwD,MAKpB,IACC,EAAqB,MAHhF,QAaN,AAJA,AACmB,IADf,EAAiB,OA+BrB,AADS,AAlBL,AAAsB,KAAtB,MAGa,GAAkB,IAI1B,IAO+D,EAAJ,EoB/P9D,GAAQ,KpBmQI,SE8IpB,AAAsC,KAkBtC,AADA,AADA,AADiE,EAAiB,EAA5D,IACA,AAA2C,EAAiB,EAA5D,KACA,AAA2C,EAAiB,EAA5D,KACA,AAA2C,EAAiB,EAA5D,OAGtB,AAAuC,KACvC,AAAsC,OAwB7B,GADL,AAb6D,AArBjE,AADA,AADA,AAD+D,EAAiB,EAA3D,IACA,AAA0C,EAAiB,EAA3D,KACA,AAA0C,EAAiB,EAA3D,KACA,AAA0C,EAAiB,EAA3D,OAkCN,MAwBgB,AAVb,AAAY,AAHX,AAxBiE,GAA4B,GAwB7F,AAHD,AADI,EAAS,GACK,MAGiB,GAGL,KAAa,GAUZ,KAAa,UApCwB,GAA6B,KAa1G,GADL,EAAW,MAwBgB,AAVb,AAAY,AAHX,AAAkB,EAAlB,AAHD,AADI,EAAS,GACK,MAGiB,GAGL,KAAa,GAUZ,KAAa,QAjC9D,AAAiD,KACjD,AAAkD,KkBvef,EAAU,IAArC,AAAC,EAAW,IAAS,UvB+a3B,AAAwB,AADL,AAAwB,EAAxB,OItYI,AJ0YvB,AAAS,EAA0B,GAAe,QIpUhD,AAA6B,AAAwC,AADlD,IACU,MAC7B,AAAsC,MHyOxC,AAAwB,AADL,AAAwB,EAAxB,OG9SI,AHkTvB,AAAS,EAA0B,GAAe,QGvOhD,AAA6B,AAAwC,AADlD,IACU,MAC7B,AAAsC,MF8QxC,AAAyB,EAAzB,KEzVuB,AF4VvB,AAAS,EAA+B,EAA0B,GAAwB,GAAhF,UE5QR,AAA6B,AAAwC,AADlD,IACU,MAC7B,AAAsC,MDgOxC,AAAyB,EAAzB,OChTuB,ADmTvB,AAAS,GAA0B,IAAwB,QC9NzD,AAA6B,AAAwC,AADlD,KACU,MAC7B,AAAsC,MApF1C,AAAI,IJmQF,AAAwB,IACxB,AAAwB,IInQxB,AAAkC,AJoQR,QIlQ5B,AAAI,IHoMF,AAAwB,IACxB,AAAwB,IGpMxB,AAAkC,AHqMR,QGnM5B,AAAI,IFmNF,AAAwB,IACxB,AAAwB,IEnNxB,AAAkC,AFoNR,QElN5B,AAAI,IDkLF,AAAwB,KACxB,AAAwB,KClLxB,AAAkC,ADmLR,QC/K5B,AAAI,EAAkE,EAAlE,EAA4C,EAA5C,EAAsB,EAAtB,OACF,AAAsC,MAOxC,AAAI,AAFsB,EAA1B,MAE8B,AADJ,ACkCjB,ASrEA,KAAY,ITqEQ,UD9B3B,EAA0B,KAE1B,AAAI,EAA8E,GAA9E,EAAuC,GAAvC,OACF,AACE,GACA,GACA,GACA,OAGF,AAA+B,MCscnC,AAAU,AAJa,AAAkB,KAAyB,GAA3C,QAIS,AD/b5B,SCgcJ,EAAgC,AD/b5B,SAWF,AAHI,AALkB,EAAwB,KAKvB,OACrB,EAAmB,WAKvB,AAA+B,WC2L/B,AAAqB,AAA+B,MACpD,AAAqB,AAA+B,MACpD,AAAqB,AAA+B,MACpD,AAAqB,AAA+B,MAQpD,AAAkC,KAClC,AAAkC,KAClC,AAAkC,KAClC,AAAkC,KAIlC,AAAI,AADyB,AAA+B,EAA/B,MACC,AA/MrB,ASrEA,KAAY,ITqEQ,QAkN3B,EAA0B,AAlNnB,ASrEA,KAAY,ITqEQ,QAqNT,AAAkB,EAAgB,EAAgB,EAAgB,MA6NtF,AAAU,AAJa,AAAkB,GAAyB,GAA3C,QAIS,AAvNK,ARjP7B,EAAQ,KAAa,SQyc7B,AAAU,EAAsB,AAxNwC,AR7OjE,EAAQ,UQ8Ob,AAAI,IAEY,AAAkB,EAAgB,EAAI,EAAI,MAoN5D,AAAU,AAJa,AAAkB,GAAyB,GAA3C,OAIS,AAjNO,ARvP/B,EAAQ,KAAa,SQyc7B,AAAU,EAAsB,AAlN0C,ARnPnE,EAAQ,UQsPG,AAAkB,EAAI,EAAgB,EAAI,MA8M5D,AAAU,AAJa,AAAkB,GAAyB,GAA3C,OAIS,AA3MO,AR7P/B,EAAQ,KAAa,SQyc7B,AAAU,EAAsB,AA5M0C,ARzPnE,EAAQ,UQ4PG,AAAkB,EAAI,EAAI,EAAgB,MAwM5D,AAAU,AAJa,AAAkB,GAAyB,GAA3C,OAIS,AArMO,ARnQ/B,EAAQ,KAAa,SQyc7B,AAAU,EAAsB,AAtM0C,AR/PnE,EAAQ,UQkQG,AAAkB,EAAI,EAAI,EAAI,MAkMhD,AAAU,AAJa,AAAkB,GAAyB,GAA3C,OAIS,AA/LO,ARzQ/B,EAAQ,KAAa,SQyc7B,AAAU,EAAsB,AAhM0C,ARrQnE,EAAQ,WQgRb,AAHI,AANkB,GAAwB,KAMvB,OACrB,EAAmB,WAKvB,AAA+B,UAzG/B,AAAyB,AAtNhB,GAAO,MAuNhB,AAAoB,KACpB,EAAO,EAAiB,KACtB,AAWE,AAAiC,AAAC,AAFW,OAE7C,KACF,AAAgB,KAEhB,AAAe,KAbf,EAAiB,SAEnB,AAAsB,S0BzHtB,gDAAQ,kCAIG,Ab9IU,AAAkC,Sa8IjC,MAIX,AblJU,AAAkC,SakJjC,MAIX,AbtJU,AAAkC,SasJjC,MAIX,Ab1JU,AAAkC,Sa0JjC,MAIX,Ab9JU,AAAkC,WaoK5C,AbpKU,AAAkC,SaoKjC,KAIX,AbxKU,AAAkC,SawKjC,KAIX,Ab5KU,AAAkC,Sa4KjC,MAIX,AbhLU,AAAkC,SagLjC,MAIX,AbpLU,AAAkC,Wa0L5C,Ab1LU,AAAkC,Wa8L5C,Ab9LU,AAAkC,WakM5C,AblMU,AAAkC,SakMjC,MAIX,AbtMU,AAAkC,WagP5C,AAPU,ARjMd,AQ2Lc,AR3Ld,AQqLc,ARrLd,AQ+Kc,AR/Kd,AQwKc,GAEA,EAHb,MRvKO,GQiLM,AR7Kd,EAAO,GQ0KN,KR9KO,GQuLM,ARnLd,EAAO,GQgLN,KRpLO,GQ6LM,ARzLd,EAAO,GQsLN,KR1LO,GQmMM,AR/Ld,EAAO,GQ4LN,IAOY,MAOT,AbtPU,AAAkC,SasPjC,MAIX,Ab1PU,AAAkC,Sa0PjC,MAIX,Ab9PU,AAAkC,Sa8PjC,MAIX,AblQU,AAAkC,WawQ5C,AbxQU,AAAkC,SawQjC,MAIX,Ab5QU,AAAkC,Sa4QjC,MAIX,AbhRU,AAAkC,SagRjC,MAIX,AbpRU,AAAkC,SaoRjC,MAItB,QtB9MA,AAA0B,KAiE1B,AA/DI,KAyBF,AACmB,Ac1Dd,AdkDL,AACmB,AcnDd,Ad2CL,AACmB,Ac5Cd,AdoCL,AACmB,AcrCd,EAAO,GduCO,Ac3Cd,EAAQ,GdwCT,McpCQ,Gd8CO,AclDd,EAAQ,Gd+CT,Mc3CQ,GdqDO,AczDd,EAAQ,GdsDT,MclDQ,Gd4DO,AchEd,EAAQ,Gd6DT,KAKK,KAuBT,AACmB,ActFd,Ad8EL,AACmB,Ac/Ed,AduEL,AACmB,AcxEd,AdgEL,AACmB,AcjEd,EAAO,GdmEO,AcvEd,EAAQ,GdoET,MchEQ,Gd0EO,Ac9Ed,EAAQ,Gd2ET,McvEQ,GdiFO,AcrFd,EAAQ,GdkFT,Mc9EQ,GdwFO,Ac5Fd,EAAQ,GdyFT,SAQ4B,UoB9HlC,AAAI,EAAS,OACJ,IAKT,AAAI,AAA8B,EAAS,OAAvC,EAAU,QASL,IAKT,AAAI,AAAoC,EAAS,OAA7C,EAAU,QAEL,AXjCY,AAAkC,AWiCrB,EAAS,WAM3C,AAAI,AAAmD,EAAU,OAA7D,EAAU,QAWL,AAAyB,GAAO,EAAhC,GAAqB,MAI9B,AAAI,EAAW,ONJP,ALlDa,AAAkC,SKkDvC,SMUD,MAIA,ANpBR,EAAO,IMmBP,MAUP,AAAI,EAAW,OACqB,KR1EpC,AAAU,AAAkC,IAAgB,KQ2EnD,KAMT,AAAI,AAAoB,EAAU,OAA9B,EAAU,QACZ,EACO,AAAuB,MAMhC,AAAI,AAAoB,EAAU,OAA9B,EAAU,QACL,KAIT,AAAI,AAAoB,EAAU,OAA9B,EAAU,QACZ,EAEA,AAAI,I3B0UN,AgB3aqB,AAAkC,AhByaW,AAD7B,GAA8B,GACpC,Y2BrUtB,IAIT,AAAI,EAAW,OAGkB,AhC5BzB,GAAQ,KAAa,KgC6B3B,AR5GQ,AAAkC,IAAgB,KQ6GnD,IAGT,AAAI,EAAW,OACqB,KRjHpC,AAAU,AAAkC,IAAgB,KQkHnD,KAIT,AAAI,EAAW,OAEN,AAAO,GAAP,MAIT,AAAI,EAAW,OACN,WXzHT,AAAI,EAAW,MACb,AAAgC,MAI3B,AADc,AAAe,MACV,KAAK,AATV,AAAkC,QASW,aETlE,AAAI,OAIJ,AAAa,KACb,AAAa,KAGb,AAAI,EAAU,MACZ,AAAc,AGyCR,AHzC+B,QAAjC,MAKF,AAAI,AADgB,EAAQ,OAGrB,AAAI,EAAkB,KAC3B,AAA6B,OAF7B,AAA6B,QAK5B,AAAI,EAAU,OAEnB,AAAI,AAAW,EAAU,OAApB,AADQ,QAKT,AADF,AACmB,EAAQ,GAFN,GACjB,KAqBJ,AAAwB,AAfpB,IAEF,AAAmB,EAAmB,KACtC,EAAkB,KACT,KAET,AAAmB,EAAmB,MACtC,EAAkB,KACb,IAAI,KAMO,OAOlB,AAAwB,AGnDO,A1BkF5B,GAAQ,I0BlFP,AAAC,AHkDgB,EAAQ,GGlDJ,SHqDtB,AAAI,EAAW,EAAU,KAApB,KAEV,AAAI,AAAU,KAAV,KAOF,AAAwB,AADxB,AAHqB,GAAwB,GAG3B,AAFM,EAAQ,UAwBlC,AATA,AAKE,EAAe,GAHf,EAAe,GAFZ,QAWA,AAAI,EAAW,EAAU,KAApB,KACV,AAAI,IACF,AAA8B,AGtC1B,AHsCgD,KGtClB,iBvBqUpC,AAAqB,IAErB,AAAI,KACF,AAAyB,MA5D3B,AAHA,AACmB,AAJE,AAAC,GAAO,GAAuB,KAIf,KADjC,MAyEJ,AAAI,IAGF,AAA2B,KAF3B,AAA2B,KAI7B,AAAuC,IAEvC,AAAkB,IAIlB,AAAgC,IAKhC,AAAI,IAGF,AAAwB,KAFxB,AAAwB,KAM1B,AAA0B,EAAgC,EAA0B,KAA1D,EAA2B,MAErD,AAAkD,IAIlD,AAAI,MAoJN,AAAmB,AADA,IACgB,KAkB1B,EAfL,IACF,AAAkD,IACnC,EAAe,IAEf,EAAe,IAUV,OAItB,SAxKI,AAAqB,KAIvB,AAAI,AAAC,KACH,AAAqB,WA5SvB,AAA4B,AADT,EAAQ,OAE3B,AAAqB,AAAsB,EAArB,EAAgB,MAUX,AAAC,OAA5B,AAA0D,AuBpFpD,EAAQ,IAAsB,MvBqFpC,AAAI,AAAC,AAFoC,AAAC,GAAiB,QAIzD,AAAI,AAA8B,IAA9B,EAAyB,MAC3B,EAA0B,KAE1B,EAAiC,GuB1F/B,EAAQ,OvB2FR,AAAqB,OAM3B,AAA6B,AuBjGvB,EAAQ,IAAsB,KvBsGpC,AuBtGM,EAAQ,MvBuGZ,EAIA,AAAI,AAAyF,IAAzF,EAAuC,EAA2B,IAAjE,MACH,EAA0B,aC3D9B,AAA4B,AADT,EAAQ,OAE3B,AAAqB,AAAsB,EAArB,EAAgB,MAStC,AAAyC,AAAC,GAAiB,KAChC,AAAC,OAA5B,AAA0D,AsB5DpD,EAAQ,IAAsB,MtB6DpC,AAAI,AAAC,KACH,AAAI,AAA8B,IAA9B,EAAyB,MAC3B,EAA0B,KAE1B,EAAiC,GsBjE/B,EAAQ,OtBkER,AAAqB,OAM3B,AAA6B,AsBxEvB,EAAQ,IAAsB,KtB6EpC,AsB7EM,EAAQ,MtBsQd,AAAqB,IAErB,AAAI,KACF,AAAyB,MAM3B,AAlE0B,AAHJ,GAAO,GAAuB,GAGP,MAsE7C,AAAI,IAGF,AAA2B,KAF3B,AAA2B,KAI7B,AAAuC,IAEvC,AAAkB,IAGlB,AAAI,AAAC,KACH,AAAqB,KA5MrB,AAAI,AAAyF,IAAzF,EAAuC,EAA2B,IAAjE,MACH,EAA0B,aChD9B,AAA4B,AADT,EAAQ,OAE3B,AAAqB,AAAsB,EAArB,EAAgB,MAWtC,AAAI,AAAC,AAFoC,AAAC,GAAiB,QAKzD,AAAI,EqBlDA,EAAQ,IrBiDY,KACpB,GAAyB,MAC3B,GAA0B,MAE1B,EAAiC,IqBrD/B,EAAQ,OrBsDR,AAAqB,OAM3B,AAA6B,AqB5DvB,EAAQ,IAAsB,KrBiEpC,AqBjEM,EAAQ,MrB6Sd,AAAqB,IAErB,AAAI,MACF,AAAyB,OAK3B,AAtF0B,AAHJ,GAAO,GAAuB,GAGP,MAoG7C,EAA2B,KAG3B,AAA6B,KAG7B,AAAI,AAAC,KACH,AAAqB,KApQrB,AAAI,AAAyF,IAAzF,EAAuC,GAA2B,IAAjE,MACH,GAA0B,cCnBH,AAAC,QAA5B,AAA0D,AoBpDpD,EAAQ,IAAsB,MpBqDpC,AAAI,AAAC,AAFoC,AAAC,GAAiB,QAGzD,AAAI,AAA8B,IAA9B,GAAyB,MAC3B,GAA0B,MAE1B,EAAiC,IoBzD/B,EAAQ,OpB0DR,AAAqB,QAM3B,AAA6B,AoBhEvB,EAAQ,IAAsB,MpBqEpC,AoBrEM,EAAQ,MpByQd,AAAqB,KAErB,AAAI,MACF,AAAyB,OAI3B,AAA0B,AAmCnB,AADQ,GAAoB,IACf,OA/BpB,AAAI,KAGF,AAA2B,OAF3B,AAA2B,MAI7B,AAAuC,KAEvC,AAAkB,MAGlB,AAAuC,OAGvC,AAAI,AAAC,MACH,AAAqB,MAxNrB,AAAI,AAAyF,KAAzF,EAAuC,GAA2B,IAAjE,MACH,GAA0B,Y4BlHhC,AAAI,AAAuC,AAAC,MAAxC,EAAW,QAQN,gDAGD,kC/BGN,AAAqB,IAErB,AAA2B,AAAC,EAAQ,IAAS,KAC7C,AAAsB,AuBsBhB,EAAQ,GAAsB,KvBrBpC,AAA0B,EAAQ,KAOlC,AAAI,AAA0C,IAA1C,AAAkB,AAAC,KAAnB,MACF,AAAqB,QETvB,AAAI,EAA0B,AAHX,AqByBb,EAAQ,IAAsB,KrBtB/B,KACH,AAAwB,MAG1B,AAAwB,IAIxB,AAAI,AAAC,KACH,AAAqB,QFUvB,AAAoB,AAAC,EAAS,GAAK,KACnC,AAA0B,EAAQ,KAMlC,AAAyB,GAAsB,QC3B/C,AAAoB,AAAC,EAAS,GAAK,KACnC,AAA0B,EAAQ,KAMlC,AAAyB,GAAsB,QCY/C,AAA0B,IAO1B,AAAyB,GAAsB,SChC/C,AAA0B,EAAQ,MAMlC,AAAyB,GAAsB,UHuC/C,AAAI,IAMF,AAAI,EAAqC,EAArC,KAEF,AAAkB,AAAC,EAAkB,GAAK,MAK5C,AAAI,EAAiC,AuB7BjC,EAAQ,GAAsB,MvB8BhC,AAAkB,AAAC,EAAK,GAAmB,OAK/C,AAA8B,AAAC,EAAS,GAAK,KAC7C,AAA+B,AuBpCzB,EAAQ,GAAsB,KvBqCpC,AAA8B,EAAQ,KAItC,AAAwB,AADL,AAAC,EAAQ,IAAQ,OAKpC,AAAI,AAAC,KACH,AAAqB,QClDvB,AAAI,IAMF,AAAI,EAAqC,EAArC,KAEF,AAAkB,AAAC,EAAkB,GAAK,MAK5C,AAAI,EAAiC,AsBTjC,EAAQ,GAAsB,MtBUhC,AAAkB,AAAC,EAAK,GAAmB,OAI/C,AAA8B,AAAC,EAAS,GAAK,KAC7C,AAA+B,AsBfzB,EAAQ,GAAsB,KtBgBpC,AAA8B,EAAQ,KAItC,AAAwB,AADL,AAAC,EAAQ,IAAQ,OAKpC,AAAI,AAAC,KACH,AAAqB,Q8BtBrB,AAA6B,KAC7B,A7BOwB,AAAC,EAAS,GAAK,QCtBzC,AAAI,KAMF,AAAI,EAAqC,GAArC,MAEF,AAAkB,AAAC,GAAkB,GAAK,OAK5C,AAAI,GAAiC,AoBFjC,EAAQ,GAAsB,MpBGhC,AAAkB,AAAC,EAAK,IAAmB,QAI/C,AAA8B,AAAC,EAAS,GAAK,MAC7C,AAA+B,AoBRzB,EAAQ,GAAsB,MpBSpC,AAA8B,EAAQ,MAItC,AAAwB,AADL,AAAC,EAAQ,IAAQ,QAKpC,AAAI,AAAC,KACH,AAAqB,SHqCvB,AAA4B,IAG5B,AAAqB,AAAmC,EAAlC,EAA6B,SCxBnD,AAA4B,IAG5B,AAAqB,AAAmC,EAAlC,EAA6B,SClBnD,AAA4B,IAG5B,AAAqB,AAAmC,EAAlC,EAA6B,SCQnD,AAA0B,EAAS,MACnC,AAAyB,AoB/BnB,EAAQ,GAAsB,MpBgCpC,AAA2B,AAHT,EAAQ,QAO1B,AAAmB,AADf,AADJ,EAAgB,KACE,KAAiB,MACD,S4BZhC,AAAoB,OAGpB,AAAoB,OAGpB,AAAoB,OAGpB,AAAoB,O1BpCtB,AAA4B,AAAC,EAAS,GAAK,MAC3C,AAA6B,EAAQ,M0BwCnC,AAAsC,Q1B1BxC,AAA0C,AkBZpC,EAAQ,IAAsB,MlBapC,AAA0C,AkBbpC,EAAQ,IAAsB,MlBcpC,AAA0C,AkBdpC,EAAQ,GAAsB,MlBepC,AAA0C,AkBfpC,EAAQ,GAAsB,MlBgBpC,AAA2C,AkBhBrC,EAAQ,GAAsB,MlBiBpC,AAA2C,AkBjBrC,EAAQ,GAAsB,MlBkBpC,AAA2C,AkBlBrC,EAAQ,GAAsB,MlBmBpC,AAA2C,AkBnBrC,EAAQ,GAAsB,MQ2ClC,AAAuC,QAYvC,AAAK,AANgB,URjDjB,EAAQ,OQwDV,AAAuB,KACvB,AAAkC,IAClC,AAAkC,KASpC,AAAsB,ARnElB,EAAQ,OQmER,KACG,AAAQ,QAAQ,EAAI,OACvB,AAAmC,EAAG,IADP,AAAE,YAMrC,A1BhDyB,AkB1BrB,EAAQ,IAAsB,cZ+BtC,AAAgC,KAChC,AAA4B,KAC5B,AUnFU,AAAkC,MAAgB,KVyF5D,AAAY,AY7CL,AL5Cc,AAAkC,SK4CzC,KZ8Cd,AAAqB,KAGrB,AU7FU,AAAkC,MAAgB,KVgG5D,AAAI,MACc,EAAI,OAClB,AAAU,AAAiB,EAAjB,KAAoB,MADA,AAAE,kBW5DpC,AAAI,AAAC,QAKL,AAAiC,ACQzB,EAAQ,ODRZ,MAEF,AAA4B,KAEgC,ACNvD,ALxCc,AAAkC,SKwCxC,MFxCf,AAAU,AAAkC,MAAgB,OCmD5D,AA2GA,AAFa,AC3JL,AAAC,ALDY,AAAkC,SKC1B,GAAM,ALDd,AAAkC,UI4J7B,OAxG1B,AA6HA,AAFA,AADkB,AC7KV,AAAC,ALDY,AAAkC,SKC1B,GAAM,ALDd,AAAkC,UI8KnB,IACjB,OArHnB,AAAiB,AAAC,ACdX,EAAO,IDcqB,GAAM,KAGzC,ACXQ,EAAQ,MDad,AAA4B,KAC5B,AAA2C,KAC3C,AAA0B,KAC1B,AAA+B,KAM/B,ADxEQ,AAAkC,MAAgB,AE4CrD,EAAO,QD+BZ,AAAa,EAAY,EAAiB,IAG1C,AD9EQ,AAAkC,MAAgB,ad2O5D,EAAO,EAAkB,KAIvB,EAAmB,KAInB,AAAyB,AAFzB,AADA,AAJyB,KAIH,GACA,UAItB,AAAI,KACF,AAA2B,KAC3B,AAAI,KACF,AAAsB,MDmB5B,AAAuC,KACvC,AAAkB,ICjBZ,AAAmC,KACnC,AAA8B,MACzB,AAAI,IACT,AAA8B,OAGhC,AgB/MI,EAAQ,chBqPR,WAEG,KAEA,KAEA,KAEA,KAEX,SAjBkE,AgB9O1D,EAAQ,EAAK,WhBgNf,AAUF,AAAE,QAAU,MAId,AAAmC,0BA7KnC,AAAsB,KACtB,AAAsB,AgBlDhB,EAAQ,GAAsB,MhBmDpC,AAAyB,EAAQ,KAIjC,AAAI,AAAC,iBA8LC,WAEG,KAEA,KAEA,KAEA,KAEX,iBAVQ,UAEG,KAEA,KAEA,KAEA,KAEX,KApMI,AAAsB,KAStB,AAPI,KgB7DA,EAAQ,EAAK,KAAb,EAAQ,EAAK,MAAb,EAAQ,EAAK,QhBqEf,AAqJF,AAAE,QAAU,MAId,AAAmC,KACzB,WAtJV,AAAyB,eyBhH3B,AAAI,EAAW,OAEb,AXbQ,AAAkC,MAAgB,AWaD,EAAQ,SAMnE,AAAI,AAAsB,EAAW,OAAjC,MAEF,AAAqB,KAGrB,AAAqB,SAYvB,AAAI,EAAS,OACX,AAAc,EAAQ,OAMxB,AAAI,AAA8B,EAAS,OAAvC,EAAU,QAmBd,AAAI,AAAoC,EAAS,OAA7C,EAAU,QAEZ,AXhEQ,AAAkC,AW+DzB,EAAS,MX/DgC,QWyE5D,AAAI,AAA4C,EAAU,OAAtD,EAAU,QAWL,GAAsB,KAG/B,AAAI,AAA2C,EAAU,OAArD,EAAU,QAKd,AAAI,EAAW,OxBxEb,AAA0B,Ae8BpB,EAAQ,GAAsB,Mf7BpC,AAA2B,Ae6BrB,EAAQ,IAAsB,MS4C7B,IAKT,AAAI,AAAoB,EAAU,OAA9B,EAAU,QACZ,EACO,AAAwB,EAAQ,MAMzC,AAAI,AAAoB,EAAU,OAA9B,EAAU,QACZ,EAGA,AAAI,IACF,AXhHM,AAAkC,AnBqPwB,AAD7B,GAA8B,GACpC,OmBrP2B,WWuH5D,AAAI,AAA0C,EAAU,OAApD,EAAU,QAIZ,AAAI,EAAW,OrBnEf,AAAoB,KAEpB,AAAc,AYRR,EAAQ,IAAsB,MZSpC,AAAiC,AYT3B,EAAQ,IAAsB,MZUpC,AAA2B,AYVrB,EAAQ,GAAsB,MZWpC,AAA6B,AYXvB,EAAQ,GAAsB,MZYpC,AAA6B,AYZvB,EAAQ,GAAsB,MZapC,AAAqB,AYbf,EAAQ,GAAsB,MZcpC,AAA0B,AYdpB,EAAQ,GAAsB,MZepC,AAAuB,AYfjB,EAAQ,GAAsB,MZiBpC,AAAI,AAAiB,AAAC,MAAlB,KAEF,AAAS,KAGX,AAAI,EAAkB,GAAjB,KAEH,AAAS,QqBuDX,AAAI,EAAW,OrBtGwC,AYalD,AZlBG,AAFgB,EAAQ,IAEJ,AADE,AOrBX,AAAkC,SPqBJ,IYmBpC,MFxCf,AAAU,AAAkC,MAAgB,QWwI1D,AAAI,EAAW,OACb,AAA4B,KAC5B,AX1IM,AAAkC,IAAgB,QW+I1D,AAAI,EAAW,OACb,AAAyB,QAO3B,AAAI,EAAW,WVnIjB,AAAoB,EAAuB,OAC3B,EAAK,MAGiC,AJxBjC,AAAkC,AIsBgB,EAAhB,UDtBvD,AAAU,AAAkC,ACuB6B,EAAxC,ODvB2B,KCqBjC,AAAE,WAQ7B,AAAmB,SUkIjB,UACO,4BACH,AAAmB,QAGnB,AAAmB,QAGnB,AAAmB,QAGnB,AAAmB,WASzB,AAAI,EAAW,OACb,AAAkB,OAMpB,AAAI,EAA+C,EAAW,KAA1D,EAAW,QACb,AAAI,KAEF,AAAK,AAA8B,AADZ,KACgC,OAAlD,EAAoB,WAA0C,AAA8B,EAAoB,OAAlD,EAAoB,WAO3F,AAAI,AAA0D,EAAU,OAApE,EAAU,QAEZ,AlCtDE,EAA0D,EAAW,KAArE,EAAW,QASb,AA6EQ,AAJV,AACE,AAJiB,AAtEY,AAJd,AyBzGV,AL5Cc,AAAkC,ApBkJJ,EAAS,UyBtG9C,MzBmLwB,KAIpB,KADd,AA1Ea,EAAW,MA8ElB,KAAqC,KA5E7C,AyBxGM,EAAQ,MzBwHd,AuB1KQ,AAAkC,IAAgB,AEwCrD,AzB+HL,EAAgB,GyB/HH,YSmKf,AAAI,AAAkD,EAAU,OAA5D,EAAU,QzByBd,AAAa,KACb,AAAuB,KyBtBrB,UACO,qBzBtLP,AAAyB,KACzB,AAAyB,KACzB,Ac5BQ,AAAkC,MAAgB,Kd8B1D,AAAI,KgBoBE,EAAQ,chBqPR,WAEG,KAEA,KAEA,KAEA,KAEX,WAlRI,AA6OA,AAAE,QAAU,MAId,AAAmC,kByB5D/B,EzBtKJ,AAAI,KAEF,AAAI,KAOJ,AAAI,KACF,AAAmC,OAIvC,AAAsB,SAYtB,AAAqB,KAIrB,AAAI,AAAuB,KAAvB,MACF,AAAsB,KACtB,AAA8B,SyB4I5B,AAA0B,UAQhC,AAAI,EAAW,OvBtLb,AAA+B,EAAQ,OACvC,AAAoB,AcKd,KAAQ,GAAsB,MdJpC,AAAsB,AcIhB,EAAQ,GAAsB,OSqLtC,AAAI,EAAW,O1B1Lb,AAAwC,AiBKlC,EAAQ,GAAsB,MjBJpC,AAAqC,AiBI/B,EAAQ,GAAsB,MjBHpC,AAAuC,AiBGjC,EAAQ,GAAsB,MjBFpC,AAAwC,AiBElC,EAAQ,GAAsB,MjBDpC,AAAwC,AiBClC,EAAQ,GAAsB,MjBCpC,AAAsC,Q0BwLxC,AAAI,EAAW,O1BhNb,AAAsC,AiBuBhC,EAAQ,GAAsB,MjBtBpC,AAAmC,AiBsB7B,EAAQ,GAAsB,MjBrBpC,AAAqC,AiBqB/B,EAAQ,GAAsB,MjBpBpC,AAAsC,AiBoBhC,EAAQ,GAAsB,MjBnBpC,AAAsC,AiBmBhC,EAAQ,GAAsB,MjBjBpC,AAAoC,W0BlB7B,SXXT,AAAI,EAAW,MACb,AAAgC,MAGlC,AAAI,AAAgB,EAAQ,MAC1B,AATQ,AAAkC,IAAgB,aC0H5C,EAAI,KAClB,AAAiB,AAAkC,EAAa,OAGhE,AAAkC,EAAkB,KACpD,EAAO,EAA8B,OAEnC,EAA+B,UAEjC,AAAmC,EAA6B,IAT9B,AAAE,WAmBtC,GAAoB,AADP,AADI,EAAO,IACG,EAAkB,WX2D7C,AAAI,AAAoC,GAA8B,MAAjE,AAAiB,EAAY,KAA7B,MAEH,AYvJM,AZsJM,AYhKP,EAAQ,KAUC,MjBmNhB,AAAqC,KACrC,AAAkB,MKzDhB,AAAY,AYjKP,EAAO,MZoKd,QArGA,AAAI,AAAC,QA2BD,AAfA,AAPwB,KAOJ,MAET,GAIT,AAFuB,KAEC,AADM,ACnF3B,GAAQ,SDsFA,GACR,AAEQ,IAFJ,EAAwB,cAQnC,AAAqB,AOxIF,AAAkC,WP2IrD,AAAqB,KAErB,AAA6B,IAG7B,QAAQ,kBAIJ,AAAyB,AYlGvB,AZiGU,AYvGX,EAAO,KAME,GAAsB,QZuGhC,AAAyB,AYvGvB,AZsGU,AYhHX,AAIA,EAAO,GAJC,KAUC,GAAsB,QZ4GhC,AAAyB,AY5GvB,AZ2GU,AYrHX,AAIA,EAAO,GAJC,KAUC,GAAsB,QZgHhC,AAAY,AY1HX,EAAQ,MZ+Hb,AAAI,IL8FN,AAAqC,KACrC,AAAkB,KK1FhB,AAAI,KAEF,AW1FC,KAaL,AAAa,GAAyB,GANlC,AADoC,KACA,KAEpB,UAOpB,AAA2B,EAA3B,OACA,AAAgC,EAAhC,OAEA,AAA2C,AAD3C,EAAqC,QAIrC,AAAI,EAAqC,KAEvC,AAA4B,KAE5B,AD9GQ,AAAkC,MAAgB,OCoH1D,ADpHQ,AAAkC,MAAgB,AE4CrD,ADuEuB,EAA2B,GAAK,GCvEhD,UZsIZ,AAAI,EAAe,KL6ErB,AAAwC,KACxC,AAAkB,KKtEuC,AAH1B,EAAY,MUvL3C,AAAU,AAAkC,MAAgB,MV2LrD,AAAI,EAAqB,MAKyB,AAD1B,EAAY,AO/LtB,AAAkC,aGAvD,AAAU,AAAkC,MAAgB,aT+M5D,AAAI,KACF,AAAiC,EAAjC,OAEA,AAAuC,IAEvC,EAAO,GAAiC,AAnL/B,EAAM,MAEN,GAAQ,GAHb,GAA8B,QAuLhC,GAAiC,AAtL1B,EAAM,MAEN,GAAQ,GAHb,KAA8B,SA8LhC,AAAI,AAHmB,EAGE,MAEvB,AAAK,UA0FK,EAAK,MACnB,AAAc,AAAI,QADM,AAAE,YAzFpB,AAAc,WejNN,EAAI,MACb,AAAQ,MAAG,EAAI,MAClB,AAAU,AAA2B,AAQxB,EAAV,EAAI,KARG,KAAgD,KADnC,AAAE,WADJ,AAAE,W5BG3B,AAAmB,IACnB,AAA0C,KauN/B,AAAI,EAAmB,MAE5B,AAAI,AAAC,KACH,AAAc,OAelB,AATA,AAGqB,EAEnB,EAAoB,GALlB,EAAmB,aAiB3B,QJlNA,AAAI,AAAC,QAML,EAAO,EAAkB,KAGvB,EAAmB,KAOnB,EAJA,AAAI,AAFJ,AAHgB,KAGH,KAEG,OAIO,AAHrB,EAAa,cAIf,AelBM,EAAQ,EAAK,Af+CP,AAYmB,EAAI,EAA9B,UARsC,AenDrC,EAAQ,EAAK,WfyB2C,AAD7C,AADC,AUzEC,AAAkC,SVyEnB,GAAK,GACP,Ma1ElC,AAAU,AAAkC,MAAgB,Kb8ExD,AAAI,AAAE,QAA4B,KAChC,AAAiC,KFwMvC,AAAwC,KACxC,AAAkB,IEnMmD,AezC9D,AL5Cc,AAAkC,SK4CzC,MF5Cd,AAAU,AAAkC,MAAgB,KbsFtD,AAA2B,MAE3B,AAAiC,iBO7CvC,AAAI,GAAmB,KACrB,EAAkB,MAClB,AAAmB,MAIrB,AAAqB,EAArB,OAGA,AAAI,AAAC,MACH,AAAI,IAGF,AAA0B,EAA1B,OHkFJ,AAAyB,AAzGd,EAAM,MAEN,GAAQ,GAHb,GAA8B,OA2GpC,EAAO,GAA0B,KAC/B,AAAe,IACf,GAA0B,WGlFxB,AAAe,KAGjB,AAAI,IACF,AAAuB,EAAvB,OACA,GAEA,AVyMA,AAAiC,AAAC,AAFW,OAE7C,KACF,AAAgB,KAEhB,AAAe,MUzMf,AAAa,KAGf,AAAI,IAEF,AAAwB,EAAxB,OR0JF,AAAa,KACb,AAAuB,MQxJrB,AAAa,KAGf,AAtDI,AADM,EAAV,MACc,MACZ,GAAoB,MACpB,EAAU,gBSsHZ,AAAW,IACX,ANnJqB,AAAkC,AOMhD,AD6IyC,GAAqB,GC7ItD,UFLc,KC4I7B,AAAW,MD5IwB,ALDd,AAAkC,cGgBvD,AAAe,AxB+DP,EAAQ,KAAa,KwB5D7B,AAAI,AAAgB,EAAQ,AAFd,AxBkEP,EAAQ,UwB/Db,AApBQ,AAAkC,IAAgB,MAwB5D,AAAI,AAAgB,AADH,EAAS,KACM,MAC9B,AAzBQ,AAAkC,IAAgB,UYwE5D,AAAI,IAQF,AAjFE,AAiFsB,AAFV,AAAiB,EAAjB,AAFO,UAEqB,AAD7B,EAAiB,MAGI,GAAU,GAjF9B,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QA6EhC,AAlFE,AAkFkB,EAAU,IAAW,GAlF3B,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SAqFhC,AA1FE,AA0FiB,AAHN,AAAY,EAAW,GRhFvB,OQmFe,QA1Fd,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QA0FhC,AA/FE,AA8F6B,AADuB,EAA9B,EAAY,IACU,IACN,GA/F1B,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,yDTwJ1B,sBAaJ,A3B1FI,A2BwF4B,S3BxFpB,KAAa,M2B2FzB,A3BvFG,EAAQ,U0BlFoB,GAAU,IAArC,AAAC,GAAW,IAAS,WC2H7B,AAAW,IACX,AAAmC,EAAe,OD5Hf,GAAU,IAArC,AAAC,GAAW,IAAS,iBCqMzB,ASvMA,AAmDqB,AADE,ATqJU,AADjB,KSpJqB,GAAS,GAA6B,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QToM9B,AAAgB,AADO,EAAY,G3BpHxB,S2BsHX,AS1MA,AT0MkB,GS1MN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTsM9B,AStMc,GAAgB,UT8M9B,ASnNA,AAuDqB,EAAiC,AT4JrB,AADjB,KS3J8C,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTgN9B,AAAgB,AADO,EAAY,G3BhIxB,S2BkIX,AStNA,ATsNkB,GStNN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTkN9B,AStNc,GAAgB,cT6IlC,AAAW,IAiFP,AN9NiB,AAAkC,cMyOnD,AS1OA,AT0OoB,AADJ,KACgB,IAAU,IS1O9B,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTsO9B,ADzNe,EAAS,GAAM,MAAS,I1BkE5B,wB2BoDf,AAAW,IACX,AAAqC,EAAe,OA0HhD,AAAsC,ADjQP,GAAU,IAArC,AAAC,GAAW,IAAS,MCiQ8B,ADjQxB,GAAU,IAArC,AAAC,GAAW,IAAS,MCiQgD,IAEzE,A3BrLI,A2BoLgC,EAAa,GC7PtC,O5ByEC,KAAa,M2BsLzB,A3BlLG,EAAQ,O2BmLX,ASlQc,GAAgB,OTmQvB,IDtQwB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAuJP,AAtJyC,cDvHV,GAAU,IAArC,AAAC,GAAW,IAAS,ICoRe,GC/Q7B,UDyRX,AShSA,AAmDqB,AADE,AT8OU,AADjB,KS7OqB,GAAS,GAA6B,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QT6R9B,AAAgB,AADO,EAAY,G3B7MxB,S2B+MX,ASnSA,ATmSkB,GSnSN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QT+R9B,AS/Rc,GAAgB,UTuS9B,AS5SA,AAuDqB,EAAiC,ATqPrB,AADjB,KSpP8C,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTyS9B,AAAgB,AADO,EAAY,G3BzNxB,S2B2NX,AS/SA,AT+SkB,GS/SN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QT2S9B,AS/Sc,GAAgB,cT6IlC,AAAW,IA0KP,ANvTiB,AAAkC,cMkUnD,ASnUA,ATmUoB,AADJ,KACgB,GAAQ,GSnU5B,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QT+T9B,ADrS8B,EAAS,GAAxB,MAAS,I1BqDb,U2BwPf,IAhKI,AAAiC,GAAqB,GCrK3C,WDyNX,AAAiC,GAAqB,GCzN3C,WDsOX,ASxOc,GAAgB,OTyO9B,ASzOc,GAAgB,OT0O9B,AS1Oc,GAAgB,YTyL9B,A3B9GI,EAAQ,KAAa,M2B+GzB,A3B3GG,EAAQ,yD2B4PP,yBASJ,AAAI,KAjOR,AAAW,IAmOkB,AAlOgB,cDtErC,EAAQ,KAAR,AC2Sc,ADjTf,EAAO,KAME,MCkTN,AAAqB,KDxTxB,EAAO,KCqTJ,AAAqB,KDzTxB,EAAQ,OCoFf,AAAW,IACX,AAAmC,IAAe,IAiPnC,MAKX,AAAgB,QAWhB,A3B/SI,SAAQ,KAAa,M2BgTzB,A3B5SG,EAAQ,O2B6SX,AAAiC,GAAqB,GC1X3C,WFLoB,GAAU,IAArC,AAAC,GAAW,IAAS,WC2H7B,AAAW,IACX,AAAmC,EAAe,OD5Hf,GAAU,IAArC,AAAC,GAAW,IAAS,IC8Ye,GCzY7B,UDmZX,AS1ZA,AAmDqB,AADE,ATwWU,KSxWI,GAAS,GAA6B,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTuZ9B,AADuB,EAAY,G3BvUxB,O2ByUX,AS7ZA,AT6ZkB,IS7ZN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTyZ9B,ASzZc,GAAgB,UTia9B,AStaA,AAuDqB,EAAiC,AT+WrB,KS/W6B,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTma9B,AADuB,EAAY,G3BnVxB,O2BqVX,ASzaA,ATyakB,ISzaN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTqa9B,ASzac,GAAgB,cT6IlC,AAAW,IAoSP,ANjbiB,AAAkC,cM2bnD,AAAiB,AAAC,KAAgB,IAAU,MAC5C,ASnZI,GAAiB,GAAK,GVlBX,EAAS,I1B4Db,U2B0Df,AAAW,IN7IU,AAAkC,UgBoSvD,AAAqB,AT9Rd,AS6RsB,AT7RtB,ASuRsB,GAAiB,ATnRtC,EAAS,GAAO,IAJT,KS6R+B,GT7R/B,QDucJ,IASP,AAAsC,ADrdP,GAAU,IAArC,AAAC,GAAW,IAAS,MCqd8B,ADrdxB,GAAU,IAArC,AAAC,GAAW,IAAS,MCqdgD,IAEzE,A3BzYI,A2BwY2B,EAAa,GCjdjC,O5ByEC,KAAa,M2B0YzB,A3BtYG,EAAQ,O2BuYX,AStdc,GAAgB,OTudvB,ID1dwB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IA2WP,AA1WyC,cDvHV,GAAU,IAArC,AAAC,GAAW,IAAS,ICwee,GCne7B,UD6eX,ASpfA,AAmDqB,AADE,ATkcU,KSlcI,GAAS,GAA6B,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTif9B,AAAgB,AADO,EAAY,G3BjaxB,S2BmaX,ASvfA,ATufkB,GSvfN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTmf9B,ASnfc,GAAgB,UT2f9B,AShgBA,AAuDqB,EAAiC,ATycrB,KSzc6B,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QT6f9B,AAAgB,AADO,EAAY,G3B7axB,S2B+aX,ASngBA,ATmgBkB,GSngBN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QT+f9B,ASngBc,GAAgB,cT6IlC,AAAW,IA8XP,AN3gBiB,AAAkC,cMqhBnD,AAAgB,AAAC,KAAgB,KACjC,ADlf8B,AUK1B,GAAiB,GAAK,GVLsB,GAAjC,MAAS,UC6f5B,IA7KI,AAAiC,GAAqB,GC9W3C,WDwbX,AS/bA,EAAY,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QT4b9B,AS5bc,GAAgB,OT6b9B,AS7bc,GAAgB,OT8b9B,AS9bc,GAAgB,QT6XvB,IAeP,A3BjUI,EAAQ,KAAa,M2BkUzB,A3B9TG,EAAQ,uD2BkdP,yBAMJ,AS9gBI,GAAiB,GAAK,KTmhBxB,AAAiC,GAAqB,GC1iB7C,SDuIf,AAAW,IN7IU,AAAkC,UgBoSvD,AAAqB,AT9Rd,AS6RsB,AT7RtB,ASuRsB,GAAiB,ATnRtC,EAAS,GAAO,IAJT,KS6R+B,GT7R/B,SD4iBJ,IAOP,A3B1eI,A2ByeqB,S3Bzeb,KAAa,M2B2ezB,A3BveG,EAAQ,O2BweX,AAAiC,GAAqB,GCrjB3C,WFLoB,GAAU,IAArC,AAAC,GAAW,IAAS,WC2H7B,AAAW,IACX,AAAmC,EAAe,IAwc9C,A3BtfI,A2BqfsB,EAAc,GC9jB7B,O5ByEC,KAAa,M2BufzB,A3BnfG,EAAQ,U0BlFoB,GAAU,IAArC,AAAC,GAAW,IAAS,IC4kBe,GCvkB7B,UDilBX,ASxlBA,AAmDqB,AADE,ATsiBU,AADjB,KSriBqB,GAAS,GAA6B,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTqlB9B,AAAgB,AADO,EAAY,G3BrgBxB,S2BugBX,AS3lBA,AT2lBkB,GS3lBN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTulB9B,ASvlBc,GAAgB,UT+lB9B,ASpmBA,AAuDqB,EAAiC,AT6iBrB,AADjB,KS5iB8C,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTimB9B,AAAgB,AADO,EAAY,G3BjhBxB,S2BmhBX,ASvmBA,ATumBkB,GSvmBN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTmmB9B,ASvmBc,GAAgB,cT6IlC,AAAW,IAkeP,AN/mBiB,AAAkC,cM8nBjD,AADF,AACe,AAJf,AACe,IADX,ASrlBA,KAAiB,GAAK,GTqlBD,MAIG,MADxB,ASplBA,EAAiB,GAAK,GTolBL,MAIrB,AAAgB,KAchB,AShpBA,ATmoBI,ASjmBA,EAAiB,GAAK,GTimBF,KACQ,EAAY,G3BhjBjC,K2BwjBiC,AAH1C,AACe,AAJf,AACe,EAAa,KADxB,AAAC,EAAY,GAAQ,MAIG,MADxB,EAAY,OAGc,G3BxjBrB,QoCpFC,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QT4oB9B,ASjpBA,ATipBoB,EAAa,IAAU,GSjpB/B,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QT6oB9B,AS7oBc,GAAgB,OT+oB9B,AAAgB,QAMhB,AAAI,AS5nBA,GAAiB,GAAK,GT4nBN,KA5gBxB,AAAW,IN7IU,AAAkC,UgBoSvD,AAAqB,AT9Rd,AS6RsB,AT7RtB,ASuRsB,GAAiB,ATnRtC,EAAS,GAAO,IAJT,KS6R+B,GT7R/B,SDwpBT,AAAiC,GAAqB,GCxpB7C,SD0pBJ,IAOP,AAAsC,ADtqBP,GAAU,IAArC,AAAC,GAAW,IAAS,MCsqB0B,EAAa,IAEhE,A3B1lBI,A2BylBsB,EAAc,GClqB7B,O5ByEC,KAAa,M2B2lBzB,A3BvlBG,EAAQ,O2BwlBX,ASvqBc,GAAgB,OTwqBvB,ID3qBwB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IA4jBP,AA3jByC,WA6jBzC,A3BtmBI,A2BqmBsB,EAAc,GC9qB7B,O5ByEC,KAAa,M2BumBzB,A3BnmBG,EAAQ,U0BlFoB,GAAU,IAArC,AAAC,GAAW,IAAS,IC4rBe,GCvrB7B,UDisBX,ASxsBA,AAmDqB,AADE,ATspBU,AADjB,KSrpBqB,GAAS,GAA6B,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTqsB9B,AAAgB,AADO,EAAY,G3BrnBxB,S2BunBX,AS3sBA,AT2sBkB,GS3sBN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTusB9B,ASvsBc,GAAgB,UT+sB9B,ASptBA,AAuDqB,EAAiC,AT6pBrB,AADjB,KS5pB8C,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTitB9B,AAAgB,AADO,EAAY,G3BjoBxB,S2BmoBX,ASvtBA,ATutBkB,GSvtBN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTmtB9B,ASvtBc,GAAgB,cT6IlC,AAAW,IAilBP,AN9tBiB,AAAkC,cMsuBnD,AAAgB,AAAC,aACjB,ASvuBc,GAAgB,WTwuB9B,ASxuBc,GAAgB,aT4uBlC,IA5HI,AAAiC,GAAqB,GC1mB3C,aDwkBX,A3B/fI,EAAQ,KAAa,M2BggBzB,A3B5fG,EAAQ,qD2B6pBP,yBAIJ,AS3sBI,GAAiB,GAAK,KTgtBxB,AAAiC,GAAqB,GCnvB7C,SDuIf,AAAW,IN7IU,AAAkC,UgBoSvD,AAAqB,AT9Rd,AS6RsB,AT7RtB,ASuRsB,GAAiB,ATnRtC,EAAS,GAAO,IAJT,KS6R+B,GT7R/B,SDqvBJ,IAMP,AAAmB,UACnB,AAAiC,GAAqB,GC5vB3C,WFLoB,GAAU,IAArC,AAAC,GAAW,IAAS,WC2H7B,AAAW,IACX,AAAmC,EAAe,IA+oB9C,A3B7rBI,A2B4rBsB,EAAc,GCrwB7B,O5ByEC,KAAa,M2B8rBzB,A3B1rBG,EAAQ,U2BgsBX,AAA+B,GAAmB,GC7wBvC,QD8wBJ,IAMP,ADzxB+B,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IA0qBP,ASlyBA,AAmDqB,AADE,ATgvBU,AAzqBQ,aSvEJ,GAAS,GAA6B,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTgyB9B,ASryBA,ATqyBkB,AAFM,EAAiB,G3B/sB9B,OoCpFC,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTiyB9B,ASjyBc,GAAgB,OTwHlC,AAAW,IACX,AAAmC,EAAe,OAirB9C,AD7yB+B,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IA4rBP,ASpzBA,AAuDqB,EAAiC,AT6vBrB,AA3rBQ,aSlEqB,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTizB9B,AStzBA,ATszBkB,AADM,EAAa,G3BjuB1B,OoCpFC,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTkzB9B,AStzBc,GAAgB,WT4HlC,AAAW,IACX,AAAmC,EAAe,OD5Hf,GAAU,IAArC,AAAC,GAAW,IAAS,MC4I7B,AAAW,IN7IU,AAAkC,UM4HvD,AAAW,IACX,AAksBiC,OAlsBiB,WA2sB9C,ASp0Bc,GAAgB,OTq0B9B,ASr0Bc,GAAgB,OTs0B9B,AS10Bc,GAAgB,aTg1B9B,AAAI,ASvyBA,GAAiB,GAAK,KToG9B,AAAW,IN7IU,AAAkC,UgBoSvD,AAAqB,AT9Rd,AS6RsB,AT7RtB,ASuRsB,GAAiB,ATnRtC,EAAS,GAAO,IAJT,KS6R+B,GT7R/B,SD+0BT,AAAiC,GAAqB,GC/0B7C,SDi1BJ,IAOP,AAAsC,AD71BP,GAAU,IAArC,AAAC,GAAW,IAAS,MC61B+B,GAAkB,IAE1E,A3BjxBI,A2BgxB2B,EAAc,ICz1BlC,O5ByEC,KAAa,M2BkxBzB,A3B9wBG,EAAQ,O2B+wBX,AS91Bc,GAAgB,OT+1BvB,IDl2BwB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAmvBP,AAlvByC,WAovBzC,A3B7xBI,A2B4xBsB,EAAc,GCr2B7B,O5ByEC,KAAa,M2B8xBzB,A3B1xBG,EAAQ,U2BgyBX,AAA+B,GAAmB,GC72BvC,QD82BJ,IAOP,AS53BA,AAmDqB,AADE,AT00BU,AADjB,KSz0BqB,GAAS,GAA6B,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTy3B9B,AAAgB,AADO,EAAY,G3BzyBxB,S2B2yBX,AS/3BA,AT+3BkB,GS/3BN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QT23B9B,AS33Bc,GAAgB,UTm4B9B,ASx4BA,AAuDqB,EAAiC,ATi1BrB,AADjB,KSh1B8C,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QTq4B9B,AAAgB,AADO,EAAY,G3BrzBxB,S2BuzBX,AS34BA,AT24BkB,GS34BN,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QTu4B9B,AS34Bc,GAAgB,cT6IlC,AAAW,IAqwBP,ANl5BiB,AAAkC,cM05BnD,ASt5Bc,GAAgB,OTu5B9B,ASv5Bc,GAAgB,OTw5B9B,AS75BA,AA0CI,GAAiB,GAAK,GTm3BW,GS75BzB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,WT45BlC,IAhGI,AAAiC,GAAqB,GC1zB3C,+CD85BP,yBASJ,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAM2B,ADt8BZ,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAg1BP,AAAgB,AA/0BpB,AAA6C,cAo1BzC,AAAgB,SAKhB,AAAgB,SAUhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAM2B,AD/+BZ,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAy3BP,AAAgB,AAx3BpB,AAA6C,cA63BzC,AAAgB,SAGpB,IA/EW,sCAmFH,0BAIJ,AAAgB,SAKhB,AAAgB,SAUhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAM2B,AD9hCZ,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAw6BP,AAAgB,AAv6BpB,AAA6C,cA46BzC,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAUhB,AAAgB,SAKhB,AAAgB,SAM2B,ADvkCZ,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAi9BP,AAAgB,AAh9BpB,AAA6C,cAq9BzC,AAAgB,SAGpB,IA/EW,sCAmFH,0BAIJ,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAUhB,AAAgB,SAM2B,ADtnCZ,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAggCP,AAAgB,AA//BpB,AAA6C,cAogCzC,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAW2B,AD/pCZ,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAyiCP,AAAgB,AAxiCpB,AAA6C,cA6iCzC,AAAgB,SAGpB,IA/EW,0CAmFH,0BAKoB,ADhrCO,GAAU,IAArC,AAAC,GAAW,IAAS,MCgrC+C,KArjC5E,AAAW,IACX,AAAmC,EAAe,OA0jCtB,ADtrCO,GAAU,IAArC,AAAC,GAAW,IAAS,MCsrC+C,KA3jC5E,AAAW,IACX,AAAmC,EAAe,OAgkCtB,AD5rCO,GAAU,IAArC,AAAC,GAAW,IAAS,MC4rC+C,KAjkC5E,AAAW,IACX,AAAmC,EAAe,OAskCtB,ADlsCO,GAAU,IAArC,AAAC,GAAW,IAAS,MCksC+C,KAvkC5E,AAAW,IACX,AAAmC,EAAe,OA4kCtB,ADxsCO,GAAU,IAArC,AAAC,KAAW,IAAS,MC2H7B,AAAW,IACX,AAAmC,EAAe,OAklCtB,AD9sCO,KAAU,IAArC,AAAC,GAAW,IAAS,MC2H7B,AAAW,IACX,AAAmC,EAAe,OA6lC9C,AAAI,AAAC,MACH,EVrqCJ,AAAI,KACF,AAAmB,QAMrB,AAAI,AAFgB,GAAoC,IAAsC,MAG5F,AAAmB,QAIrB,AAAgB,UUgqCU,ADjuCO,GAAU,IAArC,AAAC,GAAW,IAAS,MCiuC+C,KAtmC5E,AAAW,IACX,AAAmC,EAAe,OA0mC9C,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAKhB,AAAgB,SAO2B,ADtwCZ,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAgpCP,AAAgB,AA/oCpB,AAA6C,cAupC7C,IA7FW,QUrqCsB,AADjB,OAC4B,UDkC5C,AAAI,EAAe,KAGjB,AAnDE,AAmDqB,AADE,AAAC,EAAa,GAAS,AAAC,EAAmB,IAAS,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SAkDhC,AAvDE,AAuDqB,AAAK,AAAI,aAAe,GAAS,EAAQ,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SCUlC,AD6CI,AC7CoC,ED6CrB,KAEjB,AA9DE,AA8DiB,MADa,EAAR,GpCuBX,KoCpFC,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SA2DhC,AAhEE,AAgEiB,AAAI,aAAe,OAhExB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SCYlC,AAAgB,AADmB,EAAZ,GrCoER,SqClEf,ADlBI,ACkBc,GDlBF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCclC,ADdkB,GAAgB,aCuBlC,AD5BI,AC4BoB,AAAkC,AADlC,AAAY,EAAZ,AADR,MDgBR,GAAiB,GAAK,IpC0Cf,MqCxDoB,AAAY,EAAZ,IrCwDpB,GqCxD8D,GD5B7D,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QC0BlC,AD/BI,AC+BgB,AADe,EAAiB,ODY5C,GAAiB,GAAK,IRnCf,ISwBiC,GD/BhC,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QC4BlC,AAAgB,KAChB,ADlCI,ACkCc,GDlCF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8BlC,AD9BkB,GAAgB,+CT+wC1B,0BAKJ,AAAa,QAMb,AAAa,QAMb,AAAa,QAMb,AAAa,QAMb,AAAa,QAMb,AAAa,QAOmC,AD5zCjB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAusCP,AAAa,AAtsC4B,SA4sCzC,AAAa,QAMb,AAAyB,QAMzB,AAAyB,QAMzB,AAAyB,QAMzB,AAAyB,QAMzB,AAAyB,QAMzB,AAAyB,QAOuB,AD92CjB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAyvCP,AAAyB,AAxvCgB,SA8vCzC,AAAyB,QAG7B,IAhGW,QU9uCsB,AADjB,OAC4B,AAHzB,AAAmB,EAAnB,WDOnB,AAAI,EAAe,KAGjB,AAnDE,AAmDqB,AADE,AAAC,EAAa,GAAS,AAAC,EAAmB,IAAS,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SAkDhC,AAvDE,AAuDqB,AAAK,AAAI,aAAe,GAAS,EAAQ,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SCwClC,ADeI,ACfoC,EDerB,KAEjB,AA9DE,AA8DiB,MADa,EAAR,GpCuBX,KoCpFC,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SA2DhC,AAhEE,AAgEiB,AAAI,aAAe,OAhExB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SC0ClC,AAAgB,AADO,EAAY,GrCsCpB,SqCpCf,ADhDI,ACgDc,GDhDF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC4ClC,ADhDkB,GAAgB,iBC2DlC,AD5DI,AC2DiC,AAAuB,AAFpC,AADR,KACoB,GDf5B,GAAiB,GAAK,IpC0Cf,MqCzBsB,AAAY,EAAZ,IAAiC,GACzB,GD5D7B,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QC0DlC,AD/DI,AC+DgB,AADe,EAAiB,ODpB5C,GAAiB,GAAK,IRnCf,ISwDiC,GD/DhC,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QC4DlC,AAAgB,KAChB,ADlEI,ACkEc,GDlEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8DlC,ADlEkB,GAAgB,mDT63C1B,0BAKJ,AAAa,QAMb,AAAa,QAMb,AAAa,QAMb,AAAa,QAMb,AAAa,QAMb,AAAa,QAOmC,ADt6CjB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAizCP,AAAa,AAhzC4B,SAszCzC,AAAa,QAMb,AAAyB,QAMzB,AAAyB,QAMzB,AAAyB,QAMzB,AAAyB,QAMzB,AAAyB,QAMzB,AAAyB,QAOuB,ADx9CjB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAm2CP,AAAyB,AAl2CgB,SAw2CzC,AAAyB,QAG7B,IAhGW,0CAoGH,0BUh6CR,AAAgB,AADA,YAEhB,ADzEI,ACyEc,GDzEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqElC,ADrEkB,GAAgB,OCsElC,AD1EkB,GAAgB,aCuElC,AAAgB,AADA,YAEhB,ADzEI,ACyEc,GDzEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqElC,ADrEkB,GAAgB,OCsElC,AD1EkB,GAAgB,aCuElC,AAAgB,AADA,YAEhB,ADzEI,ACyEc,GDzEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqElC,ADrEkB,GAAgB,OCsElC,AD1EkB,GAAgB,aCuElC,AAAgB,AADA,YAEhB,ADzEI,ACyEc,GDzEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqElC,ADrEkB,GAAgB,OCsElC,AD1EkB,GAAgB,aCuElC,AAAgB,AADA,YAEhB,ADzEI,ACyEc,GDzEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqElC,ADrEkB,GAAgB,OCsElC,AD1EkB,GAAgB,aCuElC,AAAgB,AADA,YAEhB,ADzEI,ACyEc,GDzEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqElC,ADrEkB,GAAgB,OCsElC,AD1EkB,GAAgB,aVCC,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IUhDX,AAAgB,AADA,AVkD6B,IUlD7B,SAEhB,ADzEI,ACyEc,GDzEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqElC,ADrEkB,GAAgB,OCsElC,AD1EkB,GAAgB,aCuElC,AAAgB,QAChB,ADzEI,ACyEc,GDzEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqElC,ADrEkB,GAAgB,OCsElC,AD1EkB,GAAgB,aCgFlC,AAAgB,GADW,IrCIZ,SqCFf,ADlFI,ACkFc,GDlFF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8ElC,AD9EkB,GAAgB,OC+ElC,AD/EkB,GAAgB,UC4ElC,AAAgB,GADW,IrCIZ,SqCFf,ADlFI,ACkFc,GDlFF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8ElC,AD9EkB,GAAgB,OC+ElC,AD/EkB,GAAgB,UC4ElC,AAAgB,GADW,IrCIZ,SqCFf,ADlFI,ACkFc,GDlFF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8ElC,AD9EkB,GAAgB,OC+ElC,AD/EkB,GAAgB,UC4ElC,AAAgB,GADW,IrCIZ,SqCFf,ADlFI,ACkFc,GDlFF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8ElC,AD9EkB,GAAgB,OC+ElC,AD/EkB,GAAgB,UC4ElC,AAAgB,GADW,IrCIZ,SqCFf,ADlFI,ACkFc,GDlFF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8ElC,AD9EkB,GAAgB,OC+ElC,AD/EkB,GAAgB,UC4ElC,AAAgB,GADW,IrCIZ,SqCFf,ADlFI,ACkFc,GDlFF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8ElC,AD9EkB,GAAgB,OC+ElC,AD/EkB,GAAgB,UVHC,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IUvCX,AAAgB,AVwC6B,IUzClB,IrCIZ,SqCFf,ADlFI,ACkFc,GDlFF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8ElC,AD9EkB,GAAgB,OC+ElC,AD/EkB,GAAgB,UC4ElC,AAAgB,KAChB,ADjFkB,GAAgB,WCkFlC,AD9EkB,GAAgB,OC+ElC,AD/EkB,GAAgB,UT0kDlC,IUngDA,ADvEkB,GAAgB,eCoGD,AAHjB,OAG4B,AADzB,AAAmB,EAAnB,WDxDnB,AAAI,EAAe,KAGjB,AAnDE,AAmDqB,AADE,AAAC,EAAa,GAAS,AAAC,EAAmB,IAAS,GAC3C,GAnDpB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SAkDhC,AAvDE,AAuDqB,AAAK,AAAI,aAAe,GAAS,EAAQ,IAvDlD,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SCqGlC,AD9CI,EAAe,KAEjB,AA9DE,AA8DiB,MADa,EAAR,GpCuBX,KoCpFC,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SA2DhC,AAhEE,AAgEiB,AAAI,aAAe,OAhExB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,SCuGlC,AD5GI,AC4Gc,AADgB,EAAjB,ID3GD,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCwGlC,AD5GkB,GAAgB,mDTklD1B,0BUz/CR,AADgB,gBAEhB,AD3FI,GAAY,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuFlC,ADvFkB,GAAgB,OCwFlC,ADxFkB,GAAgB,OCyFlC,ADzFkB,GAAgB,UCqFlC,AADgB,gBAEhB,AD3FI,GAAY,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuFlC,ADvFkB,GAAgB,OCwFlC,ADxFkB,GAAgB,OCyFlC,ADzFkB,GAAgB,UCqFlC,AADgB,gBAEhB,AD3FI,GAAY,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuFlC,ADvFkB,GAAgB,OCwFlC,ADxFkB,GAAgB,OCyFlC,ADzFkB,GAAgB,UCqFlC,AADgB,gBAEhB,AD3FI,GAAY,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuFlC,ADvFkB,GAAgB,OCwFlC,ADxFkB,GAAgB,OCyFlC,ADzFkB,GAAgB,UCqFlC,AADgB,gBAEhB,AD3FI,GAAY,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuFlC,ADvFkB,GAAgB,OCwFlC,ADxFkB,GAAgB,OCyFlC,ADzFkB,GAAgB,UCqFlC,AADgB,gBAEhB,AD3FI,GAAY,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuFlC,ADvFkB,GAAgB,OCwFlC,ADxFkB,GAAgB,OCyFlC,ADzFkB,GAAgB,UVHC,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IU9BX,AADgB,AVgC6B,IUhC7B,aAEhB,AD3FI,GAAY,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuFlC,ADvFkB,GAAgB,OCwFlC,ADxFkB,GAAgB,OCyFlC,ADzFkB,GAAgB,UCqFlC,YACA,AD3FI,GAAY,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuFlC,ADvFkB,GAAgB,OCwFlC,ADxFkB,GAAgB,OCyFlC,ADzFkB,GAAgB,UTqoD9B,AAAY,QAMZ,AAAY,QAMZ,AAAY,QAMZ,AAAY,QAMZ,AAAY,QAMZ,AAAY,QDtqDmB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IAwjDP,AAvjDyC,SA6jDzC,AAAY,QAGhB,WNvqDc,AADc,AAAe,MACH,KAAK,AAjBxB,AAAkC,WKCV,ML0B7C,AK1BmC,EAA3B,AAAC,ALuBM,AADc,AAAe,AAH3B,EAAS,SAIgB,KAAK,AAxB1B,AAAkC,WKCnC,IAAS,UY0B7B,kBAAQ,AAHa,EAAW,iBAK5B,AAA2B,QAG3B,AAA2B,QAG3B,AAA2B,QAG3B,AAA2B,QAG3B,AAA2B,QAG3B,AAA2B,QZ3CI,GAAU,IAArC,AAAC,GAAW,IAAS,MCsH7B,AAAW,IWtEP,AXuEyC,SWpEzC,AAA2B,MAS/B,kCAAQ,AAHW,AADI,EAAW,IACK,yBAK/B,EAAY,KDoDpB,ADpHI,ACoHgB,EAAW,IAAU,IDpHzB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QCkHlC,ADvHI,ACuHc,AADP,AXpGQ,EAAS,GAAM,MAAS,I1BkE5B,OoCpFC,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqHlC,ADrHkB,GAAgB,OCsHlC,ADtHkB,GAAgB,OE+DZ,GACP,EAAY,KDiE3B,ADtII,ACsIgB,EAAW,GAAQ,GDtIvB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QCoIlC,ADzII,ACyIc,AAFP,AXxGuB,EAAS,GAAxB,MAAS,I1BqDb,OoCpFC,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqIlC,ADrIkB,GAAgB,OCsIlC,ADtIkB,GAAgB,OEoEZ,YAId,EAAY,KD0EpB,AD7GQ,GAAiB,GAAK,GVlBX,EAAS,I1B4Db,MqCqEf,ADzJI,ACsJc,EAAW,IAAU,IDtJvB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QCqJlC,AD1JI,AC0Jc,GD1JF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuJlC,ADvJkB,GAAgB,OCwJlC,ADxJkB,GAAgB,OE4EZ,GACP,EAAY,KDqF3B,AXlIkC,AUK1B,GAAiB,GAAK,GVLsB,GAAjC,MAAS,MWoI5B,ADzKI,ACsKa,EAAW,GDtKZ,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QCqKlC,AD1KI,AC0Kc,GD1KF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuKlC,ADvKkB,GAAgB,OCwKlC,ADxKkB,GAAgB,OEiFZ,YAId,EAAY,KD6FpB,AAAsB,EAAY,GrCnGnB,MqCqGf,ADzLI,ACsLc,EAAW,IAAU,IDtLvB,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QCqLlC,AD1LI,AC0Lc,GD1LF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuLlC,ADvLkB,GAAgB,OCwLlC,ADxLkB,GAAgB,OEyFZ,GACP,EAAY,KD0G3B,AAAiB,EAAW,KAQ5B,ADjNI,ACiNc,AAJlB,AACa,AAHS,MAAY,KAGV,MANP,AAAC,EAAW,IAAU,YDxMvB,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC6MlC,AD7MkB,GAAgB,OC8MlC,AD9MkB,GAAgB,OC+MlC,ADpNI,EAAY,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QE8FZ,YAId,EAAY,KD0HpB,ADjOI,ACiOc,AAFK,AADP,EAAW,GACS,GAAM,AAFzB,EAAW,IAE4B,OD/NxC,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC6NlC,AD7NkB,GAAgB,OC8NlC,AD9NkB,GAAgB,OC+NlC,AD/NkB,GAAgB,OEsGZ,GACP,EAAY,KDuI3B,ADnPI,ACmPc,AAFI,MAAY,MDjPlB,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC+OlC,AD/OkB,GAAgB,OCgPlC,ADhPkB,GAAgB,OCiPlC,ADtPI,ACgPa,EAAW,GDhPZ,KACd,AAAgB,GAAgB,WAIhC,AAAgB,GAAgB,QE2GZ,YAId,EAAY,MFpHhB,ACkQc,AAFL,ACxI0C,IDwI/B,IDhQR,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8PlC,AD9PkB,GAAgB,OC+PlC,ADnQkB,GAAgB,UEwHZ,GACP,EAAY,MF1HvB,ACkQc,AAFL,ACnI0C,IDmI/B,IDhQR,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8PlC,AD9PkB,GAAgB,OC+PlC,ADnQkB,GAAgB,UE6HZ,YAId,EAAY,MFlIhB,ACkQc,AAFL,AC3H0C,ID2H/B,IDhQR,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8PlC,AD9PkB,GAAgB,OC+PlC,ADnQkB,GAAgB,UEqIZ,GACP,EAAY,MFvIvB,ACkQc,AAFL,ACtH0C,IDsH/B,IDhQR,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8PlC,AD9PkB,GAAgB,OC+PlC,ADnQkB,GAAgB,UE0IZ,YAId,EAAY,MF/IhB,ACkQc,AAFL,AC9G0C,ID8G/B,IDhQR,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8PlC,AD9PkB,GAAgB,OC+PlC,ADnQkB,GAAgB,UEkJZ,GACP,EAAY,MFpJvB,ACkQc,AAFL,ACzG0C,IDyG/B,IDhQR,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8PlC,AD9PkB,GAAgB,OC+PlC,ADnQkB,GAAgB,UEuJZ,YAId,EAAY,MF5JhB,ACkQc,AAFL,ACjG0C,IDiG/B,KDhQR,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8PlC,AD9PkB,GAAgB,OC+PlC,ADnQkB,GAAgB,UE+JZ,GACP,EAAY,MFjKvB,ACkQc,AAFL,AC5F0C,ID4F/B,KDhQR,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8PlC,AD9PkB,GAAgB,OC+PlC,ADnQkB,GAAgB,UEoKZ,YAId,EAAY,MAId,AAAgB,IDsGT,EAAW,ICrGT,EAAY,MAIrB,AAAgB,IDiGT,EAAW,aC7FhB,EAAY,MAId,AAAgB,IDyFT,EAAW,ICxFT,EAAY,MAIrB,AAAgB,IDoFT,EAAW,aChFhB,EAAY,MAId,AAAgB,ID4ET,EAAW,IC3ET,EAAY,MAIrB,AAAgB,IDuET,EAAW,aCnEhB,EAAY,MAId,AAAgB,ID+DT,EAAW,KC9DT,EAAY,MAIrB,AAAgB,ID0DT,EAAW,cCtDhB,EAAY,MAId,AAAgB,ID6CT,EAAW,IC5CT,EAAY,MAIrB,AAAgB,IDwCT,EAAW,aCpChB,EAAY,MAId,AAAgB,IDgCT,EAAW,IC/BT,EAAY,MAIrB,AAAgB,ID2BT,EAAW,aCvBhB,EAAY,MAId,AAAgB,IDmBT,EAAW,IClBT,EAAY,MAIrB,AAAgB,IDcT,EAAW,aCVhB,EAAY,MAId,AAAgB,IDMT,EAAW,KCLT,EAAY,MAIrB,AAAgB,IDCT,EAAW,YCKxB,kBAAQ,cAEJ,AAAgB,QAGhB,AAAgB,QAGhB,AAAgB,QAGhB,AAAgB,QAGhB,AAAgB,QAGhB,AAAgB,QAQhB,AAAI,EAA2B,EAAmB,GAA9C,EAAmB,MZ1SQ,GAAU,IAArC,AAAC,GAAW,IAAS,MC2H7B,AAAW,IACX,AAAmC,EAAe,QWqL9C,AAAgB,MAMpB,AACmB,IADf,mDXo4CI,0BAIA,ASnqDA,GAAiB,GAAK,QTirDsB,KA7kDpD,AAAW,IAEX,AAAuC,WA4kDnC,AAAmB,ACzsDhB,ADysD4B,GAAmB,GCzsDvC,QD0sDX,AAAgB,A3BjoDZ,EAAQ,KAAa,M2BkoDzB,AAAgB,A3B9nDb,EAAQ,O2B+nDJ,IAKH,AS1rDA,GAAiB,GAAK,ST6sDtB,AS7sDA,GAAiB,GAAK,KT+sDxB,AAAmB,AADA,ACruDlB,ADquD8B,GAAmB,GCruDzC,UDwuD+B,ACxuDvC,ADwuDmD,GAAqB,GCxuDhE,ODiIf,AAAW,IACX,AAAqC,EAAe,OAmnDhD,AAAmB,AADA,ACpvDhB,ADovD4B,GAAmB,GCpvDvC,UDuvD6B,AD5vDT,GAAU,IAArC,AAAC,GAAW,IAAS,MCsI7B,AAAW,IACX,AAAqC,EAAe,OAKpD,AAAW,IAwnDP,ANrwDiB,AAAkC,aM6wDnD,AAAmB,AADA,ACtwDhB,ADswD4B,GAAmB,GCtwDvC,UDywD6B,KAxoD5C,AAAW,IACX,AAAqC,EAAe,IAwoDhD,AAAqB,QAMjB,ASzvDA,GAAiB,GAAK,STuwD1B,AAAmB,KAnqDvB,AAAW,IAoqDP,AAlqDJ,AAAuC,YAmqDnC,AAAmB,AChyDhB,ADgyD4B,EAAe,GChyDnC,WDsyDP,AS/wDA,GAAiB,GAAK,QTgH9B,AAAW,IA4qDP,AAAoB,AAAe,ANzzDlB,AAAkC,YM0zDnD,AAAqB,ACpzDlB,ADozD8B,GAAqB,GCpzD3C,QDqzDJ,IAKH,ASnyDA,GAAiB,GAAK,MTqyDxB,AAAmB,AADA,AC3zDlB,AD2zD8B,GAAmB,GC3zDzC,UD8zD+B,GAAqB,UA7rDnE,AAAW,IACX,AAAqC,EAAe,OAysDhD,AAAmB,AADA,AC10DhB,AD00D4B,GAAmB,GC10DvC,UD60D6B,AC70DrC,AD60DiD,GAAqB,GC70D9D,ODiIf,AAAW,IACX,AAAqC,EAAe,OAKpD,AAAW,IAgtDP,AN71DiB,AAAkC,aMq2DnD,AAAmB,AADA,AC91DhB,AD81D4B,GAAmB,GC91DvC,UDi2D6B,KAhuD5C,AAAW,IACX,AAAqC,EAAe,IAguDhD,AAAqB,QAIzB,IAhJM,AAAqB,ACttDpB,ADstDgC,GAAqB,GCttD7C,QDutDF,IAJP,AAAqB,WAlBd,IA+DT,AAAqB,AChwDlB,ADgwD8B,GAAqB,GChwD3C,QDiwDJ,IArEL,AAAmB,KAjkDzB,AAAW,IAkkDL,AAhkDN,AAAuC,YAikDjC,AAAmB,AC9rDlB,AD8rD8B,EAAe,GC9rDrC,sDD02DP,0BAIA,AS30DA,GAAiB,GAAK,QTy1D1B,AAAmB,KAjwDvB,AAAW,IAEX,AAAuC,WAiwDnC,AAAmB,AC93DhB,AD83D4B,EAAe,GC93DnC,QD+3DX,AAAgB,A3BtzDZ,EAAQ,KAAa,M2BuzDzB,AAAgB,A3BnzDb,EAAQ,O2BozDJ,IAKH,ASn2DA,GAAiB,GAAK,STg3DtB,ASh3DA,GAAiB,GAAK,KTk3DxB,AAAmB,AADA,ACp5DlB,ADo5D8B,GAAmB,GCp5DzC,UDu5D+B,GAAqB,UAtxDnE,AAAW,IACX,AAAqC,EAAe,OAkyDhD,AAAmB,AADA,ACn6DhB,ADm6D4B,GAAmB,GCn6DvC,UDs6D6B,AD36DT,GAAU,IAArC,AAAC,GAAW,IAAS,MCsI7B,AAAW,IACX,AAAqC,EAAe,OAKpD,AAAW,IAuyDP,ANp7DiB,AAAkC,aM47DnD,AAAmB,AADA,ACr7DhB,ADq7D4B,GAAmB,GCr7DvC,UDw7D6B,KAvzD5C,AAAW,IACX,AAAqC,EAAe,IAuzDhD,AAAqB,QAMjB,AS55DA,GAAiB,GAAK,STy6D1B,AAAmB,KAj1DvB,AAAW,IAm1DP,AAj1DJ,AAAuC,YAm1DnC,AlB/tDsC,KkBguDtC,AAAmB,ACj9DhB,ADi9D4B,EAAe,GCj9DnC,WDu9DP,ASp7DA,GAAiB,GAAK,QTi8DtB,ASj8DA,GAAiB,GAAK,MTm8DxB,AAAmB,AADA,ACr+DlB,ADq+D8B,GAAmB,GCr+DzC,UDw+D+B,ACx+DvC,ADw+DmD,GAAqB,GCx+DhE,ODiIf,AAAW,IACX,AAAqC,EAAe,OAKpD,AAAW,IAg3DP,AN7/DiB,AAAkC,aMqgEnD,AAAmB,AADA,AC9/DhB,AD8/D4B,GAAmB,GC9/DvC,UDigE6B,KAh4D5C,AAAW,IACX,AAAqC,EAAe,IAg4DhD,AAAqB,QAIzB,IA3HM,AAAqB,AC34DpB,AD24DgC,GAAqB,GC34D7C,QD44DF,IAJP,AAAqB,WAnBd,IA0DT,AAAqB,AC/6DlB,AD+6D8B,GAAqB,GC/6D3C,QDg7DJ,IAhEL,AAAmB,KArvDzB,AAAW,IAsvDL,AApvDN,AAAuC,YAqvDjC,AAAmB,ACl3DlB,ADk3D8B,EAAe,GCl3DrC,0CD0gEP,0BAn4DR,AAAW,IN7IU,AAAkC,eM4HvD,AAAW,IACX,AAAmC,AA45DE,MAAT,KA55DsB,OAo6D9C,AAAmB,KAh6DvB,AAAW,IAE4B,WAg6DnC,AAA+B,EAAe,GC7hEnC,QD8hEX,A3Br9DI,A2Bm9DmB,E3Bn9DX,KAAa,M2Bs9DzB,A3Bl9DG,EAAQ,O2Bm9DJ,IAW0B,GAAT,YAr7D5B,AAAW,IACX,AAAmC,EAAe,IAq7DvC,IAOP,AAAmB,AADY,GAAmB,GCljEvC,UFLoB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsI7B,AAAW,IACX,AAAqC,EAAe,IAo7DzC,IA/6DX,AAAW,IUtEX,AAAgB,AADA,AhBtEK,AAAkC,QgBsEvC,SAEhB,ADzEI,ACyEc,GDzEF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCqElC,ADrEkB,GAAgB,OCsElC,AD1EkB,GAAgB,UC2ElC,ADvEkB,GAAgB,UTukE9B,AAAmB,AADY,GAAmB,GCpkEvC,eDiIf,AAAW,IACX,AAAqC,EAAe,IAs8DhD,AAAqB,KACd,IAl8DX,AAAW,IN7IU,AAAkC,UMylEnD,AAAsC,GAAkB,EAAmB,IAC3E,AAAkD,EAAnB,ICplEpB,QDqlEX,ASvlEc,GAAgB,OTwlE9B,ASxlEc,GAAgB,OTylE9B,AAAiC,GAAqB,GCvlE3C,QDwlEJ,IAKP,ADlmE+B,GAAU,IAArC,AAAC,GAAW,IAAS,OCmmElB,kBAx+DX,AAAW,IACX,AAAmC,EAAe,IA8+D9C,AAAiC,GAAqB,GCrmE3C,QDsmEJ,IA/9DX,AAAW,IU7DX,AAAgB,AhBhFK,AAAkC,QgB+E5B,IrCIZ,SqCFf,ADlFI,ACkFc,GDlFF,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QC8ElC,AD9EkB,GAAgB,OC+ElC,AD/EkB,GAAgB,OCgFlC,ADhFkB,GAAgB,UTwnE9B,AAAmB,AADY,GAAmB,GCrnEvC,eDiIf,AAAW,IACX,AAAqC,EAAe,IAu/DhD,AAAqB,KACd,IAGX,IAzGI,AAAiC,GAAqB,GCphE3C,gDDioEP,0BA1/DR,AAAW,IN7IU,AAAkC,UMuHvD,AAAW,IAuhEP,AAthEyC,AAshEsB,MAAT,O3B3jE3C,U2BokEX,AAAmB,KAthEvB,AAAW,IAE4B,WAshEnC,AAA+B,EAAe,GCnpEnC,QDopEX,A3B3kEI,A2BykEmB,E3BzkEX,KAAa,M2B4kEzB,A3BxkEG,EAAQ,U2B+kEoD,GAAT,OA3iE1D,AAAW,IA2iEP,AA1iEyC,I3BrC9B,U2BqlEX,AlB/6DiC,QkBu7DjC,AAAmB,AADY,GAAmB,GCzqEvC,UFLoB,GAAU,IAArC,AAAC,GAAW,IAAS,MCsI7B,AAAW,IACX,AAAqC,EAAe,IA2iEzC,IAtiEX,AAAW,IUpDX,AADgB,AhBxFK,AAAkC,QgBwFvC,aAEhB,AD3FI,GAAY,KACd,AAAgB,GAAgB,YAIhC,AAAgB,GAAgB,QCuFlC,ADvFkB,GAAgB,OCwFlC,ADxFkB,GAAgB,OCyFlC,ADzFkB,GAAgB,UT8rE9B,AAAmB,AADY,GAAmB,GC3rEvC,eDiIf,AAAW,IACX,AAAqC,EAAe,IA6jEhD,AAAqB,KACd,IAzjEX,AAAW,IN7IU,AAAkC,UMktEnD,AS9sEc,GAAgB,OT+sE9B,AS/sEc,GAAgB,OTgtE9B,AAAsC,AALnB,KAKiC,AC1sEhD,EAAS,GAAO,KD0sEmD,IAEvE,A3BvoEI,A2BsoEwC,EAAf,GC/sElB,O5ByEC,KAAa,M2BwoEzB,A3BpoEG,EAAQ,O2BqoEX,AAAiC,GAAqB,GCltE3C,QDmtEJ,IAKP,AD7tE+B,GAAU,IAArC,AAAC,GAAW,IAAS,OC8tElB,aAxmEX,AAAW,IA8mEP,AA7mEyC,WA8mEzC,AAAiC,GAAqB,GChuE3C,WDsuEX,AlBr/DsC,QkB1G1C,AAAW,IAwmEP,ANrvEiB,AAAkC,aM6vEnD,AAAmB,AADY,GAAmB,GCtvEvC,eDiIf,AAAW,IACX,AAAqC,EAAe,IAwnEhD,AAAqB,KACd,IAGX,IArHI,AAAiC,GAAqB,GCzoE3C,iBD6Df,AAZA,AAUmB,AC3DZ,AD2DwB,AAbd,AC9CV,AD8CsB,GAAiB,GC9C/B,OD2DiC,GC3DjC,ODiDX,uCA0BI,AATW,AADI,EAAS,IACO,sBAW5B,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,MAEf,AAAe,UlByE1B,AA+DqC,KA1DrC,AAAsC,AADnB,AiBlJZ,AL5Cc,AAAkC,SK4CzC,EAAU,SjBoJxB,AehMU,AAAkC,MAAgB,KfoM5D,AAAmB,GAAmB,WAIU,KerKhD,AAnCU,AAAkC,AfwMd,OTrHvB,KwB/CP,AApCU,AAAkC,AAoClB,EAAS,KAJpB,AxB+CP,EAAQ,KAAa,MSiI7B,YAAQ,WAEJ,AAAwC,KACxC,AAAqB,SAGrB,AAAqC,KACrC,AAAqB,SAGrB,AAAuC,KACvC,AAAqB,SAGrB,AAAwC,KACxC,AAAqB,SAGrB,AAAwC,KACxC,AAAqB,aArGzB,AAAI,KACF,AAAmC,KACnC,AAAwC,MAM1C,AAAI,AAF6C,GAAoC,IAAsC,GAE/E,KAQtC,AAAoC,AAAC,MAArC,MACE,AAAuC,KAAvC,MACF,AAAiB,IACK,GACb,AAAoC,KAApC,MACT,AAAiB,IACK,GACb,AAAsC,KAAtC,MACT,AAAiB,IACK,GACb,AAAuC,KAAvC,MACT,AAAiB,IACK,GACb,AAAuC,KAAvC,MACT,AAAiB,IACK,gBAQpB,EQxFqB,GAApB,MAPP,AAAmB,KACnB,AAAmB,KACnB,AAAgB,KAChB,AAAgB,iBRqGhB,AAAI,EQjGuB,GAApB,MAPP,AAAmB,KACnB,AAAmB,KACnB,AAAgB,KAChB,AAAgB,MRyGT,IAGT,QUtCA,KAGA,AAAI,KAcF,AAAW,AAD4B,AE/JpB,AAAkC,YJsErD,AAAmB,KACnB,AAAmB,KACnB,AAAgB,KAChB,AAAgB,ME8FlB,AAAI,AADuB,IACL,KACpB,AAAW,OAUU,AAAC,IAAnB,EFrGwB,GAApB,OEuGU,AAAc,AEpLZ,AAAkC,gBFwLvD,AAAgB,GAAgB,OAGhC,AAAI,EAAkB,KACb,IAIT,AAAW,IAGX,AAjKI,AADJ,GAAU,KACI,MACZ,GAAoB,MACpB,EAAU,WAkKZ,AAAI,GAAuB,MACzB,AAAgC,MAGlC,KX0EA,SW1LA,AACoB,EACb,AACa,KADT,EAAiB,IAFxB,EAAiB,MAUrB,EAAO,AAA+D,AAAC,MAAhE,AAAsC,AAAC,KAAvC,EAAmB,AAAC,GAAnB,OAIN,AAAI,EAAiB,KACnB,AAAiB,KACZ,AAAI,GAAqB,AFnEzB,IAAU,OEoEf,AAAiB,KACZ,AACkB,IADU,GAAqC,KAA7D,EAAkB,aAM/B,AAAI,IAIF,GAAqB,AF/Ed,IAAU,QEiFV,IAGT,AAAI,IACK,IAGT,AAAI,KACF,AAAgC,KACzB,IAMT,AAAqB,ASjId,ATiI0B,GAAqB,GSjIvC,aToEf,AAAmC,SAlBnC,EAAO,AAA8B,EAAiB,KAA/C,EAAY,MACjB,AAAgB,AAiBiB,MAhBjC,EAAa,SAGf,AAAI,EAAgB,KACX,IAGT,KDtDA,MAIA,MAIA,SN+KA,AAAgB,KAKd,AADF,oBA0CQ,cAEG,MAEA,MAEA,MAEA,MAEA,MAEA,MAEA,MAEA,MAhBX,MArCA,kBA4DQ,cAEJ,QAGA,QAGA,QAGA,QAGA,QAGA,QAGA,QAGA,MAhFJ,AAAI,IAqBF,AALA,AAC2B,EANvB,AAAqB,AARzB,AAAI,EAAY,OAQZ,MACuB,MAIvB,AAAuB,AAAC,KAAxB,OHmDN,AAAwC,KACxC,AAAkB,UGnIlB,AAAI,EAAK,KACP,AAAmB,KAEnB,MAGF,AAAI,EAAQ,KACV,AAAmB,KAEnB,MAGF,AAAI,EAAO,KACT,AAAmB,KAEnB,MAGF,AAAI,EAAO,KACT,AAAmB,KAEnB,MAGF,AAAI,EAAI,KACN,AAAmB,KAEnB,MAGF,AAAI,EAAI,KACN,AAAmB,KAEnB,MAGF,AAAI,EAAS,KACX,AAAmB,KAEnB,MAGF,AAAI,EAAQ,KACV,AAAmB,KAEnB,SCtLF,AAA6B,QAI7B,AAA6B,QAI7B,AAA2B,QAI3B,AAA2B,QAI3B,AAA4B,QAI5B,AAA4B,Q0B5B5B,MAIA,MAIA,MAIA,MAIA,MAIA,MAIA,MAIA,MAIA,MAIA,MAIA,AlBtCqB,AAAkC,WmBevD,MAIA,MAIA,MAIA,MAIA,SAkBE,AADF,AAC2B,QADvB,MAMF,AADF,AAC0B,QADtB,QAIiB,EAAI,MAClB,AAAa,MAAG,EAAI,MAiC+C,AzBwP1D,AADK,AyBhQS,EAAwB,AATpB,EAAuB,GASkB,IAAK,AAV9C,EAAuB,gBAgCrD,AAAwB,EAAsB,KAS9C,AAAe,EAAI,AADK,EAAsB,MArBnB,AtCuFxB,EAAyB,AAX5B,EAA2B,OAI3B,EAAqB,IAErB,EAAqB,IwB3HjB,EAAQ,SxBgIoC,MsCnD5C,AAJA,AAAkB,EAAY,KAA9B,MACgB,AzBuNR,AADK,gBWhSL,MciFK,EAAI,MzB+MyE,AAAU,AWhSpG,EAAQ,KXgSkF,KyBjMvC,IAAiC,iBAetF,AADF,Ad7GI,AXiSQ,AADkF,EAA7E,AyBhMsC,WdhG3C,EAAK,Mc2GE,QAGC,Kd9GhB,EAAQ,EAAK,OckHjB,AAAsB,AAAC,AAAU,EAAV,EAAI,IAAW,KAEtC,AAAI,AAAkB,EAAY,KAA9B,MAcF,AAAU,AADQ,AAA0B,EAA1B,OACA,AvCuBjB,AAJW,AuC3Be,Ad3KzB,AAAC,AzBuNO,AAJhB,AA1ByD,AAHtC,AuCdQ,EAAkB,GvCcd,GAAI,EAAU,MAG2B,GAuBlC,GAOtB,QyBvNa,GAAM,AzBuNnB,AAJhB,AAzBwD,EAsBlB,GAOtB,WAjBa,GAIT,MuCtBd,EAAsB,AvCsBrB,AAJW,EAAW,IAAY,GAIrB,MuCrBd,EAAsB,AvCqBrB,AAJW,EAAW,KAAY,GAIrB,OuCZd,AAAU,AAHQ,AAA0B,EAA1B,OAGI,AxCpHpB,AwC+GkB,AAAkC,EAAgB,QxC/G5D,MAAa,MwCsHvB,EAAsB,AxClHpB,EAAQ,KAAa,MwCoHvB,ExChHC,MwCzByB,WADF,mBAiJM,EAAmB,KAChD,AAA4B,MAAG,EAAmB,KAInD,AADF,AAAI,EAAmB,KAUvB,AACW,AAFF,AAHL,AADc,IACK,KACrB,EAAU,OAEO,KAEE,EAAmB,IAE7B,EAAS,GAHhB,EAAmB,MAevB,AAA2B,MAE3B,IAGK,AAAqB,MAAG,EAAY,KAClC,AAAwB,MAAG,EAAe,KAO7C,AAAI,EAAW,AnBpPF,AAAkC,AmBkPiD,AADpE,AAHS,EAAnB,EAAe,IAGS,kBAqBpC,AARA,AAAqB,Ed5M3B,AcmMqC,AnBrPxB,AAAkC,AmBsPI,cdpM3C,KcwMF,SAMF,EACA,AAAe,IAKK,QdpNxB,Ac6MuB,Id7Mf,Mc8MQ,OAnBgC,WADR,WAoCxC,AAAkB,EAAmB,KAArC,MAGA,AADF,AAC0B,QADtB,MAIJ,AAA+B,IAC1B,AAAa,MAAG,EAAI,KAClB,AAAa,MAAG,EAAI,KAKvB,AAAI,EAAW,AzBsDT,AADK,AyBzDe,AAAiC,EAAjC,EAAwB,EAAI,kBAKpD,EACA,AAAI,IACJ,IAFsB,MANG,WADF,WAczB,EAAuB,KACP,AzB6CV,AADK,oByBjHf,AADF,AAC2B,QADvB,EAAmB,MA2ElB,AAAqB,MAAG,EAAY,KACvC,AACE,EACA,EACA,EACA,EACA,EACA,EACA,EAAmB,GACnB,AAAuB,EAAvB,EAAmB,IACnB,GACA,IAEA,EACA,EACA,KAfwC,WAhGe,WADF,mBA0HhC,EAAY,KAClC,AAAwB,MAAG,EAAe,KAQ7C,AAA2B,AnB7UV,AAAkC,AmB6UgD,AAJvE,AAHS,EAAnB,EAAe,IAGS,KAIU,WACpD,AAA2B,AnB9UV,AAAkC,AmB8UgD,aACnG,AAAwB,AnB/UP,AAAkC,AmB+U6C,cAEhG,AAAuB,IACvB,AAAI,KAQA,EAGF,IAJI,EAAe,GAAM,KACvB,EAAgB,WAepB,AdvTI,Ac+SwB,AnBjWX,AAAkC,AmBiWiD,cd/SxF,KcuTR,QAOF,AADF,AACoB,Qd9ThB,EAAQ,MckUP,AAAa,MAAG,EAAI,KAElB,AAAqB,MAAG,EAAY,KACvC,AACE,EAAe,GACf,IACA,EACA,EACA,EACA,EACA,EAAY,GACZ,AAAoB,EAApB,EAAe,IAAiB,EAAI,IACpC,GACA,IAEA,EACA,EACA,KAfwC,WAFR,WA/CU,WADR,cCvU5C,MAIA,MAIA,QAMA,AACa,Af4BN,Ae/Ba,Kf+BL,Ke7BX,WCXiB,EAAI,OACvB,AAAU,AAAgC,EAAhC,MAAmC,AAAkC,OAD7B,WAKpD,AAAgC,8GhDyLC,OA9EjC,AAAS,AADE,OACK,SAEL,AAAS,KAAW,mBAC/B,AAAI,EAAM,KACR,2BAzDE,EAAM,MAGR,AAAU,AAAkB,EAAM,aAwDrB,AAAS,EAAO,uBCmc/B,EAAe,AADC,KACW,MAE3B,AAAY,EAAM,KD3bL,AAAO,EAAK,mBACU,AAC/B,EAAW,AAA2B,EAAK,GAA/B,EAAO,gCyBnDuC,KAC9D,AAAmC,yBAK+D","sourceRoot":"./core.untouched.wasm","sourcesContent":["// Alignment guarantees\n\n// @ts-ignore: decorator\n@inline export const AL_BITS: u32 = 4; // 16 bytes to fit up to v128\n// @ts-ignore: decorator\n@inline export const AL_SIZE: usize = 1 << <usize>AL_BITS;\n// @ts-ignore: decorator\n@inline export const AL_MASK: usize = AL_SIZE - 1;\n\n// Extra debugging\n\n// @ts-ignore: decorator\n@inline export const DEBUG = true;\n\n// ╒════════════════ Common block layout (32-bit) ═════════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤\n// │                           MM info                             │ -16\n// ├───────────────────────────────────────────────────────────────┤\n// │                           GC info                             │ -12\n// ├───────────────────────────────────────────────────────────────┤\n// │                          runtime id                           │ -8\n// ├───────────────────────────────────────────────────────────────┤\n// │                         runtime size                          │ -4\n// ╞═══════════════════════════════════════════════════════════════╡\n// │                              ...                              │ ref\n@unmanaged export class BLOCK {\n  /** Memory manager info. */\n  mmInfo: usize; // WASM64 needs adaption\n  /** Garbage collector info. */\n  gcInfo: u32;\n  /** Runtime class id. */\n  rtId: u32;\n  /** Runtime object size. */\n  rtSize: u32;\n}\n\n// @ts-ignore: decorator\n@inline export const BLOCK_OVERHEAD: usize = (offsetof<BLOCK>() + AL_MASK) & ~AL_MASK;\n\n// @ts-ignore: decorator\n@inline export const BLOCK_MAXSIZE: usize = (1 << 30) - BLOCK_OVERHEAD;\n","// This file is shared with the compiler and must remain portable\n\n// ╒═══════════════════ Typeinfo interpretation ═══════════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤ ◄─ __rtti_base\n// │                             count                             │\n// ╞═══════════════════════════════════════════════════════════════╡ ┐\n// │                      Typeinfo#flags [id=0]                    │ id < count\n// ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤\n// │                      Typeinfo#base  [id=0]                    │\n// ├───────────────────────────────────────────────────────────────┤\n// │                              ...                              │\n\n/** Runtime type information data structure. */\n@unmanaged\nexport class Typeinfo {\n  /** Flags describing the shape of this class type. */\n  flags: TypeinfoFlags = TypeinfoFlags.NONE;\n  /** Base class id or `0` if none. */\n  base: u32 = 0;\n}\n\n/** Runtime type information flags. */\nexport const enum TypeinfoFlags {\n  /** No specific flags. */\n  NONE = 0,\n  /** Type is an `ArrayBufferView`. */\n  ARRAYBUFFERVIEW = 1 << 0,\n  /** Type is an `Array`. */\n  ARRAY = 1 << 1,\n  /** Type is a `StaticArray`. */\n  STATICARRAY = 1 << 2,\n  /** Type is a `Set`. */\n  SET = 1 << 3,\n  /** Type is a `Map`. */\n  MAP = 1 << 4,\n  /** Type is inherently acyclic. */\n  ACYCLIC = 1 << 5,\n  /** Value alignment of 1 byte. */\n  VALUE_ALIGN_0 = 1 << 6,\n  /** Value alignment of 2 bytes. */\n  VALUE_ALIGN_1 = 1 << 7,\n  /** Value alignment of 4 bytes. */\n  VALUE_ALIGN_2 = 1 << 8,\n  /** Value alignment of 8 bytes. */\n  VALUE_ALIGN_3 = 1 << 9,\n  /** Value alignment of 16 bytes. */\n  VALUE_ALIGN_4 = 1 << 10,\n  /** Value is a signed type. */\n  VALUE_SIGNED = 1 << 11,\n  /** Value is a float type. */\n  VALUE_FLOAT = 1 << 12,\n  /** Value type is nullable. */\n  VALUE_NULLABLE = 1 << 13,\n  /** Value type is managed. */\n  VALUE_MANAGED = 1 << 14,\n  /** Key alignment of 1 byte. */\n  KEY_ALIGN_0 = 1 << 15,\n  /** Key alignment of 2 bytes. */\n  KEY_ALIGN_1 = 1 << 16,\n  /** Key alignment of 4 bytes. */\n  KEY_ALIGN_2 = 1 << 17,\n  /** Key alignment of 8 bytes. */\n  KEY_ALIGN_3 = 1 << 18,\n  /** Key alignment of 16 bytes. */\n  KEY_ALIGN_4 = 1 << 19,\n  /** Key is a signed type. */\n  KEY_SIGNED = 1 << 20,\n  /** Key is a float type. */\n  KEY_FLOAT = 1 << 21,\n  /** Key type is nullable. */\n  KEY_NULLABLE = 1 << 22,\n  /** Key type is managed. */\n  KEY_MANAGED = 1 << 23\n}\n","import { DEBUG, BLOCK_OVERHEAD } from \"rt/common\";\nimport { Block, freeBlock, ROOT } from \"rt/tlsf\";\nimport { TypeinfoFlags } from \"shared/typeinfo\";\nimport { onincrement, ondecrement } from \"./rtrace\";\n\n// === A Pure Reference Counting Garbage Collector ===\n// see: https://researcher.watson.ibm.com/researcher/files/us-bacon/Bacon03Pure.pdf\n\n// ╒══════════════════════ GC Info structure ══════════════════════╕\n// │  3                   2                   1                    │\n// │1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0│\n// ├─┼─┴─┴─┼─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤\n// │B│color│                     refCount                          │\n// └─┴─────┴───────────────────────────────────────────────────────┘\n// B: buffered\n\n// @ts-ignore: decorator\n@inline const BUFFERED_MASK: u32 = 1 << ((sizeof<u32>() * 8) - 1);\n// @ts-ignore: decorator\n@inline const COLOR_BITS = 3;\n// @ts-ignore: decorator\n@inline const COLOR_SHIFT: u32 = ctz(BUFFERED_MASK) - COLOR_BITS;\n// @ts-ignore: decorator\n@inline const COLOR_MASK: u32 = ((1 << COLOR_BITS) - 1) << COLOR_SHIFT;\n// @ts-ignore: decorator\n@inline export const REFCOUNT_MASK: u32 = (1 << COLOR_SHIFT) - 1;\n\n// ╒════════╤═══════════════════ Colors ═══════════════════════════╕\n// │ Color  │ Meaning                                              │\n// ├────────┼──────────────────────────────────────────────────────┤\n// │ BLACK  │ In use or free                                       │\n// │ GRAY   │ Possible member of cycle                             │\n// │ WHITE  │ Member of garbage cycle                              │\n// │ PURPLE │ Possible root of cycle                               │\n// │ RED    │ Candidate cycle undergoing Σ-computation *concurrent │\n// │ ORANGE │ Candidate cycle awaiting epoch boundary  *concurrent │\n// └────────┴──────────────────────────────────────────────────────┘\n// Acyclic detection has been decoupled, hence no GREEN.\n\n// @ts-ignore: decorator\n@inline const COLOR_BLACK: u32 = 0 << COLOR_SHIFT;\n// @ts-ignore: decorator\n@inline const COLOR_GRAY: u32 = 1 << COLOR_SHIFT;\n// @ts-ignore: decorator\n@inline const COLOR_WHITE: u32 = 2 << COLOR_SHIFT;\n// @ts-ignore: decorator\n@inline const COLOR_PURPLE: u32 = 3 << COLOR_SHIFT;\n// @ts-ignore: decorator\n// @inline const COLOR_RED: u32 = 4 << COLOR_SHIFT;\n// @ts-ignore: decorator\n// @inline const COLOR_ORANGE: u32 = 5 << COLOR_SHIFT;\n\n// @ts-ignore: decorator\n@inline const VISIT_DECREMENT = 1; // guard 0\n// @ts-ignore: decorator\n@inline const VISIT_MARKGRAY = 2;\n// @ts-ignore: decorator\n@inline const VISIT_SCAN = 3;\n// @ts-ignore: decorator\n@inline const VISIT_SCANBLACK = 4;\n// @ts-ignore: decorator\n@inline const VISIT_COLLECTWHITE = 5;\n\n// @ts-ignore: decorator\n@global @unsafe @lazy\nfunction __visit(ref: usize, cookie: i32): void { // eslint-disable-line @typescript-eslint/no-unused-vars\n  if (ref < __heap_base) return;\n  if (isDefined(__GC_ALL_ACYCLIC)) {\n    if (DEBUG) assert(cookie == VISIT_DECREMENT);\n    decrement(changetype<Block>(ref - BLOCK_OVERHEAD));\n  } else {\n    let s = changetype<Block>(ref - BLOCK_OVERHEAD);\n    switch (cookie) {\n      case VISIT_DECREMENT: {\n        decrement(s);\n        break;\n      }\n      case VISIT_MARKGRAY: {\n        if (DEBUG) assert((s.gcInfo & REFCOUNT_MASK) > 0);\n        s.gcInfo = s.gcInfo - 1;\n        markGray(s);\n        break;\n      }\n      case VISIT_SCAN: {\n        scan(s);\n        break;\n      }\n      case VISIT_SCANBLACK: {\n        let info = s.gcInfo;\n        assert((info & ~REFCOUNT_MASK) == ((info + 1) & ~REFCOUNT_MASK)); // overflow\n        s.gcInfo = info + 1;\n        if ((info & COLOR_MASK) != COLOR_BLACK) {\n          scanBlack(s);\n        }\n        break;\n      }\n      case VISIT_COLLECTWHITE: {\n        collectWhite(s);\n        break;\n      }\n      default: if (DEBUG) assert(false);\n    }\n  }\n}\n\n/** Increments the reference count of the specified block by one.*/\nfunction increment(s: Block): void {\n  var info = s.gcInfo;\n  assert((info & ~REFCOUNT_MASK) == ((info + 1) & ~REFCOUNT_MASK)); // overflow\n  s.gcInfo = info + 1;\n  if (isDefined(ASC_RTRACE)) onincrement(s);\n  if (DEBUG) assert(!(s.mmInfo & 1)); // used\n}\n\n/** Decrements the reference count of the specified block by one, possibly freeing it. */\n// @ts-ignore: decorator\n@lazy\nfunction decrement(s: Block): void {\n  var info = s.gcInfo;\n  var rc = info & REFCOUNT_MASK;\n  if (isDefined(ASC_RTRACE)) ondecrement(s);\n  if (DEBUG) assert(!(s.mmInfo & 1)); // used\n  if (rc == 1) {\n    __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_DECREMENT);\n    if (isDefined(__GC_ALL_ACYCLIC)) {\n      if (DEBUG) assert(!(info & BUFFERED_MASK));\n      finalize(s);\n    } else {\n      if (!(info & BUFFERED_MASK)) {\n        finalize(s);\n      } else {\n        s.gcInfo = BUFFERED_MASK | COLOR_BLACK | 0;\n      }\n    }\n  } else {\n    if (DEBUG) assert(rc > 0);\n    if (isDefined(__GC_ALL_ACYCLIC)) {\n      s.gcInfo = (info & ~REFCOUNT_MASK) | (rc - 1);\n    } else {\n      if (!(__typeinfo(s.rtId) & TypeinfoFlags.ACYCLIC)) {\n        s.gcInfo = BUFFERED_MASK | COLOR_PURPLE | (rc - 1);\n        if (!(info & BUFFERED_MASK)) {\n          appendRoot(s);\n        }\n      } else {\n        s.gcInfo = (info & ~REFCOUNT_MASK) | (rc - 1);\n      }\n    }\n  }\n}\n\n/** Finalizes the specified block, giving it back to the memory manager. */\nfunction finalize(s: Block): void {\n  if (isDefined(__finalize)) {\n    __finalize(changetype<usize>(s) + BLOCK_OVERHEAD);\n  }\n  freeBlock(ROOT, s);\n}\n\n/** Buffer of possible roots. */\n// @ts-ignore: decorator\n@lazy var ROOTS: usize;\n/** Current absolute offset into the `ROOTS` buffer. */\n// @ts-ignore: decorator\n@lazy var CUR: usize = 0;\n/** Current absolute end offset into the `ROOTS` buffer. */\n// @ts-ignore: decorator\n@lazy var END: usize = 0;\n\n/** Appends a block to possible roots. */\nfunction appendRoot(s: Block): void {\n  var cur = CUR;\n  if (cur >= END) {\n    growRoots(); // TBD: either that or pick a default and force collection on overflow\n    cur = CUR;\n  }\n  store<Block>(cur, s);\n  CUR = cur + sizeof<usize>();\n}\n\n/** Grows the roots buffer if it ran full. */\nfunction growRoots(): void {\n  var oldRoots = ROOTS;\n  var oldSize = CUR - oldRoots;\n  var newSize = max(oldSize * 2, 64 << alignof<usize>());\n  var newRoots = __alloc(newSize, 0);\n  memory.copy(newRoots, oldRoots, oldSize);\n  if (oldRoots) __free(oldRoots);\n  ROOTS = newRoots;\n  CUR = newRoots + oldSize;\n  END = newRoots + newSize;\n}\n\n/** Collects cyclic garbage. */\n// @ts-ignore: decorator\n@global @unsafe @lazy\nexport function __collect(): void {\n  if (isDefined(__GC_ALL_ACYCLIC)) return;\n\n  // markRoots\n  var roots = ROOTS;\n  var cur = roots;\n  for (let pos = cur, end = CUR; pos < end; pos += sizeof<usize>()) {\n    let s = load<Block>(pos);\n    let info = s.gcInfo;\n    if ((info & COLOR_MASK) == COLOR_PURPLE && (info & REFCOUNT_MASK) > 0) {\n      markGray(s);\n      store<Block>(cur, s);\n      cur += sizeof<usize>();\n    } else {\n      if ((info & COLOR_MASK) == COLOR_BLACK && !(info & REFCOUNT_MASK)) {\n        finalize(s);\n      } else {\n        s.gcInfo = info & ~BUFFERED_MASK;\n      }\n    }\n  }\n  CUR = cur;\n\n  // scanRoots\n  for (let pos = roots; pos < cur; pos += sizeof<usize>()) {\n    scan(load<Block>(pos));\n  }\n\n  // collectRoots\n  for (let pos = roots; pos < cur; pos += sizeof<usize>()) {\n    let s = load<Block>(pos);\n    s.gcInfo = s.gcInfo & ~BUFFERED_MASK;\n    collectWhite(s);\n  }\n  CUR = roots;\n}\n\n/** Marks a block as gray (possible member of cycle) during the collection phase. */\nfunction markGray(s: Block): void {\n  var info = s.gcInfo;\n  if ((info & COLOR_MASK) != COLOR_GRAY) {\n    s.gcInfo = (info & ~COLOR_MASK) | COLOR_GRAY;\n    __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_MARKGRAY);\n  }\n}\n\n/** Scans a block during the collection phase, determining whether it is garbage or not. */\nfunction scan(s: Block): void {\n  var info = s.gcInfo;\n  if ((info & COLOR_MASK) == COLOR_GRAY) {\n    if ((info & REFCOUNT_MASK) > 0) {\n      scanBlack(s);\n    } else {\n      s.gcInfo = (info & ~COLOR_MASK) | COLOR_WHITE;\n      __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_SCAN);\n    }\n  }\n}\n\n/** Marks a block as black (in use) if it was found to be reachable during the collection phase. */\nfunction scanBlack(s: Block): void {\n  s.gcInfo = (s.gcInfo & ~COLOR_MASK) | COLOR_BLACK;\n  __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_SCANBLACK);\n}\n\n/** Collects all white (member of a garbage cycle) nodes when completing the collection phase.  */\nfunction collectWhite(s: Block): void {\n  var info = s.gcInfo;\n  if ((info & COLOR_MASK) == COLOR_WHITE && !(info & BUFFERED_MASK)) {\n    s.gcInfo = (info & ~COLOR_MASK) | COLOR_BLACK;\n    __visit_members(changetype<usize>(s) + BLOCK_OVERHEAD, VISIT_COLLECTWHITE);\n    finalize(s);\n  }\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __retain(ptr: usize): usize {\n  if (ptr > __heap_base) increment(changetype<Block>(ptr - BLOCK_OVERHEAD));\n  return ptr;\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __release(ptr: usize): void {\n  if (ptr > __heap_base) decrement(changetype<Block>(ptr - BLOCK_OVERHEAD));\n}\n","import { AL_BITS, AL_MASK, DEBUG, BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from \"rt/common\";\nimport { onalloc, onresize, onmove, onfree } from \"./rtrace\";\nimport { REFCOUNT_MASK } from \"./pure\";\n\n// === The TLSF (Two-Level Segregate Fit) memory allocator ===\n// see: http://www.gii.upv.es/tlsf/\n\n// - `ffs(x)` is equivalent to `ctz(x)` with x != 0\n// - `fls(x)` is equivalent to `sizeof(x) * 8 - clz(x) - 1`\n\n// ╒══════════════ Block size interpretation (32-bit) ═════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┼─┴─┴─┴─╫─┴─┴─┴─┤\n// │ |                    FL                       │ SB = SL + AL  │ ◄─ usize\n// └───────────────────────────────────────────────┴───────╨───────┘\n// FL: first level, SL: second level, AL: alignment, SB: small block\n\n// @ts-ignore: decorator\n@inline const SL_BITS: u32 = 4;\n// @ts-ignore: decorator\n@inline const SL_SIZE: u32 = 1 << SL_BITS;\n\n// @ts-ignore: decorator\n@inline const SB_BITS: u32 = SL_BITS + AL_BITS;\n// @ts-ignore: decorator\n@inline const SB_SIZE: u32 = 1 << SB_BITS;\n\n// @ts-ignore: decorator\n@inline const FL_BITS: u32 = 31 - SB_BITS;\n\n// [00]: < 256B (SB)  [12]: < 1M\n// [01]: < 512B       [13]: < 2M\n// [02]: < 1K         [14]: < 4M\n// [03]: < 2K         [15]: < 8M\n// [04]: < 4K         [16]: < 16M\n// [05]: < 8K         [17]: < 32M\n// [06]: < 16K        [18]: < 64M\n// [07]: < 32K        [19]: < 128M\n// [08]: < 64K        [20]: < 256M\n// [09]: < 128K       [21]: < 512M\n// [10]: < 256K       [22]: <= 1G - OVERHEAD\n// [11]: < 512K\n// VMs limit to 2GB total (currently), making one 1G block max (or three 512M etc.) due to block overhead\n\n// Tags stored in otherwise unused alignment bits\n\n// @ts-ignore: decorator\n@inline const FREE: usize = 1 << 0;\n// @ts-ignore: decorator\n@inline const LEFTFREE: usize = 1 << 1;\n// @ts-ignore: decorator\n@inline const TAGS_MASK: usize = FREE | LEFTFREE; // <= AL_MASK\n\n// ╒════════════════════ Block layout (32-bit) ════════════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┼─┼─┼─┤ overhead   ┐\n// │                          size                           │0│L│F│ ◄─┐ info\n// ├─────────────────────────────────────────────────────────┴─┴─┴─┤   │\n// │                                                               │   │\n// │               ... additional runtime overhead ...             │   │\n// │                                                               │   │\n// ╞═══════════════════════════════════════════════════════════════╡   │      ┐ ┘\n// │                        if free: ◄ prev                        │ ◄─┤ usize\n// ├───────────────────────────────────────────────────────────────┤   │\n// │                        if free: next ►                        │ ◄─┤\n// ├───────────────────────────────────────────────────────────────┤   │\n// │                             ...                               │   │    = 0\n// ├───────────────────────────────────────────────────────────────┤   │\n// │                        if free: back ▲                        │ ◄─┘\n// └───────────────────────────────────────────────────────────────┘ payload  ┘ >= MIN SIZE\n// F: FREE, L: LEFTFREE\n@unmanaged export class Block extends BLOCK {\n\n  /** Previous free block, if any. Only valid if free, otherwise part of payload. */\n  prev: Block | null;\n  /** Next free block, if any. Only valid if free, otherwise part of payload. */\n  next: Block | null;\n\n  // If the block is free, there is a 'back'reference at its end pointing at its start.\n}\n\n// Block constants. A block must have a minimum size of three pointers so it can hold `prev`,\n// `next` and `back` if free.\n\n// @ts-ignore: decorator\n@inline const BLOCK_MINSIZE: usize = (3 * sizeof<usize>() + AL_MASK) & ~AL_MASK; // prev + next + back\n// @ts-ignore: decorator\n// @inline const BLOCK_MAXSIZE: usize = 1 << (FL_BITS + SB_BITS - 1); // exclusive, lives in common.ts\n\n/** Gets the left block of a block. Only valid if the left block is free. */\n// @ts-ignore: decorator\n@inline function GETFREELEFT(block: Block): Block {\n  return load<Block>(changetype<usize>(block) - sizeof<usize>());\n}\n\n/** Gets the right block of of a block by advancing to the right by its size. */\n// @ts-ignore: decorator\n@inline function GETRIGHT(block: Block): Block {\n  return changetype<Block>(changetype<usize>(block) + BLOCK_OVERHEAD + (block.mmInfo & ~TAGS_MASK));\n}\n\n// ╒═════════════════════ Root layout (32-bit) ════════════════════╕\n//    3                   2                   1\n//  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0  bits\n// ├─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┤          ┐\n// │        0        |           flMap                            S│ ◄────┐\n// ╞═══════════════════════════════════════════════════════════════╡      │\n// │                           slMap[0] S                          │ ◄─┐  │\n// ├───────────────────────────────────────────────────────────────┤   │  │\n// │                           slMap[1]                            │ ◄─┤  │\n// ├───────────────────────────────────────────────────────────────┤  u32 │\n// │                           slMap[22]                           │ ◄─┘  │\n// ╞═══════════════════════════════════════════════════════════════╡    usize\n// │                            head[0]                            │ ◄────┤\n// ├───────────────────────────────────────────────────────────────┤      │\n// │                              ...                              │ ◄────┤\n// ├───────────────────────────────────────────────────────────────┤      │\n// │                           head[367]                           │ ◄────┤\n// ╞═══════════════════════════════════════════════════════════════╡      │\n// │                             tail                              │ ◄────┘\n// └───────────────────────────────────────────────────────────────┘   SIZE   ┘\n// S: Small blocks map\n@unmanaged class Root {\n  /** First level bitmap. */\n  flMap: usize;\n}\n\n// Root constants. Where stuff is stored inside of the root structure.\n\n// @ts-ignore: decorator\n@inline const SL_START: usize = sizeof<usize>();\n// @ts-ignore: decorator\n@inline const SL_END: usize = SL_START + (FL_BITS << alignof<u32>());\n// @ts-ignore: decorator\n@inline const HL_START: usize = (SL_END + AL_MASK) & ~AL_MASK;\n// @ts-ignore: decorator\n@inline const HL_END: usize = HL_START + FL_BITS * SL_SIZE * sizeof<usize>();\n// @ts-ignore: decorator\n@inline const ROOT_SIZE: usize = HL_END + sizeof<usize>();\n\n// @ts-ignore: decorator\n@lazy export var ROOT: Root;\n\n/** Gets the second level map of the specified first level. */\n// @ts-ignore: decorator\n@inline function GETSL(root: Root, fl: usize): u32 {\n  return load<u32>(\n    changetype<usize>(root) + (fl << alignof<u32>()),\n    SL_START\n  );\n}\n\n/** Sets the second level map of the specified first level. */\n// @ts-ignore: decorator\n@inline function SETSL(root: Root, fl: usize, slMap: u32): void {\n  store<u32>(\n    changetype<usize>(root) + (fl << alignof<u32>()),\n    slMap,\n    SL_START\n  );\n}\n\n/** Gets the head of the free list for the specified combination of first and second level. */\n// @ts-ignore: decorator\n@inline function GETHEAD(root: Root, fl: usize, sl: u32): Block | null {\n  return load<Block>(\n    changetype<usize>(root) + (((fl << SL_BITS) + <usize>sl) << alignof<usize>()),\n    HL_START\n  );\n}\n\n/** Sets the head of the free list for the specified combination of first and second level. */\n// @ts-ignore: decorator\n@inline function SETHEAD(root: Root, fl: usize, sl: u32, head: Block | null): void {\n  store<Block | null>(\n    changetype<usize>(root) + (((fl << SL_BITS) + <usize>sl) << alignof<usize>()),\n    head,\n    HL_START\n  );\n}\n\n/** Gets the tail block.. */\n// @ts-ignore: decorator\n@inline function GETTAIL(root: Root): Block {\n  return load<Block>(\n    changetype<usize>(root),\n    HL_END\n  );\n}\n\n/** Sets the tail block. */\n// @ts-ignore: decorator\n@inline function SETTAIL(root: Root, tail: Block): void {\n  store<Block>(\n    changetype<usize>(root),\n    tail,\n    HL_END\n  );\n}\n\n/** Inserts a previously used block back into the free list. */\nfunction insertBlock(root: Root, block: Block): void {\n  if (DEBUG) assert(block); // cannot be null\n  var blockInfo = block.mmInfo;\n  if (DEBUG) assert(blockInfo & FREE); // must be free\n\n  var right = GETRIGHT(block);\n  var rightInfo = right.mmInfo;\n\n  // merge with right block if also free\n  if (rightInfo & FREE) {\n    let newSize = (blockInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK);\n    if (newSize < BLOCK_MAXSIZE) {\n      removeBlock(root, right);\n      block.mmInfo = blockInfo = (blockInfo & TAGS_MASK) | newSize;\n      right = GETRIGHT(block);\n      rightInfo = right.mmInfo;\n      // 'back' is set below\n    }\n  }\n\n  // merge with left block if also free\n  if (blockInfo & LEFTFREE) {\n    let left = GETFREELEFT(block);\n    let leftInfo = left.mmInfo;\n    if (DEBUG) assert(leftInfo & FREE); // must be free according to right tags\n    let newSize = (leftInfo & ~TAGS_MASK) + BLOCK_OVERHEAD + (blockInfo & ~TAGS_MASK);\n    if (newSize < BLOCK_MAXSIZE) {\n      removeBlock(root, left);\n      left.mmInfo = blockInfo = (leftInfo & TAGS_MASK) | newSize;\n      block = left;\n      // 'back' is set below\n    }\n  }\n\n  right.mmInfo = rightInfo | LEFTFREE;\n  // right is no longer used now, hence rightInfo is not synced\n\n  // we now know the size of the block\n  var size = blockInfo & ~TAGS_MASK;\n  if (DEBUG) assert(size >= BLOCK_MINSIZE && size < BLOCK_MAXSIZE); // must be a valid size\n  if (DEBUG) assert(changetype<usize>(block) + BLOCK_OVERHEAD + size == changetype<usize>(right)); // must match\n\n  // set 'back' to itself at the end of block\n  store<Block>(changetype<usize>(right) - sizeof<usize>(), block);\n\n  // mapping_insert\n  var fl: usize, sl: u32;\n  if (size < SB_SIZE) {\n    fl = 0;\n    sl = <u32>(size >> AL_BITS);\n  } else {\n    const inv: usize = sizeof<usize>() * 8 - 1;\n    fl = inv - clz<usize>(size);\n    sl = <u32>((size >> (fl - SL_BITS)) ^ (1 << SL_BITS));\n    fl -= SB_BITS - 1;\n  }\n  if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range\n\n  // perform insertion\n  var head = GETHEAD(root, fl, sl);\n  block.prev = null;\n  block.next = head;\n  if (head) head.prev = block;\n  SETHEAD(root, fl, sl, block);\n\n  // update first and second level maps\n  root.flMap |= (1 << fl);\n  SETSL(root, fl, GETSL(root, fl) | (1 << sl));\n}\n\n/** Removes a free block from internal lists. */\nfunction removeBlock(root: Root, block: Block): void {\n  var blockInfo = block.mmInfo;\n  if (DEBUG) assert(blockInfo & FREE); // must be free\n  var size = blockInfo & ~TAGS_MASK;\n  if (DEBUG) assert(size >= BLOCK_MINSIZE && size < BLOCK_MAXSIZE); // must be valid\n\n  // mapping_insert\n  var fl: usize, sl: u32;\n  if (size < SB_SIZE) {\n    fl = 0;\n    sl = <u32>(size >> AL_BITS);\n  } else {\n    const inv: usize = sizeof<usize>() * 8 - 1;\n    fl = inv - clz<usize>(size);\n    sl = <u32>((size >> (fl - SL_BITS)) ^ (1 << SL_BITS));\n    fl -= SB_BITS - 1;\n  }\n  if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range\n\n  // link previous and next free block\n  var prev = block.prev;\n  var next = block.next;\n  if (prev) prev.next = next;\n  if (next) next.prev = prev;\n\n  // update head if we are removing it\n  if (block == GETHEAD(root, fl, sl)) {\n    SETHEAD(root, fl, sl, next);\n\n    // clear second level map if head is empty now\n    if (!next) {\n      let slMap = GETSL(root, fl);\n      SETSL(root, fl, slMap &= ~(1 << sl));\n\n      // clear first level map if second level is empty now\n      if (!slMap) root.flMap &= ~(1 << fl);\n    }\n  }\n  // note: does not alter left/back because it is likely that splitting\n  // is performed afterwards, invalidating those changes. so, the caller\n  // must perform those updates.\n}\n\n/** Searches for a free block of at least the specified size. */\nfunction searchBlock(root: Root, size: usize): Block | null {\n  // size was already asserted by caller\n\n  // mapping_search\n  var fl: usize, sl: u32;\n  if (size < SB_SIZE) {\n    fl = 0;\n    sl = <u32>(size >> AL_BITS);\n  } else {\n    const halfMaxSize = BLOCK_MAXSIZE >> 1; // don't round last fl\n    const inv: usize = sizeof<usize>() * 8 - 1;\n    const invRound = inv - SL_BITS;\n    let requestSize = size < halfMaxSize\n      ? size + (1 << (invRound - clz<usize>(size))) - 1\n      : size;\n    fl = inv - clz<usize>(requestSize);\n    sl = <u32>((requestSize >> (fl - SL_BITS)) ^ (1 << SL_BITS));\n    fl -= SB_BITS - 1;\n  }\n  if (DEBUG) assert(fl < FL_BITS && sl < SL_SIZE); // fl/sl out of range\n\n  // search second level\n  var slMap = GETSL(root, fl) & (~0 << sl);\n  var head: Block | null = null;\n  if (!slMap) {\n    // search next larger first level\n    let flMap = root.flMap & (~0 << (fl + 1));\n    if (!flMap) {\n      head = null;\n    } else {\n      fl = ctz<usize>(flMap);\n      slMap = GETSL(root, fl);\n      if (DEBUG) assert(slMap);  // can't be zero if fl points here\n      head = GETHEAD(root, fl, ctz<u32>(slMap));\n    }\n  } else {\n    head = GETHEAD(root, fl, ctz<u32>(slMap));\n  }\n  return head;\n}\n\n/** Prepares the specified block before (re-)use, possibly splitting it. */\nfunction prepareBlock(root: Root, block: Block, size: usize): void {\n  // size was already asserted by caller\n\n  var blockInfo = block.mmInfo;\n  if (DEBUG) assert(!(size & AL_MASK)); // size must be aligned so the new block is\n\n  // split if the block can hold another MINSIZE block incl. overhead\n  var remaining = (blockInfo & ~TAGS_MASK) - size;\n  if (remaining >= BLOCK_OVERHEAD + BLOCK_MINSIZE) {\n    block.mmInfo = size | (blockInfo & LEFTFREE); // also discards FREE\n\n    let spare = changetype<Block>(changetype<usize>(block) + BLOCK_OVERHEAD + size);\n    spare.mmInfo = (remaining - BLOCK_OVERHEAD) | FREE; // not LEFTFREE\n    insertBlock(root, spare); // also sets 'back'\n\n  // otherwise tag block as no longer FREE and right as no longer LEFTFREE\n  } else {\n    block.mmInfo = blockInfo & ~FREE;\n    GETRIGHT(block).mmInfo &= ~LEFTFREE;\n  }\n}\n\n/** Adds more memory to the pool. */\nfunction addMemory(root: Root, start: usize, end: usize): bool {\n  if (DEBUG) {\n    assert(\n      start <= end &&       // must be valid\n      !(start & AL_MASK) && // must be aligned\n      !(end & AL_MASK)      // must be aligned\n    );\n  }\n\n  var tail = GETTAIL(root);\n  var tailInfo: usize = 0;\n  if (tail) { // more memory\n    if (DEBUG) assert(start >= changetype<usize>(tail) + BLOCK_OVERHEAD);\n\n    // merge with current tail if adjacent\n    if (start - BLOCK_OVERHEAD == changetype<usize>(tail)) {\n      start -= BLOCK_OVERHEAD;\n      tailInfo = tail.mmInfo;\n    } else {\n      // We don't do this, but a user might `memory.grow` manually\n      // leading to non-adjacent pages managed by TLSF.\n    }\n\n  } else if (DEBUG) { // first memory\n    assert(start >= changetype<usize>(root) + ROOT_SIZE); // starts after root\n  }\n\n  // check if size is large enough for a free block and the tail block\n  var size = end - start;\n  if (size < BLOCK_OVERHEAD + BLOCK_MINSIZE + BLOCK_OVERHEAD) {\n    return false;\n  }\n\n  // left size is total minus its own and the zero-length tail's header\n  var leftSize = size - (BLOCK_OVERHEAD << 1);\n  var left = changetype<Block>(start);\n  left.mmInfo = leftSize | FREE | (tailInfo & LEFTFREE);\n  left.prev = null;\n  left.next = null;\n\n  // tail is a zero-length used block\n  tail = changetype<Block>(start + size - BLOCK_OVERHEAD);\n  tail.mmInfo = 0 | LEFTFREE;\n  SETTAIL(root, tail);\n\n  insertBlock(root, left); // also merges with free left before tail / sets 'back'\n\n  return true;\n}\n\n/** Grows memory to fit at least another block of the specified size. */\nfunction growMemory(root: Root, size: usize): void {\n  if (ASC_LOW_MEMORY_LIMIT) {\n    unreachable();\n    return;\n  }\n  // Here, both rounding performed in searchBlock ...\n  const halfMaxSize = BLOCK_MAXSIZE >> 1;\n  if (size < halfMaxSize) { // don't round last fl\n    const invRound = (sizeof<usize>() * 8 - 1) - SL_BITS;\n    size += (1 << (invRound - clz<usize>(size))) - 1;\n  }\n  // and additional BLOCK_OVERHEAD must be taken into account. If we are going\n  // to merge with the tail block, that's one time, otherwise it's two times.\n  var pagesBefore = memory.size();\n  size += BLOCK_OVERHEAD << usize((<usize>pagesBefore << 16) - BLOCK_OVERHEAD != changetype<usize>(GETTAIL(root)));\n  var pagesNeeded = <i32>(((size + 0xffff) & ~0xffff) >>> 16);\n  var pagesWanted = max(pagesBefore, pagesNeeded); // double memory\n  if (memory.grow(pagesWanted) < 0) {\n    if (memory.grow(pagesNeeded) < 0) unreachable();\n  }\n  var pagesAfter = memory.size();\n  addMemory(root, <usize>pagesBefore << 16, <usize>pagesAfter << 16);\n}\n\n/** Prepares and checks an allocation size. */\nfunction prepareSize(size: usize): usize {\n  if (size >= BLOCK_MAXSIZE) throw new Error(\"allocation too large\");\n  return max<usize>((size + AL_MASK) & ~AL_MASK, BLOCK_MINSIZE); // align and ensure min size\n}\n\n/** Initializes the root structure. */\nexport function maybeInitialize(): Root {\n  var root = ROOT;\n  if (!root) {\n    let rootOffset = (__heap_base + AL_MASK) & ~AL_MASK;\n    let pagesBefore = memory.size();\n    let pagesNeeded = <i32>((((rootOffset + ROOT_SIZE) + 0xffff) & ~0xffff) >>> 16);\n    if (pagesNeeded > pagesBefore && memory.grow(pagesNeeded - pagesBefore) < 0) unreachable();\n    root = changetype<Root>(rootOffset);\n    root.flMap = 0;\n    SETTAIL(root, changetype<Block>(0));\n    for (let fl: usize = 0; fl < FL_BITS; ++fl) {\n      SETSL(root, fl, 0);\n      for (let sl: u32 = 0; sl < SL_SIZE; ++sl) {\n        SETHEAD(root, fl, sl, null);\n      }\n    }\n    let memStart = (rootOffset + ROOT_SIZE + AL_MASK) & ~AL_MASK;\n    if (ASC_LOW_MEMORY_LIMIT) {\n      const memEnd = <usize>ASC_LOW_MEMORY_LIMIT & ~AL_MASK;\n      if (memStart <= memEnd) addMemory(root, memStart, memEnd);\n      else unreachable(); // low memory limit already exceeded\n    } else {\n      addMemory(root, memStart, memory.size() << 16);\n    }\n    ROOT = root;\n  }\n  return root;\n}\n\n// @ts-ignore: decorator\n@lazy var collectLock: bool = false;\n\n/** Allocates a block of the specified size. */\nexport function allocateBlock(root: Root, size: usize, id: u32): Block {\n  if (DEBUG) assert(!collectLock); // must not allocate while collecting\n  var payloadSize = prepareSize(size);\n  var block = searchBlock(root, payloadSize);\n  if (!block) {\n    if (gc.auto) {\n      if (DEBUG) collectLock = true;\n      __collect();\n      if (DEBUG) collectLock = false;\n      block = searchBlock(root, payloadSize);\n      if (!block) {\n        growMemory(root, payloadSize);\n        block = changetype<Block>(searchBlock(root, payloadSize));\n        if (DEBUG) assert(block); // must be found now\n      }\n    } else {\n      growMemory(root, payloadSize);\n      block = changetype<Block>(searchBlock(root, payloadSize));\n      if (DEBUG) assert(block); // must be found now\n    }\n  }\n  if (DEBUG) assert((block.mmInfo & ~TAGS_MASK) >= payloadSize); // must fit\n  block.gcInfo = 0; // RC=0\n  block.rtId = id;\n  block.rtSize = <u32>size;\n  removeBlock(root, <Block>block);\n  prepareBlock(root, <Block>block, payloadSize);\n  if (isDefined(ASC_RTRACE)) onalloc(block);\n  return <Block>block;\n}\n\n/** Reallocates a block to the specified size. */\nexport function reallocateBlock(root: Root, block: Block, size: usize): Block {\n  var payloadSize = prepareSize(size);\n  var blockInfo = block.mmInfo;\n  var currentSize = blockInfo & ~TAGS_MASK;\n\n  // possibly split and update runtime size if it still fits\n  if (payloadSize <= currentSize) {\n    prepareBlock(root, block, payloadSize);\n    block.rtSize = <u32>size;\n    if (isDefined(ASC_RTRACE)) {\n      if (payloadSize != currentSize) onresize(block, currentSize);\n    }\n    return block;\n  }\n\n  // merge with right free block if merger is large enough\n  var right = GETRIGHT(block);\n  var rightInfo = right.mmInfo;\n  if (rightInfo & FREE) {\n    let mergeSize = currentSize + BLOCK_OVERHEAD + (rightInfo & ~TAGS_MASK);\n    if (mergeSize >= payloadSize) {\n      removeBlock(root, right);\n      // TODO: this can yield an intermediate block larger than BLOCK_MAXSIZE, which\n      // is immediately split though. does this trigger any assertions / issues?\n      block.mmInfo = (blockInfo & TAGS_MASK) | mergeSize;\n      block.rtSize = <u32>size;\n      prepareBlock(root, block, payloadSize);\n      if (isDefined(ASC_RTRACE)) onresize(block, currentSize);\n      return block;\n    }\n  }\n\n  // otherwise move the block\n  var newBlock = allocateBlock(root, size, block.rtId); // may invalidate cached blockInfo\n  newBlock.gcInfo = block.gcInfo; // keep RC\n  memory.copy(changetype<usize>(newBlock) + BLOCK_OVERHEAD, changetype<usize>(block) + BLOCK_OVERHEAD, size);\n  if (changetype<usize>(block) >= __heap_base) {\n    if (isDefined(ASC_RTRACE)) onmove(block, newBlock);\n    freeBlock(root, block);\n  }\n  return newBlock;\n}\n\n/** Frees a block. */\nexport function freeBlock(root: Root, block: Block): void {\n  var blockInfo = block.mmInfo;\n  block.mmInfo = blockInfo | FREE;\n  if (isDefined(ASC_RTRACE)) onfree(block);\n  insertBlock(root, block);\n}\n\n/** Checks that a used block is valid to be freed or reallocated. */\nfunction checkUsedBlock(ref: usize): Block {\n  var block = changetype<Block>(ref - BLOCK_OVERHEAD);\n  assert(\n    ref != 0 && !(ref & AL_MASK) &&  // must exist and be aligned\n    !(block.mmInfo & FREE) &&        // must be used\n    !(block.gcInfo & ~REFCOUNT_MASK) // not buffered or != BLACK\n  );\n  return block;\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __alloc(size: usize, id: u32): usize {\n  return changetype<usize>(\n    allocateBlock(maybeInitialize(), size, id)\n  ) + BLOCK_OVERHEAD;\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __realloc(ref: usize, size: usize): usize {\n  return changetype<usize>(\n    reallocateBlock(maybeInitialize(), checkUsedBlock(ref), size)\n  ) + BLOCK_OVERHEAD;\n}\n\n// @ts-ignore: decorator\n@global @unsafe\nexport function __free(ref: usize): void {\n  freeBlock(maybeInitialize(), checkUsedBlock(ref));\n}\n","/// <reference path=\"./rt/index.d.ts\" />\n\n/** Garbage collector interface. */\nexport namespace gc {\n\n  /** Can be set to `false` to disable automatic collection. Defaults to `true`. */\n  export var auto: bool = true;\n\n  /** Performs a full garbage collection cycle. */\n  export function collect(): void {\n    __collect();\n  }\n}\n","// Constants that will be shared by the wasm core of the emulator\n// And libraries built around the wasm (such as the official JS), or @CryZe wasmboy-rs\n\n// ----------------------------------\n// Wasmboy Memory Map\n// https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing\n// ----------------------------------\n\n// AssemblyScript\nexport const ASSEMBLYSCRIPT_MEMORY_LOCATION: i32 = 0x000000;\nexport const ASSEMBLYSCRIPT_MEMORY_SIZE: i32 = 0x000400;\n\n// WasmBoy States\nexport const WASMBOY_STATE_LOCATION: i32 = ASSEMBLYSCRIPT_MEMORY_LOCATION + ASSEMBLYSCRIPT_MEMORY_SIZE;\nexport const WASMBOY_STATE_SIZE: i32 = 0x000400;\n\n// Gameboy Internal Memory\nexport const VIDEO_RAM_LOCATION: i32 = WASMBOY_STATE_LOCATION + WASMBOY_STATE_SIZE;\nexport const VIDEO_RAM_SIZE: i32 = 0x004000;\n\nexport const WORK_RAM_LOCATION: i32 = VIDEO_RAM_LOCATION + VIDEO_RAM_SIZE;\nexport const WORK_RAM_SIZE: i32 = 0x008000;\n\nexport const OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION: i32 = WORK_RAM_LOCATION + WORK_RAM_SIZE;\nexport const OTHER_GAMEBOY_INTERNAL_MEMORY_SIZE: i32 = 0x004000;\n\n// General Gameboy Internal Memory\nexport const GAMEBOY_INTERNAL_MEMORY_LOCATION: i32 = VIDEO_RAM_LOCATION;\nexport const GAMEBOY_INTERNAL_MEMORY_SIZE: i32 =\n  OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION - VIDEO_RAM_LOCATION + OTHER_GAMEBOY_INTERNAL_MEMORY_SIZE;\n\n// Graphics Output\nexport const GBC_PALETTE_LOCATION: i32 = OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION + OTHER_GAMEBOY_INTERNAL_MEMORY_SIZE;\nexport const GBC_PALETTE_SIZE: i32 = 0x000080;\n\nexport const BG_PRIORITY_MAP_LOCATION: i32 = GBC_PALETTE_LOCATION + GBC_PALETTE_SIZE;\nexport const BG_PRIORITY_MAP_SIZE: i32 = 0x005c00;\n\nexport const FRAME_LOCATION: i32 = BG_PRIORITY_MAP_LOCATION + BG_PRIORITY_MAP_SIZE;\nexport const FRAME_SIZE: i32 = 0x016c00;\n\nexport const BACKGROUND_MAP_LOCATION: i32 = FRAME_LOCATION + FRAME_SIZE;\nexport const BACKGROUND_MAP_SIZE: i32 = 0x030000;\n\nexport const TILE_DATA_LOCATION: i32 = BACKGROUND_MAP_LOCATION + BACKGROUND_MAP_SIZE;\nexport const TILE_DATA_SIZE: i32 = 0x024000;\n\nexport const OAM_TILES_LOCATION: i32 = TILE_DATA_LOCATION + TILE_DATA_SIZE;\nexport const OAM_TILES_SIZE: i32 = 0x003c00;\n\n// General Graphics Output\nexport const GRAPHICS_OUTPUT_LOCATION: i32 = GBC_PALETTE_LOCATION;\nexport const GRAPHICS_OUTPUT_SIZE: i32 = OAM_TILES_LOCATION - GBC_PALETTE_LOCATION + OAM_TILES_SIZE;\n\n// Audio Output\nexport const CHANNEL_1_BUFFER_LOCATION: i32 = OAM_TILES_LOCATION + OAM_TILES_SIZE;\nexport const CHANNEL_1_BUFFER_SIZE: i32 = 0x020000;\n\nexport const CHANNEL_2_BUFFER_LOCATION: i32 = CHANNEL_1_BUFFER_LOCATION + CHANNEL_1_BUFFER_SIZE;\nexport const CHANNEL_2_BUFFER_SIZE: i32 = 0x020000;\n\nexport const CHANNEL_3_BUFFER_LOCATION: i32 = CHANNEL_2_BUFFER_LOCATION + CHANNEL_2_BUFFER_SIZE;\nexport const CHANNEL_3_BUFFER_SIZE: i32 = 0x020000;\n\nexport const CHANNEL_4_BUFFER_LOCATION: i32 = CHANNEL_3_BUFFER_LOCATION + CHANNEL_3_BUFFER_SIZE;\nexport const CHANNEL_4_BUFFER_SIZE: i32 = 0x020000;\n\nexport const AUDIO_BUFFER_LOCATION: i32 = CHANNEL_4_BUFFER_LOCATION + CHANNEL_4_BUFFER_SIZE;\nexport const AUDIO_BUFFER_SIZE: i32 = 0x020000;\n\n// Catridge Ram\nexport const CARTRIDGE_RAM_LOCATION: i32 = AUDIO_BUFFER_LOCATION + AUDIO_BUFFER_SIZE;\nexport const CARTRIDGE_RAM_SIZE: i32 = 0x020000;\n\n// Boot ROM\n// http://gbdev.gg8.se/files/roms/bootroms/\n// Largest Boot rom is GBC, at 2.5KB\nexport const BOOT_ROM_LOCATION: i32 = CARTRIDGE_RAM_LOCATION + CARTRIDGE_RAM_SIZE;\nexport const BOOT_ROM_SIZE: i32 = 0x000a00;\n\n// Cartridge ROM\nexport const CARTRIDGE_ROM_LOCATION: i32 = BOOT_ROM_LOCATION + BOOT_ROM_SIZE;\nexport const CARTRIDGE_ROM_SIZE: i32 = 0x7e0400;\n\n// Debug Memory\nexport const DEBUG_GAMEBOY_MEMORY_LOCATION: i32 = CARTRIDGE_ROM_LOCATION + CARTRIDGE_ROM_SIZE;\nexport const DEBUG_GAMEBOY_MEMORY_SIZE: i32 = 0xffff;\n\n// Final General Size\nexport const WASMBOY_MEMORY_LOCATION: i32 = 0x000000;\nexport const WASMBOY_MEMORY_SIZE: i32 = DEBUG_GAMEBOY_MEMORY_LOCATION + DEBUG_GAMEBOY_MEMORY_SIZE + 1;\nexport const WASMBOY_WASM_PAGES: i32 = ceil(WASMBOY_MEMORY_SIZE / 1024 / 64) + 1;\n","export class Config {\n  // Boot Rom\n  static enableBootRom: boolean = false;\n\n  // GBC Options\n  static useGbcWhenAvailable: boolean = true;\n\n  // Batch Processing\n  static audioBatchProcessing: boolean = false;\n  static graphicsBatchProcessing: boolean = false;\n  static timersBatchProcessing: boolean = false;\n\n  // Scanline Rendering\n  static graphicsDisableScanlineRendering: boolean = false;\n\n  // Acumulate Sound Samples\n  static audioAccumulateSamples: boolean = false;\n\n  // Tile Rednering\n  static tileRendering: boolean = false;\n  static tileCaching: boolean = false;\n\n  // Audio Debugging\n  static enableAudioDebugging: boolean = false;\n}\n","// File for all of the colors for different GB Palletes\n// https://i.imgur.com/HupBY.png\n// https://www.libretro.com/index.php/gambatte-progress-report/\n// https://tcrf.net/Notes:Game_Boy_Color_Bootstrap_ROM\n\n// Our default wasmboy gb colors\nexport class WasmBoyGBColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xf2f2f2;\n  static readonly bgLightGrey: i32 = 0xa0a0a0;\n  static readonly bgDarkGrey: i32 = 0x585858;\n  static readonly bgBlack: i32 = 0x080808;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xf2f2f2;\n  static readonly obj0LightGrey: i32 = 0xa0a0a0;\n  static readonly obj0DarkGrey: i32 = 0x585858;\n  static readonly obj0Black: i32 = 0x080808;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xf2f2f2;\n  static readonly obj1LightGrey: i32 = 0xa0a0a0;\n  static readonly obj1DarkGrey: i32 = 0x585858;\n  static readonly obj1Black: i32 = 0x080808;\n}\n\n// Action Button: Right\nexport class GreenColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x52ff00;\n  static readonly bgDarkGrey: i32 = 0xff4200;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x52ff00;\n  static readonly obj0DarkGrey: i32 = 0xff4200;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x52ff00;\n  static readonly obj1DarkGrey: i32 = 0xff4200;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: A + Down\nexport class OrangeColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xffff00;\n  static readonly bgDarkGrey: i32 = 0xff0000;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffff00;\n  static readonly obj0DarkGrey: i32 = 0xff0000;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffff00;\n  static readonly obj1DarkGrey: i32 = 0xff0000;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: Up\nexport class BrownColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xffad63;\n  static readonly bgDarkGrey: i32 = 0x843100;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffad63;\n  static readonly obj0DarkGrey: i32 = 0x843100;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffad63;\n  static readonly obj1DarkGrey: i32 = 0x843100;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: B + Right\nexport class InvertedColors {\n  //Bg\n  static readonly bgWhite: i32 = 0x000000;\n  static readonly bgLightGrey: i32 = 0x008484;\n  static readonly bgDarkGrey: i32 = 0xffde00;\n  static readonly bgBlack: i32 = 0xffffff;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0x000000;\n  static readonly obj0LightGrey: i32 = 0x008484;\n  static readonly obj0DarkGrey: i32 = 0xffde00;\n  static readonly obj0Black: i32 = 0xffffff;\n\n  // Obj1\n  static readonly obj1White: i32 = 0x000000;\n  static readonly obj1LightGrey: i32 = 0x008484;\n  static readonly obj1DarkGrey: i32 = 0xffde00;\n  static readonly obj1Black: i32 = 0xffffff;\n}\n\n// Action Button: B + Left\nexport class GrayscaleColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xa5a5a5;\n  static readonly bgDarkGrey: i32 = 0x525252;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xa5a5a5;\n  static readonly obj0DarkGrey: i32 = 0x525252;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xa5a5a5;\n  static readonly obj1DarkGrey: i32 = 0x525252;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: Down\nexport class PastelMixColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffa5;\n  static readonly bgLightGrey: i32 = 0xff9494;\n  static readonly bgDarkGrey: i32 = 0x9494ff;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffa5;\n  static readonly obj0LightGrey: i32 = 0xff9494;\n  static readonly obj0DarkGrey: i32 = 0x9494ff;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffa5;\n  static readonly obj1LightGrey: i32 = 0xff9494;\n  static readonly obj1DarkGrey: i32 = 0x9494ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: B + Up\nexport class DarkBrownColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffe6c5;\n  static readonly bgLightGrey: i32 = 0xce9c84;\n  static readonly bgDarkGrey: i32 = 0x846b29;\n  static readonly bgBlack: i32 = 0x5a3108;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffad63;\n  static readonly obj0DarkGrey: i32 = 0x843100;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffad63;\n  static readonly obj1DarkGrey: i32 = 0x843100;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: A + Right\nexport class DarkGreenColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x7bff31;\n  static readonly bgDarkGrey: i32 = 0x0063c5;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff8484;\n  static readonly obj0DarkGrey: i32 = 0x943a3a;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xff8484;\n  static readonly obj1DarkGrey: i32 = 0x943a3a;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: A + Left\nexport class DarkBlueColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x8c8cde;\n  static readonly bgDarkGrey: i32 = 0x52528c;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff8484;\n  static readonly obj0DarkGrey: i32 = 0x943a3a;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffad63;\n  static readonly obj1DarkGrey: i32 = 0x843100;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: A + Up\nexport class RedColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xff8484;\n  static readonly bgDarkGrey: i32 = 0x943a3a;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x7bff31;\n  static readonly obj0DarkGrey: i32 = 0x008400;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: Left\nexport class BlueColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x63a5ff;\n  static readonly bgDarkGrey: i32 = 0x0000ff;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff8484;\n  static readonly obj0DarkGrey: i32 = 0x943a3a;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x7bff31;\n  static readonly obj1DarkGrey: i32 = 0x008400;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Action Button: B + Down\nexport class YellowColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xffff00;\n  static readonly bgDarkGrey: i32 = 0x7b4a00;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x63a5ff;\n  static readonly obj0DarkGrey: i32 = 0x0000ff;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x7bff31;\n  static readonly obj1DarkGrey: i32 = 0x008400;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Assigned Color Palettes\n\n// Alleyway\nexport class Table00Entry08Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xa59cff;\n  static readonly bgLightGrey: i32 = 0xffff00;\n  static readonly bgDarkGrey: i32 = 0x006300;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xa59cff;\n  static readonly obj0LightGrey: i32 = 0xffff00;\n  static readonly obj0DarkGrey: i32 = 0x006300;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xa59cff;\n  static readonly obj1LightGrey: i32 = 0xffff00;\n  static readonly obj1DarkGrey: i32 = 0x006300;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Pokemon Blue\nexport class Table01Entry0BColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x63a5ff;\n  static readonly bgDarkGrey: i32 = 0x0000ff;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff8484;\n  static readonly obj0DarkGrey: i32 = 0x943a3a;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Pokemon Red\nexport class Table01Entry10Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xff8484;\n  static readonly bgDarkGrey: i32 = 0x943a3a;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x7bff31;\n  static readonly obj0DarkGrey: i32 = 0x008400;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xff8484;\n  static readonly obj1DarkGrey: i32 = 0x943a3a;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Super Mario Land\nexport class Table03Entry0AColors {\n  //Bg\n  static readonly bgWhite: i32 = 0xb5b5ff;\n  static readonly bgLightGrey: i32 = 0xffff94;\n  static readonly bgDarkGrey: i32 = 0xad5a42;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0x000000;\n  static readonly obj0LightGrey: i32 = 0xffffff;\n  static readonly obj0DarkGrey: i32 = 0xff8484;\n  static readonly obj0Black: i32 = 0x943a3a;\n\n  // Obj1\n  static readonly obj1White: i32 = 0x000000;\n  static readonly obj1LightGrey: i32 = 0xffffff;\n  static readonly obj1DarkGrey: i32 = 0xff8484;\n  static readonly obj1Black: i32 = 0x943a3a;\n}\n\n// Super Mario Land 3 - WarioLand\nexport class Table05Entry00Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xadad84;\n  static readonly bgDarkGrey: i32 = 0x42737b;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff7300;\n  static readonly obj0DarkGrey: i32 = 0x944200;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x5abdff;\n  static readonly obj1DarkGrey: i32 = 0xff0000;\n  static readonly obj1Black: i32 = 0x0000ff;\n}\n\n// Donkey Kong\nexport class Table05Entry01Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffff9c;\n  static readonly bgLightGrey: i32 = 0x94b5ff;\n  static readonly bgDarkGrey: i32 = 0x639473;\n  static readonly bgBlack: i32 = 0x003a3a;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffc542;\n  static readonly obj0LightGrey: i32 = 0xffd600;\n  static readonly obj0DarkGrey: i32 = 0x943a00;\n  static readonly obj0Black: i32 = 0x4a0000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xff8484;\n  static readonly obj1DarkGrey: i32 = 0x943a3a;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Tennis\nexport class Table05Entry02Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0x6bff00;\n  static readonly bgLightGrey: i32 = 0xffffff;\n  static readonly bgDarkGrey: i32 = 0xff524a;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffffff;\n  static readonly obj0DarkGrey: i32 = 0x63a5ff;\n  static readonly obj0Black: i32 = 0x0000ff;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0xffad63;\n  static readonly obj1DarkGrey: i32 = 0x843100;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Kirby's Dream Land\nexport class Table05Entry08Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xa59cff;\n  static readonly bgLightGrey: i32 = 0xffff00;\n  static readonly bgDarkGrey: i32 = 0x006300;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xff6352;\n  static readonly obj0LightGrey: i32 = 0xd60000;\n  static readonly obj0DarkGrey: i32 = 0x630000;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0x0000ff;\n  static readonly obj1LightGrey: i32 = 0xffffff;\n  static readonly obj1DarkGrey: i32 = 0xffff7b;\n  static readonly obj1Black: i32 = 0x0084ff;\n}\n\n// Super Mario Land 2 BAYYYBEEE\nexport class Table05Entry09Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffce;\n  static readonly bgLightGrey: i32 = 0x63efef;\n  static readonly bgDarkGrey: i32 = 0x9c8431;\n  static readonly bgBlack: i32 = 0x5a5a5a;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xff7300;\n  static readonly obj0DarkGrey: i32 = 0x944200;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Link's Awakening\nexport class Table05Entry11Colors {\n  // Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xff8484;\n  static readonly bgDarkGrey: i32 = 0x943a3a;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0x00ff00;\n  static readonly obj0DarkGrey: i32 = 0x318400;\n  static readonly obj0Black: i32 = 0x004a00;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// Metroid 2\nexport class Table05Entry14Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0x63a5ff;\n  static readonly bgDarkGrey: i32 = 0x0000ff;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffff00;\n  static readonly obj0LightGrey: i32 = 0xff0000;\n  static readonly obj0DarkGrey: i32 = 0x630000;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x7bff31;\n  static readonly obj1DarkGrey: i32 = 0x008400;\n  static readonly obj1Black: i32 = 0x000000;\n}\n\n// WarioLand 2\nexport class Table05Entry15Colors {\n  //Bg\n  static readonly bgWhite: i32 = 0xffffff;\n  static readonly bgLightGrey: i32 = 0xadad84;\n  static readonly bgDarkGrey: i32 = 0x42737b;\n  static readonly bgBlack: i32 = 0x000000;\n\n  // Obj 0\n  static readonly obj0White: i32 = 0xffffff;\n  static readonly obj0LightGrey: i32 = 0xffad63;\n  static readonly obj0DarkGrey: i32 = 0xffad63;\n  static readonly obj0Black: i32 = 0x000000;\n\n  // Obj1\n  static readonly obj1White: i32 = 0xffffff;\n  static readonly obj1LightGrey: i32 = 0x63a5ff;\n  static readonly obj1DarkGrey: i32 = 0x0000ff;\n  static readonly obj1Black: i32 = 0x000000;\n}\n","// File for all of the logic of setting gameboy color plaettes\n\nimport {\n  WasmBoyGBColors,\n  BrownColors,\n  RedColors,\n  DarkBrownColors,\n  GreenColors,\n  DarkGreenColors,\n  InvertedColors,\n  PastelMixColors,\n  OrangeColors,\n  YellowColors,\n  BlueColors,\n  DarkBlueColors,\n  GrayscaleColors,\n  Table00Entry08Colors,\n  Table01Entry0BColors,\n  Table01Entry10Colors,\n  Table03Entry0AColors,\n  Table05Entry00Colors,\n  Table05Entry01Colors,\n  Table05Entry02Colors,\n  Table05Entry08Colors,\n  Table05Entry09Colors,\n  Table05Entry11Colors,\n  Table05Entry14Colors,\n  Table05Entry15Colors\n} from './colors.constants';\nimport { Cpu } from '../cpu/cpu';\nimport { eightBitLoadFromGBMemory } from '../memory/index';\n\n// Current / exported color\nexport class Colors {\n  //Bg\n  static bgWhite: i32 = WasmBoyGBColors.bgWhite;\n  static bgLightGrey: i32 = WasmBoyGBColors.bgLightGrey;\n  static bgDarkGrey: i32 = WasmBoyGBColors.bgDarkGrey;\n  static bgBlack: i32 = WasmBoyGBColors.bgBlack;\n\n  // Obj 0\n  static obj0White: i32 = WasmBoyGBColors.obj0White;\n  static obj0LightGrey: i32 = WasmBoyGBColors.obj0LightGrey;\n  static obj0DarkGrey: i32 = WasmBoyGBColors.obj0DarkGrey;\n  static obj0Black: i32 = WasmBoyGBColors.obj0Black;\n\n  // Obj1\n  static obj1White: i32 = WasmBoyGBColors.obj1White;\n  static obj1LightGrey: i32 = WasmBoyGBColors.obj1LightGrey;\n  static obj1DarkGrey: i32 = WasmBoyGBColors.obj1DarkGrey;\n  static obj1Black: i32 = WasmBoyGBColors.obj1Black;\n}\n\n// Inlined because closure compiler inlines\nexport function initializeColors(): void {\n  setManualColorizationPalette(0);\n\n  if (Cpu.GBCEnabled) {\n    // Don't need to continue this if a GBC game\n    return;\n  }\n\n  if (Cpu.BootROMEnabled) {\n    if (!Cpu.GBCEnabled) {\n      // GB\n      return;\n    }\n  }\n\n  // Do some automatic color palette swapping if we have a loaded ROM\n  let titleChecksum: i32 = 0x00;\n  for (let i: i32 = 0x0134; i <= 0x0143; i++) {\n    titleChecksum += eightBitLoadFromGBMemory(i);\n  }\n\n  // Set the colorization for the game automatically if assigned\n  // https://tcrf.net/Notes:Game_Boy_Color_Bootstrap_ROM\n  let hash: i32 = titleChecksum & 0xff;\n  setHashColorizationPalette(hash);\n}\n\nexport function getRedFromHexColor(color: i32): i32 {\n  return (color & 0xff0000) >> 16;\n}\n\nexport function getGreenFromHexColor(color: i32): i32 {\n  return (color & 0x00ff00) >> 8;\n}\n\nexport function getBlueFromHexColor(color: i32): i32 {\n  return color & 0x0000ff;\n}\n\n// Function to set the colorization\n// By manually pressing buttons\nexport function setManualColorizationPalette(colorizationId: i32): void {\n  // Set the colorizationId clockwise according to:\n  // https://en.wikipedia.org/wiki/Game_Boy_Color\n  switch (colorizationId) {\n    case 0:\n      Colors.bgWhite = WasmBoyGBColors.bgWhite;\n      Colors.bgLightGrey = WasmBoyGBColors.bgLightGrey;\n      Colors.bgDarkGrey = WasmBoyGBColors.bgDarkGrey;\n      Colors.bgBlack = WasmBoyGBColors.bgBlack;\n\n      Colors.obj0White = WasmBoyGBColors.obj0White;\n      Colors.obj0LightGrey = WasmBoyGBColors.obj0LightGrey;\n      Colors.obj0DarkGrey = WasmBoyGBColors.obj0DarkGrey;\n      Colors.obj0Black = WasmBoyGBColors.obj0Black;\n\n      Colors.obj1White = WasmBoyGBColors.obj1White;\n      Colors.obj1LightGrey = WasmBoyGBColors.obj1LightGrey;\n      Colors.obj1DarkGrey = WasmBoyGBColors.obj1DarkGrey;\n      Colors.obj1Black = WasmBoyGBColors.obj1Black;\n      break;\n    case 1:\n      // Up, Brown\n      Colors.bgWhite = BrownColors.bgWhite;\n      Colors.bgLightGrey = BrownColors.bgLightGrey;\n      Colors.bgDarkGrey = BrownColors.bgDarkGrey;\n      Colors.bgBlack = BrownColors.bgBlack;\n\n      Colors.obj0White = BrownColors.obj0White;\n      Colors.obj0LightGrey = BrownColors.obj0LightGrey;\n      Colors.obj0DarkGrey = BrownColors.obj0DarkGrey;\n      Colors.obj0Black = BrownColors.obj0Black;\n\n      Colors.obj1White = BrownColors.obj1White;\n      Colors.obj1LightGrey = BrownColors.obj1LightGrey;\n      Colors.obj1DarkGrey = BrownColors.obj1DarkGrey;\n      Colors.obj1Black = BrownColors.obj1Black;\n      break;\n    case 2:\n      // Up + A, Red\n      Colors.bgWhite = RedColors.bgWhite;\n      Colors.bgLightGrey = RedColors.bgLightGrey;\n      Colors.bgDarkGrey = RedColors.bgDarkGrey;\n      Colors.bgBlack = RedColors.bgBlack;\n\n      Colors.obj0White = RedColors.obj0White;\n      Colors.obj0LightGrey = RedColors.obj0LightGrey;\n      Colors.obj0DarkGrey = RedColors.obj0DarkGrey;\n      Colors.obj0Black = RedColors.obj0Black;\n\n      Colors.obj1White = RedColors.obj1White;\n      Colors.obj1LightGrey = RedColors.obj1LightGrey;\n      Colors.obj1DarkGrey = RedColors.obj1DarkGrey;\n      Colors.obj1Black = RedColors.obj1Black;\n      break;\n    case 3:\n      // Up + B, DarkBrown\n      Colors.bgWhite = DarkBrownColors.bgWhite;\n      Colors.bgLightGrey = DarkBrownColors.bgLightGrey;\n      Colors.bgDarkGrey = DarkBrownColors.bgDarkGrey;\n      Colors.bgBlack = DarkBrownColors.bgBlack;\n\n      Colors.obj0White = DarkBrownColors.obj0White;\n      Colors.obj0LightGrey = DarkBrownColors.obj0LightGrey;\n      Colors.obj0DarkGrey = DarkBrownColors.obj0DarkGrey;\n      Colors.obj0Black = DarkBrownColors.obj0Black;\n\n      Colors.obj1White = DarkBrownColors.obj1White;\n      Colors.obj1LightGrey = DarkBrownColors.obj1LightGrey;\n      Colors.obj1DarkGrey = DarkBrownColors.obj1DarkGrey;\n      Colors.obj1Black = DarkBrownColors.obj1Black;\n      break;\n    case 4:\n      // Right, Green\n      Colors.bgWhite = GreenColors.bgWhite;\n      Colors.bgLightGrey = GreenColors.bgLightGrey;\n      Colors.bgDarkGrey = GreenColors.bgDarkGrey;\n      Colors.bgBlack = GreenColors.bgBlack;\n\n      Colors.obj0White = GreenColors.obj0White;\n      Colors.obj0LightGrey = GreenColors.obj0LightGrey;\n      Colors.obj0DarkGrey = GreenColors.obj0DarkGrey;\n      Colors.obj0Black = GreenColors.obj0Black;\n\n      Colors.obj1White = GreenColors.obj1White;\n      Colors.obj1LightGrey = GreenColors.obj1LightGrey;\n      Colors.obj1DarkGrey = GreenColors.obj1DarkGrey;\n      Colors.obj1Black = GreenColors.obj1Black;\n      break;\n    case 5:\n      // Right + A, DarkGreenColors\n      Colors.bgWhite = DarkGreenColors.bgWhite;\n      Colors.bgLightGrey = DarkGreenColors.bgLightGrey;\n      Colors.bgDarkGrey = DarkGreenColors.bgDarkGrey;\n      Colors.bgBlack = DarkGreenColors.bgBlack;\n\n      Colors.obj0White = DarkGreenColors.obj0White;\n      Colors.obj0LightGrey = DarkGreenColors.obj0LightGrey;\n      Colors.obj0DarkGrey = DarkGreenColors.obj0DarkGrey;\n      Colors.obj0Black = DarkGreenColors.obj0Black;\n\n      Colors.obj1White = DarkGreenColors.obj1White;\n      Colors.obj1LightGrey = DarkGreenColors.obj1LightGrey;\n      Colors.obj1DarkGrey = DarkGreenColors.obj1DarkGrey;\n      Colors.obj1Black = DarkGreenColors.obj1Black;\n      break;\n    case 6:\n      // Right + B, InvertedColors\n      Colors.bgWhite = InvertedColors.bgWhite;\n      Colors.bgLightGrey = InvertedColors.bgLightGrey;\n      Colors.bgDarkGrey = InvertedColors.bgDarkGrey;\n      Colors.bgBlack = InvertedColors.bgBlack;\n\n      Colors.obj0White = InvertedColors.obj0White;\n      Colors.obj0LightGrey = InvertedColors.obj0LightGrey;\n      Colors.obj0DarkGrey = InvertedColors.obj0DarkGrey;\n      Colors.obj0Black = InvertedColors.obj0Black;\n\n      Colors.obj1White = InvertedColors.obj1White;\n      Colors.obj1LightGrey = InvertedColors.obj1LightGrey;\n      Colors.obj1DarkGrey = InvertedColors.obj1DarkGrey;\n      Colors.obj1Black = InvertedColors.obj1Black;\n      break;\n    case 7:\n      // Down, PastelMixColors\n      Colors.bgWhite = PastelMixColors.bgWhite;\n      Colors.bgLightGrey = PastelMixColors.bgLightGrey;\n      Colors.bgDarkGrey = PastelMixColors.bgDarkGrey;\n      Colors.bgBlack = PastelMixColors.bgBlack;\n\n      Colors.obj0White = PastelMixColors.obj0White;\n      Colors.obj0LightGrey = PastelMixColors.obj0LightGrey;\n      Colors.obj0DarkGrey = PastelMixColors.obj0DarkGrey;\n      Colors.obj0Black = PastelMixColors.obj0Black;\n\n      Colors.obj1White = PastelMixColors.obj1White;\n      Colors.obj1LightGrey = PastelMixColors.obj1LightGrey;\n      Colors.obj1DarkGrey = PastelMixColors.obj1DarkGrey;\n      Colors.obj1Black = PastelMixColors.obj1Black;\n      break;\n    case 8:\n      // Down + A, Orange\n      Colors.bgWhite = OrangeColors.bgWhite;\n      Colors.bgLightGrey = OrangeColors.bgLightGrey;\n      Colors.bgDarkGrey = OrangeColors.bgDarkGrey;\n      Colors.bgBlack = OrangeColors.bgBlack;\n\n      Colors.obj0White = OrangeColors.obj0White;\n      Colors.obj0LightGrey = OrangeColors.obj0LightGrey;\n      Colors.obj0DarkGrey = OrangeColors.obj0DarkGrey;\n      Colors.obj0Black = OrangeColors.obj0Black;\n\n      Colors.obj1White = OrangeColors.obj1White;\n      Colors.obj1LightGrey = OrangeColors.obj1LightGrey;\n      Colors.obj1DarkGrey = OrangeColors.obj1DarkGrey;\n      Colors.obj1Black = OrangeColors.obj1Black;\n      break;\n    case 9:\n      // Down + B, Yellow\n      Colors.bgWhite = YellowColors.bgWhite;\n      Colors.bgLightGrey = YellowColors.bgLightGrey;\n      Colors.bgDarkGrey = YellowColors.bgDarkGrey;\n      Colors.bgBlack = YellowColors.bgBlack;\n\n      Colors.obj0White = YellowColors.obj0White;\n      Colors.obj0LightGrey = YellowColors.obj0LightGrey;\n      Colors.obj0DarkGrey = YellowColors.obj0DarkGrey;\n      Colors.obj0Black = YellowColors.obj0Black;\n\n      Colors.obj1White = YellowColors.obj1White;\n      Colors.obj1LightGrey = YellowColors.obj1LightGrey;\n      Colors.obj1DarkGrey = YellowColors.obj1DarkGrey;\n      Colors.obj1Black = YellowColors.obj1Black;\n      break;\n    case 10:\n      // Left, Blue\n      Colors.bgWhite = BlueColors.bgWhite;\n      Colors.bgLightGrey = BlueColors.bgLightGrey;\n      Colors.bgDarkGrey = BlueColors.bgDarkGrey;\n      Colors.bgBlack = BlueColors.bgBlack;\n\n      Colors.obj0White = BlueColors.obj0White;\n      Colors.obj0LightGrey = BlueColors.obj0LightGrey;\n      Colors.obj0DarkGrey = BlueColors.obj0DarkGrey;\n      Colors.obj0Black = BlueColors.obj0Black;\n\n      Colors.obj1White = BlueColors.obj1White;\n      Colors.obj1LightGrey = BlueColors.obj1LightGrey;\n      Colors.obj1DarkGrey = BlueColors.obj1DarkGrey;\n      Colors.obj1Black = BlueColors.obj1Black;\n      break;\n    case 11:\n      // Left + A, Dark Blue\n      Colors.bgWhite = DarkBlueColors.bgWhite;\n      Colors.bgLightGrey = DarkBlueColors.bgLightGrey;\n      Colors.bgDarkGrey = DarkBlueColors.bgDarkGrey;\n      Colors.bgBlack = DarkBlueColors.bgBlack;\n\n      Colors.obj0White = DarkBlueColors.obj0White;\n      Colors.obj0LightGrey = DarkBlueColors.obj0LightGrey;\n      Colors.obj0DarkGrey = DarkBlueColors.obj0DarkGrey;\n      Colors.obj0Black = DarkBlueColors.obj0Black;\n\n      Colors.obj1White = DarkBlueColors.obj1White;\n      Colors.obj1LightGrey = DarkBlueColors.obj1LightGrey;\n      Colors.obj1DarkGrey = DarkBlueColors.obj1DarkGrey;\n      Colors.obj1Black = DarkBlueColors.obj1Black;\n      break;\n    case 12:\n      // Left + B, GrayScale\n      Colors.bgWhite = GrayscaleColors.bgWhite;\n      Colors.bgLightGrey = GrayscaleColors.bgLightGrey;\n      Colors.bgDarkGrey = GrayscaleColors.bgDarkGrey;\n      Colors.bgBlack = GrayscaleColors.bgBlack;\n\n      Colors.obj0White = GrayscaleColors.obj0White;\n      Colors.obj0LightGrey = GrayscaleColors.obj0LightGrey;\n      Colors.obj0DarkGrey = GrayscaleColors.obj0DarkGrey;\n      Colors.obj0Black = GrayscaleColors.obj0Black;\n\n      Colors.obj1White = GrayscaleColors.obj1White;\n      Colors.obj1LightGrey = GrayscaleColors.obj1LightGrey;\n      Colors.obj1DarkGrey = GrayscaleColors.obj1DarkGrey;\n      Colors.obj1Black = GrayscaleColors.obj1Black;\n      break;\n  }\n}\n\n// Function to set the colorization\n// By checksum of the title\n// https://forums.nesdev.com/viewtopic.php?f=20&t=10226\n// TODO: torch2424 need to find how to get the \"disambiguation\"\n// Inlined because closure compiler inlines\nexport function setHashColorizationPalette(hash: i32): void {\n  switch (hash) {\n    case 0x88:\n      Colors.bgWhite = Table00Entry08Colors.bgWhite;\n      Colors.bgLightGrey = Table00Entry08Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table00Entry08Colors.bgDarkGrey;\n      Colors.bgBlack = Table00Entry08Colors.bgBlack;\n\n      Colors.obj0White = Table00Entry08Colors.obj0White;\n      Colors.obj0LightGrey = Table00Entry08Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table00Entry08Colors.obj0DarkGrey;\n      Colors.obj0Black = Table00Entry08Colors.obj0Black;\n\n      Colors.obj1White = Table00Entry08Colors.obj1White;\n      Colors.obj1LightGrey = Table00Entry08Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table00Entry08Colors.obj1DarkGrey;\n      Colors.obj1Black = Table00Entry08Colors.obj1Black;\n      break;\n    case 0x61:\n      Colors.bgWhite = Table01Entry0BColors.bgWhite;\n      Colors.bgLightGrey = Table01Entry0BColors.bgLightGrey;\n      Colors.bgDarkGrey = Table01Entry0BColors.bgDarkGrey;\n      Colors.bgBlack = Table01Entry0BColors.bgBlack;\n\n      Colors.obj0White = Table01Entry0BColors.obj0White;\n      Colors.obj0LightGrey = Table01Entry0BColors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table01Entry0BColors.obj0DarkGrey;\n      Colors.obj0Black = Table01Entry0BColors.obj0Black;\n\n      Colors.obj1White = Table01Entry0BColors.obj1White;\n      Colors.obj1LightGrey = Table01Entry0BColors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table01Entry0BColors.obj1DarkGrey;\n      Colors.obj1Black = Table01Entry0BColors.obj1Black;\n      break;\n    case 0x14:\n      Colors.bgWhite = Table01Entry10Colors.bgWhite;\n      Colors.bgLightGrey = Table01Entry10Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table01Entry10Colors.bgDarkGrey;\n      Colors.bgBlack = Table01Entry10Colors.bgBlack;\n\n      Colors.obj0White = Table01Entry10Colors.obj0White;\n      Colors.obj0LightGrey = Table01Entry10Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table01Entry10Colors.obj0DarkGrey;\n      Colors.obj0Black = Table01Entry10Colors.obj0Black;\n\n      Colors.obj1White = Table01Entry10Colors.obj1White;\n      Colors.obj1LightGrey = Table01Entry10Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table01Entry10Colors.obj1DarkGrey;\n      Colors.obj1Black = Table01Entry10Colors.obj1Black;\n      break;\n    case 0x46:\n      Colors.bgWhite = Table03Entry0AColors.bgWhite;\n      Colors.bgLightGrey = Table03Entry0AColors.bgLightGrey;\n      Colors.bgDarkGrey = Table03Entry0AColors.bgDarkGrey;\n      Colors.bgBlack = Table03Entry0AColors.bgBlack;\n\n      Colors.obj0White = Table03Entry0AColors.obj0White;\n      Colors.obj0LightGrey = Table03Entry0AColors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table03Entry0AColors.obj0DarkGrey;\n      Colors.obj0Black = Table03Entry0AColors.obj0Black;\n\n      Colors.obj1White = Table03Entry0AColors.obj1White;\n      Colors.obj1LightGrey = Table03Entry0AColors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table03Entry0AColors.obj1DarkGrey;\n      Colors.obj1Black = Table03Entry0AColors.obj1Black;\n      break;\n    case 0x59:\n    case 0xc6:\n      Colors.bgWhite = Table05Entry00Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry00Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry00Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry00Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry00Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry00Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry00Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry00Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry00Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry00Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry00Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry00Colors.obj1Black;\n      break;\n    case 0x86:\n    case 0xa8:\n      Colors.bgWhite = Table05Entry01Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry01Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry01Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry01Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry01Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry01Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry01Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry01Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry01Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry01Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry01Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry01Colors.obj1Black;\n      break;\n    case 0xbf:\n    case 0xce:\n    case 0xd1:\n    case 0xf0:\n      Colors.bgWhite = Table05Entry02Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry02Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry02Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry02Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry02Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry02Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry02Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry02Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry02Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry02Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry02Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry02Colors.obj1Black;\n      break;\n    case 0x27:\n    case 0x49:\n    case 0x5c:\n    case 0xb3:\n      Colors.bgWhite = Table05Entry08Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry08Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry08Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry08Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry08Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry08Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry08Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry08Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry08Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry08Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry08Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry08Colors.obj1Black;\n      break;\n    case 0xc9:\n      Colors.bgWhite = Table05Entry09Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry09Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry09Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry09Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry09Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry09Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry09Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry09Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry09Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry09Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry09Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry09Colors.obj1Black;\n      break;\n    case 0x70:\n      Colors.bgWhite = Table05Entry11Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry11Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry11Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry11Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry11Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry11Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry11Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry11Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry11Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry11Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry11Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry11Colors.obj1Black;\n      break;\n    case 0x46:\n      Colors.bgWhite = Table05Entry14Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry14Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry14Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry14Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry14Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry14Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry14Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry14Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry14Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry14Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry14Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry14Colors.obj1Black;\n      break;\n    case 0xd3:\n      Colors.bgWhite = Table05Entry15Colors.bgWhite;\n      Colors.bgLightGrey = Table05Entry15Colors.bgLightGrey;\n      Colors.bgDarkGrey = Table05Entry15Colors.bgDarkGrey;\n      Colors.bgBlack = Table05Entry15Colors.bgBlack;\n\n      Colors.obj0White = Table05Entry15Colors.obj0White;\n      Colors.obj0LightGrey = Table05Entry15Colors.obj0LightGrey;\n      Colors.obj0DarkGrey = Table05Entry15Colors.obj0DarkGrey;\n      Colors.obj0Black = Table05Entry15Colors.obj0Black;\n\n      Colors.obj1White = Table05Entry15Colors.obj1White;\n      Colors.obj1LightGrey = Table05Entry15Colors.obj1LightGrey;\n      Colors.obj1DarkGrey = Table05Entry15Colors.obj1DarkGrey;\n      Colors.obj1Black = Table05Entry15Colors.obj1Black;\n      break;\n  }\n}\n","import { GBC_PALETTE_LOCATION } from '../constants';\nimport { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory, eightBitStoreIntoGBMemory } from '../memory/index';\nimport { checkBitOnByte, resetBitOnByte, setBitOnByte, concatenateBytes } from '../helpers/index';\n\nimport { Colors } from './colors';\n\n// Class for GBC Color palletes\n// http://gbdev.gg8.se/wiki/articles/Video_Display#FF68_-_BCPS.2FBGPI_-_CGB_Mode_Only_-_Background_Palette_Index\nexport class Palette {\n  static memoryLocationBackgroundPaletteIndex: i32 = 0xff68;\n  static memoryLocationBackgroundPaletteData: i32 = 0xff69;\n  static memoryLocationSpritePaletteIndex: i32 = 0xff6a;\n  static memoryLocationSpritePaletteData: i32 = 0xff6b;\n\n  // Palettes\n  static readonly memoryLocationBackgroundPalette: i32 = 0xff47;\n  static readonly memoryLocationSpritePaletteOne: i32 = 0xff48;\n  static readonly memoryLocationSpritePaletteTwo: i32 = 0xff49;\n}\n\n// Inlined because closure compiler inlines\nexport function initializePalette(): void {\n  if (Cpu.GBCEnabled) {\n    // GBC Palettes\n    eightBitStoreIntoGBMemory(0xff68, 0xc0);\n    eightBitStoreIntoGBMemory(0xff69, 0xff);\n    eightBitStoreIntoGBMemory(0xff6a, 0xc1);\n    eightBitStoreIntoGBMemory(0xff6b, 0x0d);\n  } else {\n    // GBC Palettes\n    eightBitStoreIntoGBMemory(0xff68, 0xff);\n    eightBitStoreIntoGBMemory(0xff69, 0xff);\n    eightBitStoreIntoGBMemory(0xff6a, 0xff);\n    eightBitStoreIntoGBMemory(0xff6b, 0xff);\n  }\n\n  // Override some values if using the bootrom\n  if (Cpu.BootROMEnabled && Cpu.GBCEnabled) {\n    // GBC Palettes\n    eightBitStoreIntoGBMemory(0xff69, 0x20);\n    eightBitStoreIntoGBMemory(0xff6b, 0x8a);\n  }\n}\n\n// Simple get pallete color or monochrome GB\n// shouldRepresentColorByColorId is good for debugging tile data for GBC games that don't have\n// monochromePalettes\n// Inlined because closure compiler inlines\nexport function getMonochromeColorFromPalette(\n  colorId: i32,\n  paletteMemoryLocation: i32,\n  shouldRepresentColorByColorId: boolean = false\n): i32 {\n  // Shift our paletteByte, 2 times for each color ID\n  // And off any extra bytes\n  // Return our Color (00 - white, 01 - light grey, 10 Dark grey, or 11 - Black)\n  let color = colorId;\n  if (!shouldRepresentColorByColorId) {\n    color = ((<i32>eightBitLoadFromGBMemory(paletteMemoryLocation)) >> (colorId << 1)) & 0x03;\n  }\n\n  // Since our max is 254, and max is 3.\n  // monochrome color palette is modified from bgb\n  // TODO: Make these colors into a constant\n  let rgbColor = 242;\n\n  switch (color) {\n    case 0:\n      break;\n    case 1:\n      rgbColor = 160;\n      break;\n    case 2:\n      rgbColor = 88;\n      break;\n    case 3:\n      rgbColor = 8;\n      break;\n  }\n\n  return rgbColor;\n}\n\n// Function to returns the Colorized color for a GB games\nexport function getColorizedGbHexColorFromPalette(colorId: i32, paletteMemoryLocation: i32): i32 {\n  // Shift our paletteByte, 2 times for each color ID\n  // And off any extra bytes\n  // Return our Color (00 - white, 01 - light grey, 10 Dark grey, or 11 - Black)\n  let color = ((<i32>eightBitLoadFromGBMemory(paletteMemoryLocation)) >> (colorId * 2)) & 0x03;\n\n  // Check which palette we got, to apply the right color layer\n  let hexColor = 0;\n  if (paletteMemoryLocation === Palette.memoryLocationSpritePaletteOne) {\n    hexColor = Colors.obj0White;\n\n    switch (color) {\n      case 0:\n        break;\n      case 1:\n        hexColor = Colors.obj0LightGrey;\n        break;\n      case 2:\n        hexColor = Colors.obj0DarkGrey;\n        break;\n      case 3:\n        hexColor = Colors.obj0Black;\n        break;\n    }\n  } else if (paletteMemoryLocation === Palette.memoryLocationSpritePaletteTwo) {\n    hexColor = Colors.obj1White;\n\n    switch (color) {\n      case 0:\n        break;\n      case 1:\n        hexColor = Colors.obj1LightGrey;\n        break;\n      case 2:\n        hexColor = Colors.obj1DarkGrey;\n        break;\n      case 3:\n        hexColor = Colors.obj1Black;\n        break;\n    }\n  } else {\n    hexColor = Colors.bgWhite;\n\n    switch (color) {\n      case 0:\n        break;\n      case 1:\n        hexColor = Colors.bgLightGrey;\n        break;\n      case 2:\n        hexColor = Colors.bgDarkGrey;\n        break;\n      case 3:\n        hexColor = Colors.bgBlack;\n        break;\n    }\n  }\n\n  return hexColor;\n}\n\n// Inlined because closure compiler inlines\nexport function writeColorPaletteToMemory(offset: i32, value: i32): void {\n  // FF68\n  //  Bit 0-5   Index (00-3F)\n  let memoryLocationSpritePaletteData = Palette.memoryLocationSpritePaletteData;\n  if (offset === Palette.memoryLocationBackgroundPaletteData || offset === memoryLocationSpritePaletteData) {\n    // Get the palette index\n    let paletteIndex: i32 = eightBitLoadFromGBMemory(offset - 1);\n\n    // Clear the 6th bit, as it does nothing\n    paletteIndex = resetBitOnByte(6, paletteIndex);\n\n    // Check if we are changing the sprite pallete data\n    let isSprite = offset === memoryLocationSpritePaletteData;\n    storePaletteByteInWasmMemory(paletteIndex, value, isSprite);\n    incrementPaletteIndexIfSet(paletteIndex, offset - 1);\n  }\n}\n\n// Functions to Handle Write to pallete data registers\n// http://gbdev.gg8.se/wiki/articles/Video_Display#FF68_-_BCPS.2FBGPI_-_CGB_Mode_Only_-_Background_Palette_Index\n// Function to handle incrementing the pallete index if required\n// Inlined because closure compiler inlines\nfunction incrementPaletteIndexIfSet(paletteIndex: i32, offset: i32): void {\n  // Check ther auto increment box\n  if (checkBitOnByte(7, paletteIndex)) {\n    // Increment the index, and return the value before the increment\n    // Ensure we don't ouverflow our auto increment bit\n    paletteIndex += 1;\n    paletteIndex = setBitOnByte(7, paletteIndex);\n\n    eightBitStoreIntoGBMemory(offset, paletteIndex);\n  }\n}\n\n// FF68\n// Bit 0-5   Index (00-3F)\n// Bit 7     Auto Increment  (0=Disabled, 1=Increment after Writing)\n// Index is 00-0x3F because the means 0 - 63 (64),\n// and apparently there are 8 bytes per pallete to describe Color 0-3 (4 colors),\n// and 0-7 (8 palltetes). Therefore, 64!\nexport function getRgbColorFromPalette(paletteId: i32, colorId: i32, isSprite: boolean): i32 {\n  // Each Pallete takes 8 bytes, so multiply by 8 to get the pallete\n  // And Each color takes 2 bytes, therefore, multiple by 2 for the correct color bytes in the palette\n  let paletteIndex = paletteId * 8 + colorId * 2;\n\n  // Load the Color that is seperated into two bytes\n  let paletteHighByte: i32 = loadPaletteByteFromWasmMemory(paletteIndex + 1, isSprite);\n  let paletteLowByte: i32 = loadPaletteByteFromWasmMemory(paletteIndex, isSprite);\n\n  // Return the concatenated color byte\n  return <i32>concatenateBytes(paletteHighByte, paletteLowByte);\n}\n\n// Function to return the color from a passed 16 bit color pallette\nexport function getColorComponentFromRgb(colorId: i32, colorRgb: i32): i32 {\n  // Get our bitmask for the color ID\n  // bit mask tested good :)\n  colorId *= 5;\n  let bitMask = 0x1f << colorId;\n  let colorValue = (colorRgb & bitMask) >> colorId;\n\n  // Goal is to reach 254 for each color, so 255 / 31 (0x1F) ~8 TODO: Make exact\n  // Want 5 bits for each\n  return colorValue * 8;\n}\n\n// Function to load a byte from our Gbc Palette memory\nexport function loadPaletteByteFromWasmMemory(paletteIndexByte: i32, isSprite: boolean): u8 {\n  // Clear the top two bits to just get the bottom palette Index\n  let paletteIndex = paletteIndexByte & 0x3f;\n\n  // Move over the palette index to not overlap the background has 0x3F, so Zero for Sprites is 0x40)\n  if (isSprite) {\n    paletteIndex += 0x40;\n  }\n\n  return load<u8>(GBC_PALETTE_LOCATION + paletteIndex);\n}\n\n// Function to store a byte to our Gbc Palette memory\n// Inlined because closure compiler inlines\nexport function storePaletteByteInWasmMemory(paletteIndexByte: i32, value: i32, isSprite: boolean): void {\n  // Clear the top two bits to just get the bottom palette Index\n  let paletteIndex = paletteIndexByte & 0x3f;\n\n  // Move over the palette index to not overlap the background (has 0x3F, so Zero for Sprites is 0x40)\n  if (isSprite) {\n    paletteIndex += 0x40;\n  }\n\n  store<u8>(GBC_PALETTE_LOCATION + paletteIndex, <u8>value);\n}\n","// Functions for performance hacks, and debugging tiles\n\nimport { Cpu } from '../cpu/index';\nimport { Graphics, loadFromVramBank } from './graphics';\nimport {\n  getMonochromeColorFromPalette,\n  getColorizedGbHexColorFromPalette,\n  getRgbColorFromPalette,\n  getColorComponentFromRgb\n} from './palette';\nimport { getRedFromHexColor, getGreenFromHexColor, getBlueFromHexColor } from './colors';\nimport { addPriorityforPixel } from './priority';\n// Assembly script really not feeling the reexport\n// using Skip Traps, because LCD has unrestricted access\n// http://gbdev.gg8.se/wiki/articles/Video_Display#LCD_OAM_DMA_Transfers\nimport { checkBitOnByte } from '../helpers/index';\nimport { i8Portable } from '../portable/portable';\n\nexport class TileCache {\n  static tileId: i32 = -1;\n  static horizontalFlip: boolean = false;\n  static nextXIndexToPerformCacheCheck: i32 = -1;\n}\n\n// Inlined because closure compiler inlines\nexport function resetTileCache(): void {\n  TileCache.tileId = -1;\n  TileCache.nextXIndexToPerformCacheCheck = -1;\n}\n\nexport function drawPixelsFromLineOfTile(\n  tileId: i32,\n  tileDataMemoryLocation: i32,\n  vramBankId: i32,\n  tileLineXStart: i32,\n  tileLineXEnd: i32,\n  tileLineY: i32,\n  outputLineX: i32,\n  outputLineY: i32,\n  outputWidth: i32,\n  wasmMemoryStart: i32,\n  shouldRepresentMonochromeColorByColorId: boolean,\n  paletteLocation: i32,\n  bgMapAttributes: i32,\n  spriteAttributes: i32\n): i32 {\n  // Get our number of pixels drawn\n  let pixelsDrawn = 0;\n\n  // Get our tile data address\n  let tileDataAddress = getTileDataAddress(tileDataMemoryLocation, tileId);\n\n  // Get the bytes for our tile\n  let byteOneForLineOfTilePixels = loadFromVramBank(tileDataAddress + tileLineY * 2, vramBankId);\n  let byteTwoForLineOfTilePixels = loadFromVramBank(tileDataAddress + tileLineY * 2 + 1, vramBankId);\n\n  // Loop through our X values to draw\n  for (let x = tileLineXStart; x <= tileLineXEnd; ++x) {\n    // First find where we are going to do our final output x\n    // And don't allow any width overflow\n    let iteratedOutputX = outputLineX + (x - tileLineXStart);\n    if (iteratedOutputX < outputWidth) {\n      // However, We need to reverse our byte (if not horizontally flipped),\n      // As pixel 0 is on byte 7, and pixel 1 is on byte 6, etc...\n      // Therefore, is pixelX was 2, then really is need to be 5\n      // So 2 - 7 = -5, * 1 = 5\n      // Or to simplify, 7 - 2 = 5 haha!\n      let pixelXInTile = x;\n      if (bgMapAttributes < 0 || !checkBitOnByte(5, bgMapAttributes)) {\n        pixelXInTile = 7 - pixelXInTile;\n      }\n\n      // Get our pallete colors for the tile\n      let paletteColorId = 0;\n      if (checkBitOnByte(pixelXInTile, byteTwoForLineOfTilePixels)) {\n        // Byte one represents the second bit in our color id, so bit shift\n        paletteColorId += 1;\n        paletteColorId = paletteColorId << 1;\n      }\n      if (checkBitOnByte(pixelXInTile, byteOneForLineOfTilePixels)) {\n        paletteColorId += 1;\n      }\n\n      // Get the pallete\n      let red = 0;\n      let green = 0;\n      let blue = 0;\n\n      // Check if we should draw color or not\n      if (Cpu.GBCEnabled && (bgMapAttributes >= 0 || spriteAttributes >= 0)) {\n        // Draw C O L O R\n\n        let isSprite = spriteAttributes >= 0;\n\n        // Call the helper function to grab the correct color from the palette\n        // Get the palette index byte\n        let bgPalette = bgMapAttributes & 0x07;\n        if (isSprite) {\n          bgPalette = spriteAttributes & 0x07;\n        }\n        let rgbColorPalette = getRgbColorFromPalette(bgPalette, paletteColorId, isSprite);\n\n        // Split off into red green and blue\n        red = getColorComponentFromRgb(0, rgbColorPalette);\n        green = getColorComponentFromRgb(1, rgbColorPalette);\n        blue = getColorComponentFromRgb(2, rgbColorPalette);\n      } else {\n        // Draw Monochrome\n\n        // Get the default palette if none\n        if (paletteLocation <= 0) {\n          paletteLocation = Graphics.memoryLocationBackgroundPalette;\n        }\n\n        if (shouldRepresentMonochromeColorByColorId) {\n          let monochromeColor = getMonochromeColorFromPalette(paletteColorId, paletteLocation, shouldRepresentMonochromeColorByColorId);\n          red = monochromeColor;\n          green = monochromeColor;\n          blue = monochromeColor;\n        } else {\n          let hexColor = getColorizedGbHexColorFromPalette(paletteColorId, paletteLocation);\n          red = getRedFromHexColor(hexColor);\n          green = getGreenFromHexColor(hexColor);\n          blue = getBlueFromHexColor(hexColor);\n        }\n      }\n\n      // Finally Lets place a pixel in memory\n      // Find where our tile line would start\n      let pixelStart = getTilePixelStart(iteratedOutputX, outputLineY, outputWidth);\n\n      // Can not optimize wasmMemoryStart any further, as this is in a loop.\n      store<u8>(wasmMemoryStart + pixelStart + 0, <u8>red);\n      store<u8>(wasmMemoryStart + pixelStart + 1, <u8>green);\n      store<u8>(wasmMemoryStart + pixelStart + 2, <u8>blue);\n\n      let gbcBgPriority: boolean = false;\n      if (bgMapAttributes >= 0) {\n        gbcBgPriority = checkBitOnByte(7, bgMapAttributes);\n      }\n\n      // Lastly, add the pixel to our background priority map\n      // https://github.com/torch2424/wasmBoy/issues/51\n      // Bits 0 & 1 will represent the color Id drawn by the BG/Window\n      // Bit 2 will represent if the Bg/Window has GBC priority.\n      addPriorityforPixel(iteratedOutputX, outputLineY, paletteColorId, gbcBgPriority);\n\n      pixelsDrawn++;\n    }\n  }\n\n  return pixelsDrawn;\n}\n\n// Inlined because closure compiler inlines\nexport function getTilePixelStart(outputLineX: i32, outputLineY: i32, outputWidth: i32): i32 {\n  // Finally Lets place a pixel in memory\n  let pixelStart = outputLineY * outputWidth + outputLineX;\n\n  // Each pixel takes 3 slots, therefore, multiply by 3!\n  return pixelStart * 3;\n}\n\nexport function getTileDataAddress(tileDataMemoryLocation: i32, tileIdFromTileMap: i32): i32 {\n  // Watch this part of The ultimate gameboy talk: https://youtu.be/HyzD8pNlpwI?t=30m50s\n  // A line of 8 pixels on a single tile, is represented by 2 bytes.\n  // since a single tile is 8x8 pixels, 8 * 2 = 16 bytes\n\n  // Get the tile ID's tile addess from tile data.\n  // For instance, let's say our first line of tile data represents tiles for letters:\n  // a b c d e f g\n  // And we have tileId 0x02. That means we want the tile for the 'c' character\n  // Since each tile is 16 bytes, it would be the starting tileDataAddress + (tileId * tileSize), to skip over tiles we dont want\n  // The whole signed thing is weird, and has something to do how the second set of tile data is stored :p\n  if (tileDataMemoryLocation === Graphics.memoryLocationTileDataSelectZeroStart) {\n    // Treat the tile Id as a signed int, subtract an offset of 128\n    // if the tileId was 0 then the tile would be in memory region 0x9000-0x900F\n    if (checkBitOnByte(7, tileIdFromTileMap)) {\n      tileIdFromTileMap -= 128;\n    } else {\n      tileIdFromTileMap += 128;\n    }\n  }\n\n  // if the background layout gave us the tileId 0, then the tile data would be between 0x8000-0x800F.\n  return tileDataMemoryLocation + tileIdFromTileMap * 16;\n}\n","// NOTE: Tons of Copy-pasta btween channels, because Classes cannot be instantiated yet in assemblyscript\n\n// Square Channel with Frequency Sweep\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Frequency_Sweep\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Sound } from './sound';\nimport { isDutyCycleClockPositiveOrNegativeForWaveform } from './duty';\nimport { Cpu } from '../cpu/index';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { checkBitOnByte, log, logTimeout } from '../helpers/index';\n\nexport class Channel1 {\n  // Cycle Counter for our sound accumulator\n  static cycleCounter: i32 = 0;\n\n  // Max Length of our Length Load\n  static MAX_LENGTH: i32 = 64;\n\n  // Squarewave channel with volume envelope and frequency sweep functions.\n  // NR10 -> Sweep Register R/W\n  static readonly memoryLocationNRx0: i32 = 0xff10;\n  // -PPP NSSS Sweep period, negate, shift\n  static NRx0SweepPeriod: i32 = 0;\n  static NRx0Negate: boolean = false;\n  static NRx0SweepShift: i32 = 0;\n  static updateNRx0(value: i32): void {\n    let oldSweepNegate = Channel1.NRx0Negate;\n\n    Channel1.NRx0SweepPeriod = (value & 0x70) >> 4;\n    Channel1.NRx0Negate = checkBitOnByte(3, value);\n    Channel1.NRx0SweepShift = value & 0x07;\n\n    // Obscure Behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    // Clearing the sweep negate mode bit in NR10 after at least one sweep calculation has been made,\n    // using the negate mode since the last trigger causes the channel to be immediately disabled.\n    // This prevents you from having the sweep lower the frequency then raise the frequency without a trigger inbetween.\n    if (oldSweepNegate && !Channel1.NRx0Negate && Channel1.sweepNegateShouldDisableChannelOnClear) {\n      Channel1.isEnabled = false;\n    }\n  }\n\n  // NR11 -> Sound length/Wave pattern duty (R/W)\n  static readonly memoryLocationNRx1: i32 = 0xff11;\n  // DDLL LLLL Duty, Length load (64-L)\n  static NRx1Duty: i32 = 0;\n  static NRx1LengthLoad: i32 = 0;\n  static updateNRx1(value: i32): void {\n    Channel1.NRx1Duty = (value >> 6) & 0x03;\n    Channel1.NRx1LengthLoad = value & 0x3f;\n\n    // Also need to set our length counter. Taken from the old, setChannelLengthCounter\n    // Channel length is determined by 64 (or 256 if channel 3), - the length load\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n    // Note, this will be different for channel 3\n    Channel1.lengthCounter = Channel1.MAX_LENGTH - Channel1.NRx1LengthLoad;\n  }\n\n  // NR12 -> Volume Envelope (R/W)\n  static readonly memoryLocationNRx2: i32 = 0xff12;\n  // VVVV APPP Starting volume, Envelope add mode, period\n  static NRx2StartingVolume: i32 = 0;\n  static NRx2EnvelopeAddMode: boolean = false;\n  static NRx2EnvelopePeriod: i32 = 0;\n  static updateNRx2(value: i32): void {\n    // Handle \"Zombie Mode\" Obscure behavior\n    // https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    if (Channel1.isEnabled) {\n      // If the old envelope period was zero and the envelope is still doing automatic updates,\n      // volume is incremented by 1, otherwise if the envelope was in subtract mode,\n      // volume is incremented by 2.\n      // NOTE: However, from my testing, it ALWAYS increments by one. This was determined\n      // by my testing for prehistoric man\n      if (Channel1.NRx2EnvelopePeriod === 0 && Channel1.isEnvelopeAutomaticUpdating) {\n        // Volume can't be more than 4 bits\n        Channel1.volume = (Channel1.volume + 1) & 0x0f;\n      }\n\n      // If the mode was changed (add to subtract or subtract to add),\n      // volume is set to 16-volume. But volume cant be more than 4 bits\n      if (Channel1.NRx2EnvelopeAddMode !== checkBitOnByte(3, value)) {\n        Channel1.volume = (16 - Channel1.volume) & 0x0f;\n      }\n    }\n\n    // Handle the regular write\n    Channel1.NRx2StartingVolume = (value >> 4) & 0x0f;\n    Channel1.NRx2EnvelopeAddMode = checkBitOnByte(3, value);\n    Channel1.NRx2EnvelopePeriod = value & 0x07;\n\n    // Also, get our channel is dac enabled\n    let isDacEnabled = (value & 0xf8) > 0;\n    Channel1.isDacEnabled = isDacEnabled;\n\n    // Blargg length test\n    // Disabling DAC should disable channel immediately\n    if (!isDacEnabled) {\n      Channel1.isEnabled = false;\n    }\n  }\n\n  // NR13 -> Frequency lo (W)\n  static readonly memoryLocationNRx3: i32 = 0xff13;\n  // FFFF FFFF Frequency LSB\n  static NRx3FrequencyLSB: i32 = 0;\n  static updateNRx3(value: i32): void {\n    Channel1.NRx3FrequencyLSB = value;\n\n    // Update Channel Frequency\n    Channel1.frequency = (Channel1.NRx4FrequencyMSB << 8) | value;\n  }\n\n  // NR14 -> Frequency hi (R/W)\n  static readonly memoryLocationNRx4: i32 = 0xff14;\n  // TL-- -FFF Trigger, Length enable, Frequency MSB\n  static NRx4LengthEnabled: boolean = false;\n  static NRx4FrequencyMSB: i32 = 0;\n  // NOTE: Order in which these events happen are very particular\n  // And globals can be affected by other functions\n  // Thus, optimizations here should be extremely careful\n  static updateNRx4(value: i32): void {\n    // Handle our Channel frequency first\n    // As this is modified if we trigger for length.\n    let frequencyMSB = value & 0x07;\n    Channel1.NRx4FrequencyMSB = frequencyMSB;\n    Channel1.frequency = (frequencyMSB << 8) | Channel1.NRx3FrequencyLSB;\n\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    // Also see blargg's cgb sound test\n    // Extra length clocking occurs when writing to NRx4,\n    // when the frame sequencer's next step is one that,\n    // doesn't clock the length counter.\n    let frameSequencer = Sound.frameSequencer;\n    let doesNextFrameSequencerUpdateLength = (frameSequencer & 1) === 1;\n    let isBeingLengthEnabled = !Channel1.NRx4LengthEnabled && checkBitOnByte(6, value);\n    if (!doesNextFrameSequencerUpdateLength) {\n      // Check lengthEnable\n      if (Channel1.lengthCounter > 0 && isBeingLengthEnabled) {\n        Channel1.lengthCounter -= 1;\n\n        if (!checkBitOnByte(7, value) && Channel1.lengthCounter === 0) {\n          Channel1.isEnabled = false;\n        }\n      }\n    }\n\n    // Set the length enabled from the value\n    Channel1.NRx4LengthEnabled = checkBitOnByte(6, value);\n\n    // Trigger out channel, unfreeze length if frozen\n    // Triggers should happen after obscure behavior\n    // See test 11 for trigger\n    if (checkBitOnByte(7, value)) {\n      Channel1.trigger();\n\n      // When we trigger on the obscure behavior, and we reset the length Counter to max\n      // We need to clock\n      if (!doesNextFrameSequencerUpdateLength && Channel1.lengthCounter === Channel1.MAX_LENGTH && Channel1.NRx4LengthEnabled) {\n        Channel1.lengthCounter -= 1;\n      }\n    }\n  }\n\n  // Channel Properties\n  static readonly channelNumber: i32 = 1;\n  static isEnabled: boolean = false;\n  static isDacEnabled: boolean = false;\n  static frequency: i32 = 0;\n  static frequencyTimer: i32 = 0x00;\n  static envelopeCounter: i32 = 0x00;\n  static isEnvelopeAutomaticUpdating: boolean = false;\n  static lengthCounter: i32 = 0x00;\n  static volume: i32 = 0x00;\n\n  // Square Wave properties\n  static dutyCycle: i32 = 0x00;\n  static waveFormPositionOnDuty: i32 = 0x00;\n\n  // Channel 1 Sweep\n  static isSweepEnabled: boolean = false;\n  static sweepCounter: i32 = 0x00;\n  static sweepShadowFrequency: i32 = 0x00;\n  static sweepNegateShouldDisableChannelOnClear: boolean = false;\n\n  // Save States\n  static readonly saveStateSlot: i32 = 7;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    // Cycle Counter\n    store<i32>(getSaveStateMemoryOffset(0x00, Channel1.saveStateSlot), Channel1.cycleCounter);\n\n    // NRx0\n    store<u8>(getSaveStateMemoryOffset(0x04, Channel1.saveStateSlot), <u8>Channel1.NRx0SweepPeriod);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x05, Channel1.saveStateSlot), Channel1.NRx0Negate);\n    store<u8>(getSaveStateMemoryOffset(0x06, Channel1.saveStateSlot), <u8>Channel1.NRx0SweepShift);\n\n    // NRx1\n    store<u8>(getSaveStateMemoryOffset(0x07, Channel1.saveStateSlot), <u8>Channel1.NRx1Duty);\n    store<u16>(getSaveStateMemoryOffset(0x09, Channel1.saveStateSlot), <u16>Channel1.NRx1LengthLoad);\n\n    // NRx2\n    store<u8>(getSaveStateMemoryOffset(0x0a, Channel1.saveStateSlot), <u8>Channel1.NRx2StartingVolume);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0b, Channel1.saveStateSlot), Channel1.NRx2EnvelopeAddMode);\n    store<u8>(getSaveStateMemoryOffset(0x0c, Channel1.saveStateSlot), <u8>Channel1.NRx2EnvelopePeriod);\n\n    // NRx3\n    store<u8>(getSaveStateMemoryOffset(0x0d, Channel1.saveStateSlot), <u8>Channel1.NRx3FrequencyLSB);\n\n    // NRx4\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0e, Channel1.saveStateSlot), Channel1.NRx4LengthEnabled);\n    store<u8>(getSaveStateMemoryOffset(0x0f, Channel1.saveStateSlot), <u8>Channel1.NRx4FrequencyMSB);\n\n    // Channel Properties\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x10, Channel1.saveStateSlot), Channel1.isEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x11, Channel1.saveStateSlot), Channel1.isDacEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x12, Channel1.saveStateSlot), Channel1.frequency);\n    store<i32>(getSaveStateMemoryOffset(0x16, Channel1.saveStateSlot), Channel1.frequencyTimer);\n    store<i32>(getSaveStateMemoryOffset(0x1a, Channel1.saveStateSlot), Channel1.envelopeCounter);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x1e, Channel1.saveStateSlot), Channel1.isEnvelopeAutomaticUpdating);\n    store<i32>(getSaveStateMemoryOffset(0x1f, Channel1.saveStateSlot), Channel1.lengthCounter);\n    store<i32>(getSaveStateMemoryOffset(0x23, Channel1.saveStateSlot), Channel1.volume);\n\n    // Square Duty\n    store<u8>(getSaveStateMemoryOffset(0x27, Channel1.saveStateSlot), Channel1.dutyCycle);\n    store<u8>(getSaveStateMemoryOffset(0x28, Channel1.saveStateSlot), <u8>Channel1.waveFormPositionOnDuty);\n\n    // Square Sweep\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x29, Channel1.saveStateSlot), Channel1.isSweepEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x2a, Channel1.saveStateSlot), Channel1.sweepCounter);\n    store<u16>(getSaveStateMemoryOffset(0x2e, Channel1.saveStateSlot), Channel1.sweepShadowFrequency);\n    storeBooleanDirectlyToWasmMemory(\n      getSaveStateMemoryOffset(0x31, Channel1.saveStateSlot),\n      Channel1.sweepNegateShouldDisableChannelOnClear\n    );\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // Cycle Counter\n    Channel1.cycleCounter = load<i32>(getSaveStateMemoryOffset(0x00, Channel1.cycleCounter));\n\n    // NRx0\n    Channel1.NRx0SweepPeriod = load<u8>(getSaveStateMemoryOffset(0x04, Channel1.saveStateSlot));\n    Channel1.NRx0Negate = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x05, Channel1.saveStateSlot));\n    Channel1.NRx0SweepShift = load<u8>(getSaveStateMemoryOffset(0x06, Channel1.saveStateSlot));\n\n    // NRx1\n    Channel1.NRx1Duty = load<u8>(getSaveStateMemoryOffset(0x07, Channel1.saveStateSlot));\n    Channel1.NRx1LengthLoad = load<u16>(getSaveStateMemoryOffset(0x09, Channel1.saveStateSlot));\n\n    // NRx2\n    Channel1.NRx2StartingVolume = load<u8>(getSaveStateMemoryOffset(0x0a, Channel1.saveStateSlot));\n    Channel1.NRx2EnvelopeAddMode = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0b, Channel1.saveStateSlot));\n    Channel1.NRx2EnvelopePeriod = load<u8>(getSaveStateMemoryOffset(0x0c, Channel1.saveStateSlot));\n\n    // NRx3\n    Channel1.NRx3FrequencyLSB = load<u8>(getSaveStateMemoryOffset(0x0d, Channel1.saveStateSlot));\n\n    // NRx4\n    Channel1.NRx4LengthEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0e, Channel1.saveStateSlot));\n    Channel1.NRx4FrequencyMSB = load<u8>(getSaveStateMemoryOffset(0x0f, Channel1.saveStateSlot));\n\n    // Channel Properties\n    Channel1.isEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x10, Channel1.saveStateSlot));\n    Channel1.isDacEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x11, Channel1.saveStateSlot));\n    Channel1.frequency = load<i32>(getSaveStateMemoryOffset(0x12, Channel1.saveStateSlot));\n    Channel1.frequencyTimer = load<i32>(getSaveStateMemoryOffset(0x16, Channel1.saveStateSlot));\n    Channel1.envelopeCounter = load<i32>(getSaveStateMemoryOffset(0x1a, Channel1.saveStateSlot));\n    Channel1.isEnvelopeAutomaticUpdating = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x1e, Channel1.saveStateSlot));\n    Channel1.lengthCounter = load<i32>(getSaveStateMemoryOffset(0x1f, Channel1.saveStateSlot));\n    Channel1.volume = load<i32>(getSaveStateMemoryOffset(0x23, Channel1.saveStateSlot));\n\n    // Square Duty\n    Channel1.dutyCycle = load<u8>(getSaveStateMemoryOffset(0x27, Channel1.saveStateSlot));\n    Channel1.waveFormPositionOnDuty = load<u8>(getSaveStateMemoryOffset(0x28, Channel1.saveStateSlot));\n\n    // Square Sweep\n    Channel1.isSweepEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x29, Channel1.saveStateSlot));\n    Channel1.sweepCounter = load<u8>(getSaveStateMemoryOffset(0x2a, Channel1.saveStateSlot));\n    Channel1.sweepShadowFrequency = load<u8>(getSaveStateMemoryOffset(0x2e, Channel1.saveStateSlot));\n    Channel1.sweepNegateShouldDisableChannelOnClear = loadBooleanDirectlyFromWasmMemory(\n      getSaveStateMemoryOffset(0x31, Channel1.saveStateSlot)\n    );\n  }\n\n  static initialize(): void {\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx0, 0x80);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx1, 0xbf);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx2, 0xf3);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx3, 0xc1);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx4, 0xbf);\n\n    // Override/reset some variables if the boot ROM is enabled\n    // For GBC and GB\n    if (Cpu.BootROMEnabled) {\n      eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx1, 0x3f);\n      eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx2, 0x00);\n      eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx3, 0x00);\n      eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx4, 0xb8);\n    }\n  }\n\n  // Function to get a sample using the cycle counter on the channel\n  static getSampleFromCycleCounter(): i32 {\n    let accumulatedCycles = Channel1.cycleCounter;\n    Channel1.cycleCounter = 0;\n    return Channel1.getSample(accumulatedCycles);\n  }\n\n  // Function to reset our timer, useful for GBC double speed mode\n  static resetTimer(): void {\n    let frequencyTimer = (2048 - Channel1.frequency) << 2;\n\n    // TODO: Ensure this is correct for GBC Double Speed Mode\n    if (Cpu.GBCDoubleSpeed) {\n      frequencyTimer = frequencyTimer << 2;\n    }\n    Channel1.frequencyTimer = frequencyTimer;\n  }\n\n  static getSample(numberOfCycles: i32): i32 {\n    // Decrement our channel timer\n    let frequencyTimer = Channel1.frequencyTimer;\n    frequencyTimer -= numberOfCycles;\n    while (frequencyTimer <= 0) {\n      // Get the amount that overflowed so we don't drop cycles\n      let overflowAmount = abs(frequencyTimer);\n\n      // Reset our timer\n      // A square channel's frequency timer period is set to (2048-frequency)*4.\n      // Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through:\n      Channel1.resetTimer();\n      frequencyTimer = Channel1.frequencyTimer;\n      frequencyTimer -= overflowAmount;\n\n      // Also increment our duty cycle\n      // What is duty? https://en.wikipedia.org/wiki/Duty_cycle\n      // Duty cycle for square wave: http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n      Channel1.waveFormPositionOnDuty = (Channel1.waveFormPositionOnDuty + 1) & 7;\n    }\n\n    Channel1.frequencyTimer = frequencyTimer;\n\n    // Get our ourput volume\n    let outputVolume = 0;\n\n    // Finally to set our output volume, the channel must be enabled,\n    // Our channel DAC must be enabled, and we must be in an active state\n    // Of our duty cycle\n    if (Channel1.isEnabled && Channel1.isDacEnabled) {\n      // Volume can't be more than 4 bits.\n      // Volume should never be more than 4 bits, but doing a check here\n      outputVolume = Channel1.volume & 0x0f;\n    } else {\n      // Return silence\n      // Since range from -15 - 15, or 0 to 30 for our unsigned\n      return 15;\n    }\n\n    // Get the current sampleValue\n    let sample = 1;\n    if (!isDutyCycleClockPositiveOrNegativeForWaveform(Channel1.NRx1Duty, Channel1.waveFormPositionOnDuty)) {\n      sample = -sample;\n    }\n\n    sample *= outputVolume;\n\n    // Square Waves Can range from -15 - 15. Therefore simply add 15\n    sample += 15;\n    return sample;\n  }\n\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Trigger_Event\n  static trigger(): void {\n    Channel1.isEnabled = true;\n    // Set length to maximum done in write\n    if (Channel1.lengthCounter === 0) {\n      Channel1.lengthCounter = Channel1.MAX_LENGTH;\n    }\n\n    // Reset our timer\n    // A square channel's frequency timer period is set to (2048-frequency)*4.\n    // Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through:\n    Channel1.resetTimer();\n\n    // The volume envelope and sweep timers treat a period of 0 as 8.\n    // Meaning, if the period is zero, set it to the max (8).\n    if (Channel1.NRx2EnvelopePeriod === 0) {\n      Channel1.envelopeCounter = 8;\n    } else {\n      Channel1.envelopeCounter = Channel1.NRx2EnvelopePeriod;\n    }\n    Channel1.isEnvelopeAutomaticUpdating = true;\n\n    Channel1.volume = Channel1.NRx2StartingVolume;\n\n    // Handle Channel Sweep\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    Channel1.sweepShadowFrequency = Channel1.frequency;\n\n    // Reset back to the sweep period\n    // Obscure behavior\n    // Sweep timers treat a period o 0 as 8\n    if (Channel1.NRx0SweepPeriod === 0) {\n      Channel1.sweepCounter = 8;\n    } else {\n      Channel1.sweepCounter = Channel1.NRx0SweepPeriod;\n    }\n\n    // The internal enabled flag is set if either the sweep period or shift are non-zero, cleared otherwise.\n    Channel1.isSweepEnabled = Channel1.NRx0SweepPeriod > 0 || Channel1.NRx0SweepShift > 0;\n\n    Channel1.sweepNegateShouldDisableChannelOnClear = false;\n\n    // If the sweep shift is non-zero, frequency calculation and the overflow check are performed immediately.\n    // NOTE: The double calculation thing for the sweep does not happen here.\n    if (Channel1.NRx0SweepShift > 0 && didCalculatedSweepOverflow(calculateSweep())) {\n      Channel1.isEnabled = false;\n    }\n\n    // Finally if DAC is off, channel is still disabled\n    if (!Channel1.isDacEnabled) {\n      Channel1.isEnabled = false;\n    }\n  }\n\n  // Function to determine if the current channel would update when getting the sample\n  // This is used to accumulate samples\n  static willChannelUpdate(numberOfCycles: i32): boolean {\n    //Increment our cycle counter\n    let cycleCounter = Channel1.cycleCounter + numberOfCycles;\n    Channel1.cycleCounter = cycleCounter;\n\n    // Dac enabled status cached by accumulator\n    return !(Channel1.frequencyTimer - cycleCounter > 0);\n  }\n\n  static updateSweep(): void {\n    // Dont update period if not enabled\n    if (!Channel1.isEnabled || !Channel1.isSweepEnabled) {\n      return;\n    }\n\n    // Decrement the sweep counter\n    let sweepCounter = Channel1.sweepCounter - 1;\n    if (sweepCounter <= 0) {\n      // Reset back to the sweep period\n      // Obscure behavior\n      // Sweep timers treat a period of 0 as 8 (They reset back to the max)\n      if (Channel1.NRx0SweepPeriod === 0) {\n        // Sweep isn't calculated when the period is 0\n        Channel1.sweepCounter = 8;\n      } else {\n        // Reset our sweep counter to its period\n        Channel1.sweepCounter = Channel1.NRx0SweepPeriod;\n\n        // Calculate our sweep\n        // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n        // When it generates a clock and the sweep's internal enabled flag is set and the sweep period is not zero,\n        // a new frequency is calculated and the overflow check is performed. If the new frequency is 2047 or less,\n        // and the sweep shift is not zero, this new frequency is written back to the shadow frequency,\n        // and square 1's frequency in NR13 and NR14, then frequency calculation,\n        // and overflow check are run AGAIN immediately using this new value,\n        // but this second new frequency is not written back.\n        let newFrequency = calculateSweep();\n        if (didCalculatedSweepOverflow(newFrequency)) {\n          Channel1.isEnabled = false;\n        }\n\n        if (Channel1.NRx0SweepShift > 0) {\n          Channel1.setFrequency(newFrequency);\n\n          if (didCalculatedSweepOverflow(calculateSweep())) {\n            Channel1.isEnabled = false;\n          }\n        }\n      }\n    } else {\n      Channel1.sweepCounter = sweepCounter;\n    }\n  }\n\n  static updateLength(): void {\n    let lengthCounter = Channel1.lengthCounter;\n    if (lengthCounter > 0 && Channel1.NRx4LengthEnabled) {\n      lengthCounter -= 1;\n\n      if (lengthCounter === 0) {\n        Channel1.isEnabled = false;\n      }\n    }\n    Channel1.lengthCounter = lengthCounter;\n  }\n\n  static updateEnvelope(): void {\n    let envelopeCounter = Channel1.envelopeCounter - 1;\n    if (envelopeCounter <= 0) {\n      // Reset back to the sweep period\n      // Obscure behavior\n      // Envelopes treat a period of 0 as 8 (They reset back to the max)\n      if (Channel1.NRx2EnvelopePeriod === 0) {\n        envelopeCounter = 8;\n      } else {\n        envelopeCounter = Channel1.NRx2EnvelopePeriod;\n\n        // When the timer generates a clock and the envelope period is NOT zero, a new volume is calculated\n        // NOTE: There is some weiirrdd obscure behavior where zero can equal 8, so watch out for that\n        // If notes are sustained for too long, this is probably why\n        if (envelopeCounter !== 0 && Channel1.isEnvelopeAutomaticUpdating) {\n          let volume = Channel1.volume;\n\n          // Increment the volume\n          if (Channel1.NRx2EnvelopeAddMode) {\n            volume += 1;\n          } else {\n            volume -= 1;\n          }\n\n          // Don't allow the volume to go above 4 bits.\n          volume = volume & 0x0f;\n\n          // Check if we are below the max\n          if (volume < 15) {\n            Channel1.volume = volume;\n          } else {\n            Channel1.isEnvelopeAutomaticUpdating = false;\n          }\n        }\n      }\n    }\n    Channel1.envelopeCounter = envelopeCounter;\n  }\n\n  static setFrequency(frequency: i32): void {\n    // Set our shadowFrequency\n    Channel1.sweepShadowFrequency = frequency;\n\n    // Get the high and low bits\n    let passedFrequencyHighBits = (frequency >> 8) & 0x07;\n    let passedFrequencyLowBits = frequency & 0xff;\n\n    // Get the new register 4\n    let register4 = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx4);\n    // Knock off lower 3 bits, and Or on our high bits\n    let newRegister4 = register4 & 0xf8;\n    newRegister4 = newRegister4 | passedFrequencyHighBits;\n\n    // Set the registers\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx3, passedFrequencyLowBits);\n    eightBitStoreIntoGBMemory(Channel1.memoryLocationNRx4, newRegister4);\n\n    // Save the frequency for ourselves without triggering memory traps\n    Channel1.NRx3FrequencyLSB = passedFrequencyLowBits;\n    Channel1.NRx4FrequencyMSB = passedFrequencyHighBits;\n    Channel1.frequency = (Channel1.NRx4FrequencyMSB << 8) | Channel1.NRx3FrequencyLSB;\n  }\n  // Done!\n}\n\n// Sweep Specific functions\n// Function to determing a new sweep in the current context\nfunction calculateSweep(): i32 {\n  // Start our new frequency, by making it equal to the \"shadow frequency\"\n  let oldFrequency = Channel1.sweepShadowFrequency;\n  let newFrequency = oldFrequency >> Channel1.NRx0SweepShift;\n\n  // Check for sweep negation\n  if (Channel1.NRx0Negate) {\n    Channel1.sweepNegateShouldDisableChannelOnClear = true;\n    newFrequency = oldFrequency - newFrequency;\n  } else {\n    newFrequency = oldFrequency + newFrequency;\n  }\n\n  return newFrequency;\n}\n\n// Function to check if a calculated sweep overflowed\nfunction didCalculatedSweepOverflow(calculatedSweep: i32): boolean {\n  // 7FF is the highest value of the frequency: 111 1111 1111\n  // if it overflows, should disable the channel (handled by the caller)\n  if (calculatedSweep > 0x7ff) {\n    return true;\n  }\n\n  return false;\n}\n","// NOTE: Tons of Copy-pasta btween channels, because Classes cannot be instantiated yet in assemblyscript\n\n// Simple Square Channel\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Sound } from './sound';\nimport { isDutyCycleClockPositiveOrNegativeForWaveform } from './duty';\nimport { Cpu } from '../cpu/index';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { checkBitOnByte, log, logTimeout } from '../helpers/index';\n\nexport class Channel2 {\n  // Cycle Counter for our sound accumulator\n  static cycleCounter: i32 = 0;\n\n  // Max Length of our Length Load\n  static MAX_LENGTH: i32 = 64;\n\n  // Squarewave channel with volume envelope functions only.\n\n  // Only used by register reading\n  static readonly memoryLocationNRx0: i32 = 0xff15;\n\n  // NR21 -> Sound length/Wave pattern duty (R/W)\n  static readonly memoryLocationNRx1: i32 = 0xff16;\n  // DDLL LLLL Duty, Length load (64-L)\n  static NRx1Duty: i32 = 0;\n  static NRx1LengthLoad: i32 = 0;\n  static updateNRx1(value: i32): void {\n    Channel2.NRx1Duty = (value >> 6) & 0x03;\n    Channel2.NRx1LengthLoad = value & 0x3f;\n\n    // Also need to set our length counter. Taken from the old, setChannelLengthCounter\n    // Channel length is determined by 64 (or 256 if channel 3), - the length load\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n    // Note, this will be different for channel 3\n    Channel2.lengthCounter = Channel2.MAX_LENGTH - Channel2.NRx1LengthLoad;\n  }\n\n  // NR22 -> Volume Envelope (R/W)\n  static readonly memoryLocationNRx2: i32 = 0xff17;\n  // VVVV APPP Starting volume, Envelope add mode, period\n  static NRx2StartingVolume: i32 = 0;\n  static NRx2EnvelopeAddMode: boolean = false;\n  static NRx2EnvelopePeriod: i32 = 0;\n  static updateNRx2(value: i32): void {\n    // Handle \"Zombie Mode\" Obscure behavior\n    // https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    if (Channel2.isEnabled) {\n      // If the old envelope period was zero and the envelope is still doing automatic updates,\n      // volume is incremented by 1, otherwise if the envelope was in subtract mode,\n      // volume is incremented by 2.\n      // NOTE: However, from my testing, it ALWAYS increments by one. This was determined\n      // by my testing for prehistoric man\n      if (Channel2.NRx2EnvelopePeriod === 0 && Channel2.isEnvelopeAutomaticUpdating) {\n        // Volume can't be more than 4 bits\n        Channel2.volume = (Channel2.volume + 1) & 0x0f;\n      }\n\n      // If the mode was changed (add to subtract or subtract to add),\n      // volume is set to 16-volume. But volume cant be more than 4 bits\n      if (Channel2.NRx2EnvelopeAddMode !== checkBitOnByte(3, value)) {\n        Channel2.volume = (16 - Channel2.volume) & 0x0f;\n      }\n    }\n\n    Channel2.NRx2StartingVolume = (value >> 4) & 0x0f;\n    Channel2.NRx2EnvelopeAddMode = checkBitOnByte(3, value);\n    Channel2.NRx2EnvelopePeriod = value & 0x07;\n\n    // Also, get our channel is dac enabled\n    let isDacEnabled = (value & 0xf8) > 0;\n    Channel2.isDacEnabled = isDacEnabled;\n\n    // Blargg length test\n    // Disabling DAC should disable channel immediately\n    if (!isDacEnabled) {\n      Channel2.isEnabled = isDacEnabled;\n    }\n  }\n\n  // NR23 -> Frequency lo (W)\n  static readonly memoryLocationNRx3: i32 = 0xff18;\n  // FFFF FFFF Frequency LSB\n  static NRx3FrequencyLSB: i32 = 0;\n  static updateNRx3(value: i32): void {\n    Channel2.NRx3FrequencyLSB = value;\n\n    // Update Channel Frequency\n    Channel2.frequency = (Channel2.NRx4FrequencyMSB << 8) | value;\n  }\n\n  // NR24 -> Frequency hi (R/W)\n  static readonly memoryLocationNRx4: i32 = 0xff19;\n  // TL-- -FFF Trigger, Length enable, Frequency MSB\n  static NRx4LengthEnabled: boolean = false;\n  static NRx4FrequencyMSB: i32 = 0;\n  static updateNRx4(value: i32): void {\n    // Handle our Channel frequency first\n    // As this is modified if we trigger for length.\n    let frequencyMSB = value & 0x07;\n    Channel2.NRx4FrequencyMSB = frequencyMSB;\n    Channel2.frequency = (frequencyMSB << 8) | Channel2.NRx3FrequencyLSB;\n\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    // Also see blargg's cgb sound test\n    // Extra length clocking occurs when writing to NRx4,\n    // when the frame sequencer's next step is one that,\n    // doesn't clock the length counter.\n    let frameSequencer = Sound.frameSequencer;\n    let doesNextFrameSequencerUpdateLength = (frameSequencer & 1) === 1;\n    let isBeingLengthEnabled = !Channel2.NRx4LengthEnabled && checkBitOnByte(6, value);\n    if (!doesNextFrameSequencerUpdateLength) {\n      if (Channel2.lengthCounter > 0 && isBeingLengthEnabled) {\n        Channel2.lengthCounter -= 1;\n\n        if (!checkBitOnByte(7, value) && Channel2.lengthCounter === 0) {\n          Channel2.isEnabled = false;\n        }\n      }\n    }\n\n    // Set the length enabled from the value\n    Channel2.NRx4LengthEnabled = checkBitOnByte(6, value);\n\n    // Trigger out channel, unfreeze length if frozen\n    // Triggers should happen after obscure behavior\n    // See test 11 for trigger\n    if (checkBitOnByte(7, value)) {\n      Channel2.trigger();\n\n      // When we trigger on the obscure behavior, and we reset the length Counter to max\n      // We need to clock\n      if (!doesNextFrameSequencerUpdateLength && Channel2.lengthCounter === Channel2.MAX_LENGTH && Channel2.NRx4LengthEnabled) {\n        Channel2.lengthCounter -= 1;\n      }\n    }\n  }\n\n  // Channel Properties\n  static readonly channelNumber: i32 = 2;\n  static isEnabled: boolean = false;\n  static isDacEnabled: boolean = false;\n  static frequency: i32 = 0;\n  static frequencyTimer: i32 = 0x00;\n  static envelopeCounter: i32 = 0x00;\n  static isEnvelopeAutomaticUpdating: boolean = false;\n  static lengthCounter: i32 = 0x00;\n  static volume: i32 = 0x00;\n\n  // Square Wave properties\n  static dutyCycle: i32 = 0x00;\n  static waveFormPositionOnDuty: i32 = 0x00;\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 8;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    // Cycle Counter\n    store<i32>(getSaveStateMemoryOffset(0x00, Channel2.saveStateSlot), Channel2.cycleCounter);\n\n    // NRx0\n    // No NRx0 Properties\n\n    // NRx1\n    store<u8>(getSaveStateMemoryOffset(0x07, Channel2.saveStateSlot), <u8>Channel2.NRx1Duty);\n    store<u16>(getSaveStateMemoryOffset(0x08, Channel2.saveStateSlot), <u16>Channel2.NRx1LengthLoad);\n\n    // NRx2\n    store<u8>(getSaveStateMemoryOffset(0x0a, Channel2.saveStateSlot), <u8>Channel2.NRx2StartingVolume);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0b, Channel2.saveStateSlot), Channel2.NRx2EnvelopeAddMode);\n    store<u8>(getSaveStateMemoryOffset(0x0c, Channel2.saveStateSlot), <u8>Channel2.NRx2EnvelopePeriod);\n\n    // NRx3\n    store<u8>(getSaveStateMemoryOffset(0x0d, Channel2.saveStateSlot), <u8>Channel2.NRx3FrequencyLSB);\n\n    // NRx4\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0e, Channel2.saveStateSlot), Channel2.NRx4LengthEnabled);\n    store<u8>(getSaveStateMemoryOffset(0x0f, Channel2.saveStateSlot), <u8>Channel2.NRx4FrequencyMSB);\n\n    // Channel Properties\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x10, Channel2.saveStateSlot), Channel2.isEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x11, Channel2.saveStateSlot), Channel2.isDacEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x12, Channel2.saveStateSlot), Channel2.frequency);\n    store<i32>(getSaveStateMemoryOffset(0x16, Channel2.saveStateSlot), Channel2.frequencyTimer);\n    store<i32>(getSaveStateMemoryOffset(0x1a, Channel2.saveStateSlot), Channel2.envelopeCounter);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x1e, Channel2.saveStateSlot), Channel2.isEnvelopeAutomaticUpdating);\n    store<i32>(getSaveStateMemoryOffset(0x1f, Channel2.saveStateSlot), Channel2.lengthCounter);\n    store<i32>(getSaveStateMemoryOffset(0x23, Channel2.saveStateSlot), Channel2.volume);\n\n    // Square Duty\n    store<u8>(getSaveStateMemoryOffset(0x27, Channel2.saveStateSlot), Channel2.dutyCycle);\n    store<u8>(getSaveStateMemoryOffset(0x28, Channel2.saveStateSlot), <u8>Channel2.waveFormPositionOnDuty);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // Cycle Counter\n    Channel2.cycleCounter = load<i32>(getSaveStateMemoryOffset(0x00, Channel2.cycleCounter));\n\n    // NRx0\n    // No NRx0\n\n    // NRx1\n    Channel2.NRx1Duty = load<u8>(getSaveStateMemoryOffset(0x07, Channel2.saveStateSlot));\n    Channel2.NRx1LengthLoad = load<u16>(getSaveStateMemoryOffset(0x08, Channel2.saveStateSlot));\n\n    // NRx2\n    Channel2.NRx2StartingVolume = load<u8>(getSaveStateMemoryOffset(0xa, Channel2.saveStateSlot));\n    Channel2.NRx2EnvelopeAddMode = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0b, Channel2.saveStateSlot));\n    Channel2.NRx2EnvelopePeriod = load<u8>(getSaveStateMemoryOffset(0x0c, Channel2.saveStateSlot));\n\n    // NRx3\n    Channel2.NRx3FrequencyLSB = load<u8>(getSaveStateMemoryOffset(0x0d, Channel2.saveStateSlot));\n\n    // NRx4\n    Channel2.NRx4LengthEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0e, Channel2.saveStateSlot));\n    Channel2.NRx4FrequencyMSB = load<u8>(getSaveStateMemoryOffset(0x0f, Channel2.saveStateSlot));\n\n    // Channel Properties\n    Channel2.isEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x10, Channel2.saveStateSlot));\n    Channel2.isDacEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x11, Channel2.saveStateSlot));\n    Channel2.frequency = load<i32>(getSaveStateMemoryOffset(0x12, Channel2.saveStateSlot));\n    Channel2.frequencyTimer = load<i32>(getSaveStateMemoryOffset(0x16, Channel2.saveStateSlot));\n    Channel2.envelopeCounter = load<i32>(getSaveStateMemoryOffset(0x1a, Channel2.saveStateSlot));\n    Channel2.isEnvelopeAutomaticUpdating = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x1e, Channel2.saveStateSlot));\n    Channel2.lengthCounter = load<i32>(getSaveStateMemoryOffset(0x1f, Channel2.saveStateSlot));\n    Channel2.volume = load<i32>(getSaveStateMemoryOffset(0x23, Channel2.saveStateSlot));\n\n    // Square Duty\n    Channel2.dutyCycle = load<u8>(getSaveStateMemoryOffset(0x27, Channel2.saveStateSlot));\n    Channel2.waveFormPositionOnDuty = load<u8>(getSaveStateMemoryOffset(0x28, Channel2.saveStateSlot));\n  }\n\n  static initialize(): void {\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx1 - 1, 0xff);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx1, 0x3f);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx2, 0x00);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx3, 0x00);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx4, 0xb8);\n  }\n\n  // Function to get a sample using the cycle counter on the channel\n  static getSampleFromCycleCounter(): i32 {\n    let accumulatedCycles = Channel2.cycleCounter;\n    Channel2.cycleCounter = 0;\n    return Channel2.getSample(accumulatedCycles);\n  }\n\n  // Function to reset our timer, useful for GBC double speed mode\n  static resetTimer(): void {\n    let frequencyTimer = (2048 - Channel2.frequency) << 2;\n\n    // TODO: Ensure this is correct for GBC Double Speed Mode\n    Channel2.frequencyTimer = frequencyTimer << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  static getSample(numberOfCycles: i32): i32 {\n    // Decrement our channel timer\n    let frequencyTimer = Channel2.frequencyTimer;\n    frequencyTimer -= numberOfCycles;\n    while (frequencyTimer <= 0) {\n      // Get the amount that overflowed so we don't drop cycles\n      let overflowAmount = abs(frequencyTimer);\n\n      // Reset our timer\n      // A square channel's frequency timer period is set to (2048-frequency)*4.\n      // Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through:\n      Channel2.resetTimer();\n      frequencyTimer = Channel2.frequencyTimer;\n      frequencyTimer -= overflowAmount;\n\n      // Also increment our duty cycle\n      // What is duty? https://en.wikipedia.org/wiki/Duty_cycle\n      // Duty cycle for square wave: http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n      Channel2.waveFormPositionOnDuty = (Channel2.waveFormPositionOnDuty + 1) & 7;\n    }\n\n    Channel2.frequencyTimer = frequencyTimer;\n\n    // Get our ourput volume\n    let outputVolume = 0;\n\n    // Finally to set our output volume, the channel must be enabled,\n    // Our channel DAC must be enabled, and we must be in an active state\n    // Of our duty cycle\n    if (Channel2.isEnabled && Channel2.isDacEnabled) {\n      // Volume can't be more than 4 bits.\n      // Volume should never be more than 4 bits, but doing a check here\n      outputVolume = Channel2.volume & 0x0f;\n    } else {\n      // Return silence\n      // Since range from -15 - 15, or 0 to 30 for our unsigned\n      return 15;\n    }\n\n    // Get the current sampleValue\n    let sample = 1;\n    if (!isDutyCycleClockPositiveOrNegativeForWaveform(Channel2.NRx1Duty, Channel2.waveFormPositionOnDuty)) {\n      sample = -sample;\n    }\n\n    sample = sample * outputVolume;\n\n    // Square Waves Can range from -15 - 15. Therefore simply add 15\n    sample += 15;\n    return sample;\n  }\n\n  //http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Trigger_Event\n  static trigger(): void {\n    Channel2.isEnabled = true;\n    // Set length to maximum done in write\n    if (Channel2.lengthCounter === 0) {\n      Channel2.lengthCounter = Channel2.MAX_LENGTH;\n    }\n\n    // Reset our timer\n    // A square channel's frequency timer period is set to (2048-frequency)*4.\n    // Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through:\n    Channel2.resetTimer();\n\n    // The volume envelope and sweep timers treat a period of 0 as 8.\n    // Meaning, if the period is zero, set it to the max (8).\n    if (Channel2.NRx2EnvelopePeriod === 0) {\n      Channel2.envelopeCounter = 8;\n    } else {\n      Channel2.envelopeCounter = Channel2.NRx2EnvelopePeriod;\n    }\n    Channel2.isEnvelopeAutomaticUpdating = true;\n\n    Channel2.volume = Channel2.NRx2StartingVolume;\n\n    // Finally if DAC is off, channel is still disabled\n    if (!Channel2.isDacEnabled) {\n      Channel2.isEnabled = false;\n    }\n  }\n\n  // Function to determine if the current channel would update when getting the sample\n  // This is used to accumulate samples\n  static willChannelUpdate(numberOfCycles: i32): boolean {\n    //Increment our cycle counter\n    let cycleCounter = Channel2.cycleCounter + numberOfCycles;\n    Channel2.cycleCounter = cycleCounter;\n\n    // Dac enabled status cached by accumulator\n    return !(Channel2.frequencyTimer - cycleCounter > 0);\n  }\n\n  static updateLength(): void {\n    let lengthCounter = Channel2.lengthCounter;\n    if (lengthCounter > 0 && Channel2.NRx4LengthEnabled) {\n      lengthCounter -= 1;\n    }\n\n    if (lengthCounter === 0) {\n      Channel2.isEnabled = false;\n    }\n    Channel2.lengthCounter = lengthCounter;\n  }\n\n  static updateEnvelope(): void {\n    let envelopeCounter = Channel2.envelopeCounter - 1;\n    if (envelopeCounter <= 0) {\n      // Reset back to the sweep period\n      // Obscure behavior\n      // Envelopes treat a period of 0 as 8 (They reset back to the max)\n      if (Channel2.NRx2EnvelopePeriod === 0) {\n        envelopeCounter = 8;\n      } else {\n        envelopeCounter = Channel2.NRx2EnvelopePeriod;\n\n        // When the timer generates a clock and the envelope period is NOT zero, a new volume is calculated\n        // NOTE: There is some weiirrdd obscure behavior where zero can equal 8, so watch out for that\n        if (envelopeCounter !== 0 && Channel2.isEnvelopeAutomaticUpdating) {\n          let volume = Channel2.volume;\n\n          // Increment the volume\n          if (Channel2.NRx2EnvelopeAddMode) {\n            volume += 1;\n          } else {\n            volume -= 1;\n          }\n\n          // Don't allow the volume to go above 4 bits.\n          volume = volume & 0x0f;\n\n          // Check if we are below the max\n          if (volume < 15) {\n            Channel2.volume = volume;\n          } else {\n            Channel2.isEnvelopeAutomaticUpdating = false;\n          }\n        }\n      }\n    }\n    Channel2.envelopeCounter = envelopeCounter;\n  }\n\n  static setFrequency(frequency: i32): void {\n    // Get the high and low bits\n    let passedFrequencyHighBits = frequency >> 8;\n    let passedFrequencyLowBits = frequency & 0xff;\n\n    // Get the new register 4\n    let register4 = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx4);\n    // Knock off lower 3 bits, and Or on our high bits\n    let newRegister4 = register4 & 0xf8;\n    newRegister4 = newRegister4 | passedFrequencyHighBits;\n\n    // Set the registers\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx3, passedFrequencyLowBits);\n    eightBitStoreIntoGBMemory(Channel2.memoryLocationNRx4, newRegister4);\n\n    // Save the frequency for ourselves without triggering memory traps\n    Channel2.NRx3FrequencyLSB = passedFrequencyLowBits;\n    Channel2.NRx4FrequencyMSB = passedFrequencyHighBits;\n    Channel2.frequency = (passedFrequencyHighBits << 8) | passedFrequencyLowBits;\n  }\n  // Done!\n}\n","// NOTE: Tons of Copy-pasta btween channels, because Classes cannot be instantiated yet in assemblyscript\n\n// How to Search for similar things in binjgb\n// Wave channel trigger : APU_NR34_ADDR\n// Wave Channel getSample : update_wave\n\n// Wave Channel\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Wave_Channel\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Sound } from './sound';\nimport { Cpu } from '../cpu/index';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { checkBitOnByte, log } from '../helpers/index';\nimport { i32Portable } from '../portable/portable';\n\nexport class Channel3 {\n  // Cycle Counter for our sound accumulator\n  static cycleCounter: i32 = 0;\n\n  // Max Length of our Length Load\n  static MAX_LENGTH: i32 = 256;\n\n  // Voluntary Wave channel with 32 4-bit programmable samples, played in sequence.\n  // NR30 -> Sound on/off (R/W)\n  static readonly memoryLocationNRx0: i32 = 0xff1a;\n  // E--- ---- DAC power\n  static updateNRx0(value: i32): void {\n    let isDacEnabled = checkBitOnByte(7, value);\n\n    // Sample buffer reset to zero when powered on\n    if (!Channel3.isDacEnabled && isDacEnabled) {\n      Channel3.sampleBuffer = 0x00;\n    }\n\n    Channel3.isDacEnabled = isDacEnabled;\n\n    // Blargg length test\n    // Disabling DAC should disable channel immediately\n    if (!isDacEnabled) {\n      Channel3.isEnabled = isDacEnabled;\n    }\n  }\n\n  // NR31 -> Sound length (R/W)\n  static readonly memoryLocationNRx1: i32 = 0xff1b;\n  // LLLL LLLL Length load (256-L)\n  static NRx1LengthLoad: i32 = 0;\n  static updateNRx1(value: i32): void {\n    Channel3.NRx1LengthLoad = value;\n\n    // Also need to set our length counter. Taken from the old, setChannelLengthCounter\n    // Channel length is determined by 64 (or 256 if channel 3), - the length load\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n    // Note, this will be different for channel 3\n    // Supposed to be 256, so subtracting 255 and then adding 1 if that makes sense\n    Channel3.lengthCounter = Channel3.MAX_LENGTH - Channel3.NRx1LengthLoad;\n  }\n\n  // NR32 -> Select ouput level (R/W)\n  static readonly memoryLocationNRx2: i32 = 0xff1c;\n  // -VV- ---- Volume code (00=0%, 01=100%, 10=50%, 11=25%)\n  static NRx2VolumeCode: i32 = 0;\n  static updateNRx2(value: i32): void {\n    Channel3.NRx2VolumeCode = (value >> 5) & 0x0f;\n  }\n\n  // NR33 -> Frequency lower data (W)\n  static readonly memoryLocationNRx3: i32 = 0xff1d;\n  // FFFF FFFF Frequency LSB\n  static NRx3FrequencyLSB: i32 = 0;\n  static updateNRx3(value: i32): void {\n    Channel3.NRx3FrequencyLSB = value;\n\n    // Update Channel Frequency\n    Channel3.frequency = (Channel3.NRx4FrequencyMSB << 8) | value;\n  }\n\n  // NR34 -> Frequency higher data (R/W)\n  static readonly memoryLocationNRx4: i32 = 0xff1e;\n  // TL-- -FFF Trigger, Length enable, Frequency MSB\n  static NRx4LengthEnabled: boolean = false;\n  static NRx4FrequencyMSB: i32 = 0;\n  static updateNRx4(value: i32): void {\n    // Handle our frequency\n    // Must be done first for our upcoming trigger\n    // To correctly reset timing\n    let frequencyMSB = value & 0x07;\n    Channel3.NRx4FrequencyMSB = frequencyMSB;\n    Channel3.frequency = (frequencyMSB << 8) | Channel3.NRx3FrequencyLSB;\n\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    // Also see blargg's cgb sound test\n    // Extra length clocking occurs when writing to NRx4,\n    // when the frame sequencer's next step is one that,\n    // doesn't clock the length counter.\n    let frameSequencer = Sound.frameSequencer;\n    let doesNextFrameSequencerUpdateLength = (frameSequencer & 1) === 1;\n    let isBeingLengthEnabled = false;\n    if (!doesNextFrameSequencerUpdateLength) {\n      // Check lengthEnable\n      isBeingLengthEnabled = !Channel3.NRx4LengthEnabled && checkBitOnByte(6, value);\n      if (Channel3.lengthCounter > 0 && isBeingLengthEnabled) {\n        Channel3.lengthCounter -= 1;\n\n        if (!checkBitOnByte(7, value) && Channel3.lengthCounter === 0) {\n          Channel3.isEnabled = false;\n        }\n      }\n    }\n\n    // Set the length enabled from the value\n    Channel3.NRx4LengthEnabled = checkBitOnByte(6, value);\n\n    // Trigger our channel, unfreeze length if frozen\n    // Triggers should happen after obscure behavior\n    // See test 11 for trigger\n    if (checkBitOnByte(7, value)) {\n      Channel3.trigger();\n\n      // When we trigger on the obscure behavior, and we reset the length Counter to max\n      // We need to clock\n      if (!doesNextFrameSequencerUpdateLength && Channel3.lengthCounter === Channel3.MAX_LENGTH && Channel3.NRx4LengthEnabled) {\n        Channel3.lengthCounter -= 1;\n      }\n    }\n  }\n\n  // Our wave table location\n  static readonly memoryLocationWaveTable: i32 = 0xff30;\n\n  // Channel Properties\n  static readonly channelNumber: i32 = 3;\n  static isEnabled: boolean = false;\n  static isDacEnabled: boolean = false;\n  static frequency: i32 = 0;\n  static frequencyTimer: i32 = 0x00;\n  static lengthCounter: i32 = 0x00;\n\n  // WaveTable Properties\n  static waveTablePosition: i32 = 0x00;\n  static volumeCode: i32 = 0x00;\n  static volumeCodeChanged: boolean = false;\n  static sampleBuffer: i32 = 0x00;\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 9;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    // Cycle Counter\n    store<i32>(getSaveStateMemoryOffset(0x00, Channel3.saveStateSlot), Channel3.cycleCounter);\n\n    // NRx0\n    // No NRx0 Properties\n\n    // NRx1\n    store<u16>(getSaveStateMemoryOffset(0x08, Channel3.saveStateSlot), <u16>Channel3.NRx1LengthLoad);\n\n    // NRx2\n    store<u8>(getSaveStateMemoryOffset(0x0a, Channel3.saveStateSlot), <u8>Channel3.NRx2VolumeCode);\n\n    // NRx3\n    store<u8>(getSaveStateMemoryOffset(0x0c, Channel3.saveStateSlot), <u8>Channel3.NRx3FrequencyLSB);\n\n    // NRx4\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0d, Channel3.saveStateSlot), Channel3.NRx4LengthEnabled);\n    store<u8>(getSaveStateMemoryOffset(0x0e, Channel3.saveStateSlot), <u8>Channel3.NRx4FrequencyMSB);\n\n    // Channel Properties\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0f, Channel3.saveStateSlot), Channel3.isEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x10, Channel3.saveStateSlot), Channel3.isDacEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x11, Channel3.saveStateSlot), Channel3.frequency);\n    store<i32>(getSaveStateMemoryOffset(0x15, Channel3.saveStateSlot), Channel3.frequencyTimer);\n    // No Envelope\n    store<i32>(getSaveStateMemoryOffset(0x19, Channel3.saveStateSlot), Channel3.lengthCounter);\n\n    // WaveTable Properties\n    store<i32>(getSaveStateMemoryOffset(0x21, Channel3.saveStateSlot), Channel3.waveTablePosition);\n    store<u8>(getSaveStateMemoryOffset(0x25, Channel3.saveStateSlot), Channel3.volumeCode);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x26, Channel3.saveStateSlot), Channel3.volumeCodeChanged);\n    store<i32>(getSaveStateMemoryOffset(0x27, Channel3.saveStateSlot), Channel3.sampleBuffer);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // Cycle Counter\n    Channel3.cycleCounter = load<i32>(getSaveStateMemoryOffset(0x00, Channel3.cycleCounter));\n\n    // NRx0\n    // No NRx0\n\n    // NRx1\n    Channel3.NRx1LengthLoad = load<u16>(getSaveStateMemoryOffset(0x08, Channel3.saveStateSlot));\n\n    // NRx2\n    Channel3.NRx2VolumeCode = load<u8>(getSaveStateMemoryOffset(0x0a, Channel3.saveStateSlot));\n\n    // NRx3\n    Channel3.NRx3FrequencyLSB = load<u8>(getSaveStateMemoryOffset(0x0c, Channel3.saveStateSlot));\n\n    // NRx4\n    Channel3.NRx4LengthEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0d, Channel3.saveStateSlot));\n    Channel3.NRx4FrequencyMSB = load<u8>(getSaveStateMemoryOffset(0x0e, Channel3.saveStateSlot));\n\n    // Channel Properties\n    Channel3.isEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0f, Channel3.saveStateSlot));\n    Channel3.isDacEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x10, Channel3.saveStateSlot));\n    Channel3.frequency = load<i32>(getSaveStateMemoryOffset(0x11, Channel3.saveStateSlot));\n    Channel3.frequencyTimer = load<i32>(getSaveStateMemoryOffset(0x15, Channel3.saveStateSlot));\n    // No Envelope\n    Channel3.lengthCounter = load<i32>(getSaveStateMemoryOffset(0x19, Channel3.saveStateSlot));\n\n    // Wave Table Properties\n    Channel3.waveTablePosition = load<i32>(getSaveStateMemoryOffset(0x21, Channel3.saveStateSlot));\n    Channel3.volumeCode = load<i32>(getSaveStateMemoryOffset(0x25, Channel3.saveStateSlot));\n    Channel3.volumeCodeChanged = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x26, Channel3.saveStateSlot));\n    Channel3.sampleBuffer = load<i32>(getSaveStateMemoryOffset(0x27, Channel3.saveStateSlot));\n  }\n\n  // Memory Read Trap\n  static handleWaveRamRead(): i32 {\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    // If the wave channel is enabled, accessing any byte from $FF30-$FF3F is equivalent to,\n    // accessing the current byte selected by the waveform position. Further, on the DMG accesses will only work in this manner,\n    // if made within a couple of clocks of the wave channel accessing wave RAM;\n    // if made at any other time, reads return $FF and writes have no effect.\n\n    // TODO: Handle DMG case\n\n    return readCurrentSampleByteFromWaveRam();\n  }\n\n  // Memory Write Trap\n  static handleWaveRamWrite(value: i32): void {\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    // If the wave channel is enabled, accessing any byte from $FF30-$FF3F is equivalent to,\n    // accessing the current byte selected by the waveform position. Further, on the DMG accesses will only work in this manner,\n    // if made within a couple of clocks of the wave channel accessing wave RAM;\n    // if made at any other time, reads return $FF and writes have no effect.\n\n    // Thus we want to write the value to the current sample position\n    // Will Find the position, and knock off any remainder\n    let positionIndexToAdd = i32Portable(Channel3.waveTablePosition >> 1);\n    let memoryLocationWaveSample = Channel3.memoryLocationWaveTable + positionIndexToAdd;\n\n    eightBitStoreIntoGBMemory(memoryLocationWaveSample, value);\n  }\n\n  static initialize(): void {\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx0, 0x7f);\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx1, 0xff);\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx2, 0x9f);\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx3, 0x00);\n    eightBitStoreIntoGBMemory(Channel3.memoryLocationNRx4, 0xb8);\n\n    // The volume code changed\n    Channel3.volumeCodeChanged = true;\n  }\n\n  // Function to get a sample using the cycle counter on the channel\n  static getSampleFromCycleCounter(): i32 {\n    let accumulatedCycles = Channel3.cycleCounter;\n    Channel3.cycleCounter = 0;\n    return Channel3.getSample(accumulatedCycles);\n  }\n\n  // Function to reset our timer, useful for GBC double speed mode\n  static resetTimer(): void {\n    let frequencyTimer = (2048 - Channel3.frequency) << 1;\n\n    // TODO: Ensure this is correct for GBC Double Speed Mode\n    Channel3.frequencyTimer = frequencyTimer << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  static getSample(numberOfCycles: i32): i32 {\n    // Check if we are enabled\n    if (!Channel3.isEnabled || !Channel3.isDacEnabled) {\n      // Return silence\n      // Since range from -15 - 15, or 0 to 30 for our unsigned\n      return 15;\n    }\n\n    // Get our volume code\n    // Need this to compute the sample\n    let volumeCode = Channel3.volumeCode;\n    if (Channel3.volumeCodeChanged) {\n      volumeCode = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx2);\n      volumeCode = volumeCode >> 5;\n      volumeCode = volumeCode & 0x0f;\n      Channel3.volumeCode = volumeCode;\n      Channel3.volumeCodeChanged = false;\n    }\n\n    // Get the current sample\n    let sample = getSampleFromSampleBufferForWaveTablePosition();\n\n    // Shift our sample and set our volume depending on the volume code\n    // Since we can't multiply by float, simply divide by 4, 2, 1\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Wave_Channel\n    let outputVolume = 0;\n    switch (volumeCode) {\n      case 0:\n        sample >>= 4;\n        break;\n      case 1:\n        // Dont Shift sample\n        outputVolume = 1;\n        break;\n      case 2:\n        sample >>= 1;\n        outputVolume = 2;\n        break;\n      default:\n        sample >>= 2;\n        outputVolume = 4;\n        break;\n    }\n\n    // Apply out output volume\n    sample = outputVolume > 0 ? sample / outputVolume : 0;\n    // Square Waves Can range from -15 - 15. Therefore simply add 15\n    sample += 15;\n\n    // Update the sample based on our timer\n    let frequencyTimer = Channel3.frequencyTimer;\n    frequencyTimer -= numberOfCycles;\n    while (frequencyTimer <= 0) {\n      // Get the amount that overflowed so we don't drop cycles\n      let overflowAmount = abs(frequencyTimer);\n\n      // Reset our timer\n      // A wave channel's frequency timer period is set to (2048-frequency) * 2.\n      // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Wave_Channel\n      Channel3.resetTimer();\n      frequencyTimer = Channel3.frequencyTimer;\n      frequencyTimer -= overflowAmount;\n\n      // Update our sample buffer\n      advanceWavePositionAndSampleBuffer();\n    }\n\n    Channel3.frequencyTimer = frequencyTimer;\n\n    // Finally return the sample\n    return sample;\n  }\n\n  //http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Trigger_Event\n  static trigger(): void {\n    Channel3.isEnabled = true;\n    // Length counter maximum handled by write\n    if (Channel3.lengthCounter === 0) {\n      Channel3.lengthCounter = Channel3.MAX_LENGTH;\n    }\n\n    // Reset our timer\n    // A wave channel's frequency timer period is set to (2048-frequency)*2.\n    Channel3.resetTimer();\n\n    // Add some delay to our frequency timer\n    // So Honestly, lifted this from binjgb\n    // https://github.com/binji/binjgb/blob/68eb4b2f6d5d7a98d270e12c4b8ff065c07f5e94/src/emulator.c#L2625\n    // I have no clue why this is, but it passes 09-wave read while on.s\n    // blargg test.\n    // I think this has to do with obscure behavior?\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware\n    // When triggering the wave channel,\n    // the first sample to play is the previous one still in the high nibble of the sample buffer,\n    // and the next sample is the second nibble from the wave table.\n    // This is because it doesn't load the first byte on trigger like it \"should\".\n    // The first nibble from the wave table is thus not played until the waveform loops.\n    Channel3.frequencyTimer += 6;\n\n    // Reset our wave table position\n    Channel3.waveTablePosition = 0;\n\n    // Finally if DAC is off, channel is still disabled\n    if (!Channel3.isDacEnabled) {\n      Channel3.isEnabled = false;\n    }\n  }\n\n  // Function to determine if the current channel would update when getting the sample\n  // This is used to accumulate samples\n  static willChannelUpdate(numberOfCycles: i32): boolean {\n    //Increment our cycle counter\n    Channel3.cycleCounter += numberOfCycles;\n\n    // Dac enabled status cached by accumulator\n    return !(!Channel3.volumeCodeChanged && Channel3.frequencyTimer - Channel3.cycleCounter > 0);\n  }\n\n  static updateLength(): void {\n    let lengthCounter = Channel3.lengthCounter;\n    if (lengthCounter > 0 && Channel3.NRx4LengthEnabled) {\n      lengthCounter -= 1;\n    }\n\n    if (lengthCounter === 0) {\n      Channel3.isEnabled = false;\n    }\n    Channel3.lengthCounter = lengthCounter;\n  }\n}\n\n// Functions specific to wave memory\nfunction advanceWavePositionAndSampleBuffer(): void {\n  // Advance the wave table position, and loop back if needed\n  let waveTablePosition = Channel3.waveTablePosition;\n  waveTablePosition += 1;\n  while (waveTablePosition >= 32) {\n    waveTablePosition -= 32;\n  }\n  Channel3.waveTablePosition = waveTablePosition;\n\n  // Load the next sample byte from wave ram,\n  // into the sample buffer\n  Channel3.sampleBuffer = readCurrentSampleByteFromWaveRam();\n}\n\nfunction readCurrentSampleByteFromWaveRam(): i32 {\n  // Will Find the position, and knock off any remainder\n  let positionIndexToAdd = i32Portable(Channel3.waveTablePosition >> 1);\n  let memoryLocationWaveSample = Channel3.memoryLocationWaveTable + positionIndexToAdd;\n\n  return eightBitLoadFromGBMemory(memoryLocationWaveSample);\n}\n\nfunction getSampleFromSampleBufferForWaveTablePosition(): i32 {\n  let sample = Channel3.sampleBuffer;\n\n  // Need to grab the top or lower half for the correct sample\n  sample >>= (<i32>((Channel3.waveTablePosition & 1) === 0)) << 2;\n  sample &= 0x0f;\n\n  return sample;\n}\n","// NOTE: Tons of Copy-pasta btween channels, because Classes cannot be instantiated yet in assemblyscript\n\n// Noise Channel\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Noise_Channel\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Sound } from './sound';\nimport { Cpu } from '../cpu/index';\nimport { eightBitStoreIntoGBMemory, loadBooleanDirectlyFromWasmMemory, storeBooleanDirectlyToWasmMemory } from '../memory/index';\nimport { checkBitOnByte } from '../helpers/index';\n\nexport class Channel4 {\n  // Cycle Counter for our sound accumulator\n  static cycleCounter: i32 = 0;\n\n  // Max Length of our Length Load\n  static MAX_LENGTH: i32 = 64;\n\n  // Channel 4\n  // 'white noise' channel with volume envelope functions.\n\n  // Only used by register reading\n  static readonly memoryLocationNRx0: i32 = 0xff1f;\n\n  // NR41 -> Sound length (R/W)\n  static readonly memoryLocationNRx1: i32 = 0xff20;\n  // --LL LLLL Length load (64-L)\n  static NRx1LengthLoad: i32 = 0;\n  static updateNRx1(value: i32): void {\n    Channel4.NRx1LengthLoad = value & 0x3f;\n\n    // Also need to set our length counter. Taken from the old, setChannelLengthCounter\n    // Channel length is determined by 64 (or 256 if channel 3), - the length load\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n    // Note, this will be different for channel 3\n    Channel4.lengthCounter = Channel4.MAX_LENGTH - Channel4.NRx1LengthLoad;\n  }\n\n  // NR42 -> Volume Envelope (R/W)\n  static readonly memoryLocationNRx2: i32 = 0xff21;\n  // VVVV APPP Starting volume, Envelope add mode, period\n  static NRx2StartingVolume: i32 = 0;\n  static NRx2EnvelopeAddMode: boolean = false;\n  static NRx2EnvelopePeriod: i32 = 0;\n  static updateNRx2(value: i32): void {\n    // Handle \"Zombie Mode\" Obscure behavior\n    // https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    if (Channel4.isEnabled) {\n      // If the old envelope period was zero and the envelope is still doing automatic updates,\n      // volume is incremented by 1, otherwise if the envelope was in subtract mode,\n      // volume is incremented by 2.\n      // NOTE: However, from my testing, it ALWAYS increments by one. This was determined\n      // by my testing for prehistoric man\n      if (Channel4.NRx2EnvelopePeriod === 0 && Channel4.isEnvelopeAutomaticUpdating) {\n        // Volume can't be more than 4 bits\n        Channel4.volume = (Channel4.volume + 1) & 0x0f;\n      }\n\n      // If the mode was changed (add to subtract or subtract to add),\n      // volume is set to 16-volume. But volume cant be more than 4 bits\n      if (Channel4.NRx2EnvelopeAddMode !== checkBitOnByte(3, value)) {\n        Channel4.volume = (16 - Channel4.volume) & 0x0f;\n      }\n    }\n\n    Channel4.NRx2StartingVolume = (value >> 4) & 0x0f;\n    Channel4.NRx2EnvelopeAddMode = checkBitOnByte(3, value);\n    Channel4.NRx2EnvelopePeriod = value & 0x07;\n\n    // Also, get our channel is dac enabled\n    let isDacEnabled = (value & 0xf8) > 0;\n    Channel4.isDacEnabled = isDacEnabled;\n\n    // Blargg length test\n    // Disabling DAC should disable channel immediately\n    if (!isDacEnabled) {\n      Channel4.isEnabled = isDacEnabled;\n    }\n  }\n\n  // NR43 -> Polynomial Counter (R/W)\n  static readonly memoryLocationNRx3: i32 = 0xff22;\n  // SSSS WDDD Clock shift, Width mode of LFSR, Divisor code\n  static NRx3ClockShift: i32 = 0;\n  static NRx3WidthMode: boolean = false;\n  static NRx3DivisorCode: i32 = 0;\n  static updateNRx3(value: i32): void {\n    let divisorCode = value & 0x07;\n    Channel4.NRx3ClockShift = value >> 4;\n    Channel4.NRx3WidthMode = checkBitOnByte(3, value);\n    Channel4.NRx3DivisorCode = divisorCode;\n    // Also, get our divisor\n    divisorCode <<= 1;\n    if (divisorCode < 1) divisorCode = 1;\n    Channel4.divisor = divisorCode << 3;\n  }\n\n  // NR44 -> Trigger, Length Enable\n  static readonly memoryLocationNRx4: i32 = 0xff23;\n  // TL-- ---- Trigger, Length enable\n  static NRx4LengthEnabled: boolean = false;\n  static updateNRx4(value: i32): void {\n    // Obscure behavior\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Obscure_Behavior\n    // Also see blargg's cgb sound test\n    // Extra length clocking occurs when writing to NRx4,\n    // when the frame sequencer's next step is one that,\n    // doesn't clock the length counter.\n    let frameSequencer = Sound.frameSequencer;\n    let doesNextFrameSequencerUpdateLength = (frameSequencer & 1) === 1;\n    let isBeingLengthEnabled = !Channel4.NRx4LengthEnabled && checkBitOnByte(6, value);\n    if (!doesNextFrameSequencerUpdateLength) {\n      if (Channel4.lengthCounter > 0 && isBeingLengthEnabled) {\n        Channel4.lengthCounter -= 1;\n\n        if (!checkBitOnByte(7, value) && Channel4.lengthCounter === 0) {\n          Channel4.isEnabled = false;\n        }\n      }\n    }\n\n    // Set the length enabled from the value\n    Channel4.NRx4LengthEnabled = checkBitOnByte(6, value);\n\n    // Trigger out channel, unfreeze length if frozen\n    // Triggers should happen after obscure behavior\n    // See test 11 for trigger\n    if (checkBitOnByte(7, value)) {\n      Channel4.trigger();\n\n      // When we trigger on the obscure behavior, and we reset the length Counter to max\n      // We need to clock\n      if (!doesNextFrameSequencerUpdateLength && Channel4.lengthCounter === Channel4.MAX_LENGTH && Channel4.NRx4LengthEnabled) {\n        Channel4.lengthCounter -= 1;\n      }\n    }\n  }\n\n  // Channel Properties\n  static readonly channelNumber: i32 = 4;\n  static isEnabled: boolean = false;\n  static isDacEnabled: boolean = false;\n  static frequencyTimer: i32 = 0x00;\n  static envelopeCounter: i32 = 0x00;\n  static isEnvelopeAutomaticUpdating: boolean = false;\n  static lengthCounter: i32 = 0x00;\n  static volume: i32 = 0x00;\n  static divisor: i32 = 0;\n\n  // Noise properties\n  // NOTE: Is only 15 bits\n  static linearFeedbackShiftRegister: i32 = 0x00;\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 10;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    // Cycle Counter\n    store<i32>(getSaveStateMemoryOffset(0x00, Channel4.saveStateSlot), Channel4.cycleCounter);\n\n    // NRx0\n    // No NRx0 Properties\n\n    // NRx1\n    store<u16>(getSaveStateMemoryOffset(0x04, Channel4.saveStateSlot), <u16>Channel4.NRx1LengthLoad);\n\n    // NRx2\n    store<u8>(getSaveStateMemoryOffset(0x06, Channel4.saveStateSlot), <u8>Channel4.NRx2StartingVolume);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x07, Channel4.saveStateSlot), Channel4.NRx2EnvelopeAddMode);\n    store<u8>(getSaveStateMemoryOffset(0x08, Channel4.saveStateSlot), <u8>Channel4.NRx2EnvelopePeriod);\n\n    // NRx3\n    store<u8>(getSaveStateMemoryOffset(0x09, Channel4.saveStateSlot), <u8>Channel4.NRx3ClockShift);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0a, Channel4.saveStateSlot), Channel4.NRx3WidthMode);\n    store<u8>(getSaveStateMemoryOffset(0x0b, Channel4.saveStateSlot), <u8>Channel4.NRx3DivisorCode);\n\n    // NRx4\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0d, Channel4.saveStateSlot), Channel4.NRx4LengthEnabled);\n\n    // Channel Properties\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0f, Channel4.saveStateSlot), Channel4.isEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x10, Channel4.saveStateSlot), Channel4.isDacEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x15, Channel4.saveStateSlot), Channel4.frequencyTimer);\n    store<i32>(getSaveStateMemoryOffset(0x19, Channel4.saveStateSlot), Channel4.envelopeCounter);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x1d, Channel4.saveStateSlot), Channel4.isEnvelopeAutomaticUpdating);\n    store<i32>(getSaveStateMemoryOffset(0x1e, Channel4.saveStateSlot), Channel4.lengthCounter);\n    store<i32>(getSaveStateMemoryOffset(0x22, Channel4.saveStateSlot), Channel4.volume);\n\n    // LSFR\n    store<u16>(getSaveStateMemoryOffset(0x26, Channel4.saveStateSlot), <u16>Channel4.linearFeedbackShiftRegister);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // Cycle Counter\n    Channel4.cycleCounter = load<i32>(getSaveStateMemoryOffset(0x00, Channel4.cycleCounter));\n\n    // NRx0\n    // No NRx0\n\n    // NRx1\n    Channel4.NRx1LengthLoad = load<u8>(getSaveStateMemoryOffset(0x04, Channel4.saveStateSlot));\n\n    // NRx2\n    Channel4.NRx2StartingVolume = load<u8>(getSaveStateMemoryOffset(0x06, Channel4.saveStateSlot));\n    Channel4.NRx2EnvelopeAddMode = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x07, Channel4.saveStateSlot));\n    Channel4.NRx2EnvelopePeriod = load<u8>(getSaveStateMemoryOffset(0x08, Channel4.saveStateSlot));\n\n    // NRx3\n    Channel4.NRx3ClockShift = load<u8>(getSaveStateMemoryOffset(0x09, Channel4.saveStateSlot));\n    Channel4.NRx3WidthMode = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0a, Channel4.saveStateSlot));\n    Channel4.NRx3DivisorCode = load<u8>(getSaveStateMemoryOffset(0x0b, Channel4.saveStateSlot));\n\n    // NRx4\n    Channel4.NRx4LengthEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0d, Channel4.saveStateSlot));\n\n    // Channel Properties\n    Channel4.isEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0f, Channel4.saveStateSlot));\n    Channel4.isDacEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x10, Channel4.saveStateSlot));\n    Channel4.frequencyTimer = load<i32>(getSaveStateMemoryOffset(0x15, Channel4.saveStateSlot));\n    Channel4.envelopeCounter = load<i32>(getSaveStateMemoryOffset(0x19, Channel4.saveStateSlot));\n    Channel4.isEnvelopeAutomaticUpdating = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x1d, Channel4.saveStateSlot));\n    Channel4.lengthCounter = load<i32>(getSaveStateMemoryOffset(0x1e, Channel4.saveStateSlot));\n    Channel4.volume = load<i32>(getSaveStateMemoryOffset(0x22, Channel4.saveStateSlot));\n\n    // LSFR\n    Channel4.linearFeedbackShiftRegister = load<u16>(getSaveStateMemoryOffset(0x26, Channel4.saveStateSlot));\n  }\n\n  static initialize(): void {\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx1 - 1, 0xff);\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx1, 0xff);\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx2, 0x00);\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx3, 0x00);\n    eightBitStoreIntoGBMemory(Channel4.memoryLocationNRx4, 0xbf);\n  }\n\n  // Function to get a sample using the cycle counter on the channel\n  static getSampleFromCycleCounter(): i32 {\n    let accumulatedCycles = Channel4.cycleCounter;\n    Channel4.cycleCounter = 0;\n    return Channel4.getSample(accumulatedCycles);\n  }\n\n  static getSample(numberOfCycles: i32): i32 {\n    // Decrement our channel timer\n    let frequencyTimer = Channel4.frequencyTimer;\n    frequencyTimer -= numberOfCycles;\n\n    // TODO: This can't be a while loop to use up all the cycles,\n    // Since noise is psuedo random and the period can be anything\n    if (frequencyTimer <= 0) {\n      // Get the amount that overflowed so we don't drop cycles\n      let overflowAmount = abs(frequencyTimer);\n\n      // Reset our timer\n      frequencyTimer = Channel4.getNoiseChannelFrequencyPeriod();\n      frequencyTimer -= overflowAmount;\n\n      // Do some cool stuff with lfsr\n      // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Noise_Channel\n\n      // First XOR bit zero and one\n      let linearFeedbackShiftRegister = Channel4.linearFeedbackShiftRegister;\n      let lfsrBitZero = linearFeedbackShiftRegister & 0x01;\n      let lfsrBitOne = linearFeedbackShiftRegister >> 1;\n      lfsrBitOne = lfsrBitOne & 0x01;\n      let xorLfsrBitZeroOne = lfsrBitZero ^ lfsrBitOne;\n\n      // Shift all lsfr bits by one\n      linearFeedbackShiftRegister = linearFeedbackShiftRegister >> 1;\n\n      // Place the XOR result on bit 15\n      linearFeedbackShiftRegister = linearFeedbackShiftRegister | (xorLfsrBitZeroOne << 14);\n\n      // If the width mode is set, set xor on bit 6, and make lfsr 7 bit\n      if (Channel4.NRx3WidthMode) {\n        // Make 7 bit, by knocking off lower bits. Want to keeps bits 8 - 16, and then or on 7\n        linearFeedbackShiftRegister = linearFeedbackShiftRegister & ~0x40;\n        linearFeedbackShiftRegister = linearFeedbackShiftRegister | (xorLfsrBitZeroOne << 6);\n      }\n      Channel4.linearFeedbackShiftRegister = linearFeedbackShiftRegister;\n    }\n\n    // Make sure period never becomes negative\n    if (frequencyTimer < 0) {\n      frequencyTimer = 0;\n    }\n\n    Channel4.frequencyTimer = frequencyTimer;\n\n    // Get our ourput volume, set to zero for silence\n    let outputVolume = 0;\n\n    // Finally to set our output volume, the channel must be enabled,\n    // Our channel DAC must be enabled, and we must be in an active state\n    // Of our duty cycle\n    if (Channel4.isEnabled && Channel4.isDacEnabled) {\n      // Volume can't be more than 4 bits.\n      // Volume should never be more than 4 bits, but doing a check here\n      outputVolume = Channel4.volume & 0x0f;\n    } else {\n      // Return silence\n      // Since range from -15 - 15, or 0 to 30 for our unsigned\n      return 15;\n    }\n\n    // Declare our sample\n    let sample = 0;\n\n    // Wave form output is bit zero of lfsr, INVERTED\n    sample = !checkBitOnByte(0, Channel4.linearFeedbackShiftRegister) ? 1 : -1;\n    sample = sample * outputVolume;\n\n    // Noise Can range from -15 - 15. Therefore simply add 15\n    sample = sample + 15;\n    return <i32>sample;\n  }\n\n  //http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Trigger_Event\n  static trigger(): void {\n    Channel4.isEnabled = true;\n    // Length counter maximum handled by write\n    if (Channel4.lengthCounter === 0) {\n      Channel4.lengthCounter = Channel4.MAX_LENGTH;\n    }\n\n    // Reset our timers\n    Channel4.frequencyTimer = Channel4.getNoiseChannelFrequencyPeriod();\n\n    // The volume envelope and sweep timers treat a period of 0 as 8.\n    // Meaning, if the period is zero, set it to the max (8).\n    if (Channel4.NRx2EnvelopePeriod === 0) {\n      Channel4.envelopeCounter = 8;\n    } else {\n      Channel4.envelopeCounter = Channel4.NRx2EnvelopePeriod;\n    }\n    Channel4.isEnvelopeAutomaticUpdating = true;\n\n    Channel4.volume = Channel4.NRx2StartingVolume;\n\n    // Noise channel's LFSR bits are all set to 1.\n    Channel4.linearFeedbackShiftRegister = 0x7fff;\n\n    // Finally if DAC is off, channel is still disabled\n    if (!Channel4.isDacEnabled) {\n      Channel4.isEnabled = false;\n    }\n  }\n\n  // Function to determine if the current channel would update when getting the sample\n  // This is used to accumulate samples\n  static willChannelUpdate(numberOfCycles: i32): boolean {\n    //Increment our cycle counter\n    Channel4.cycleCounter += numberOfCycles;\n\n    // Dac enabled status cached by accumulator\n    return !(Channel4.frequencyTimer - Channel4.cycleCounter > 0);\n  }\n\n  static getNoiseChannelFrequencyPeriod(): i32 {\n    // Get our divisor from the divisor code, and shift by the clock shift\n    let response = Channel4.divisor << Channel4.NRx3ClockShift;\n    return response << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  static updateLength(): void {\n    let lengthCounter = Channel4.lengthCounter;\n    if (lengthCounter > 0 && Channel4.NRx4LengthEnabled) {\n      lengthCounter -= 1;\n    }\n\n    if (lengthCounter === 0) {\n      Channel4.isEnabled = false;\n    }\n    Channel4.lengthCounter = lengthCounter;\n  }\n\n  static updateEnvelope(): void {\n    let envelopeCounter = Channel4.envelopeCounter - 1;\n    if (envelopeCounter <= 0) {\n      // Reset back to the sweep period\n      // Obscure behavior\n      // Envelopes treat a period of 0 as 8 (They reset back to the max)\n      if (Channel4.NRx2EnvelopePeriod === 0) {\n        envelopeCounter = 8;\n      } else {\n        envelopeCounter = Channel4.NRx2EnvelopePeriod;\n\n        // When the timer generates a clock and the envelope period is NOT zero, a new volume is calculated\n        // NOTE: There is some weiirrdd obscure behavior where zero can equal 8, so watch out for that\n        if (envelopeCounter !== 0 && Channel4.isEnvelopeAutomaticUpdating) {\n          let volume = Channel4.volume;\n\n          // Increment the volume\n          if (Channel4.NRx2EnvelopeAddMode) {\n            volume += 1;\n          } else {\n            volume -= 1;\n          }\n\n          // Don't allow the volume to go above 4 bits.\n          volume = volume & 0x0f;\n\n          // Check if we are below the max\n          if (volume < 15) {\n            Channel4.volume = volume;\n          } else {\n            Channel4.isEnvelopeAutomaticUpdating = false;\n          }\n        }\n      }\n    }\n    Channel4.envelopeCounter = envelopeCounter;\n  }\n  // Done!\n}\n","import { Sound, mixChannelSamples, setLeftAndRightOutputForAudioQueue } from './sound';\nimport { Channel1 } from './channel1';\nimport { Channel2 } from './channel2';\nimport { Channel3 } from './channel3';\nimport { Channel4 } from './channel4';\nimport { i32Portable } from '../portable/portable';\nimport { AUDIO_BUFFER_LOCATION } from '../constants';\n\n// Another class simply for accumulating samples\n// Default everything to silence\nexport class SoundAccumulator {\n  static channel1Sample: i32 = 15;\n  static channel2Sample: i32 = 15;\n  static channel3Sample: i32 = 15;\n  static channel4Sample: i32 = 15;\n  static channel1DacEnabled: boolean = false;\n  static channel2DacEnabled: boolean = false;\n  static channel3DacEnabled: boolean = false;\n  static channel4DacEnabled: boolean = false;\n  static leftChannelSampleUnsignedByte: i32 = 127;\n  static rightChannelSampleUnsignedByte: i32 = 127;\n  static mixerVolumeChanged: boolean = false;\n  static mixerEnabledChanged: boolean = false;\n\n  // If a channel was updated, need to also track if we need to need to mix them again\n  static needToRemixSamples: boolean = false;\n}\n\n// Inlined because closure compiler inlines\nexport function initializeSoundAccumulator(): void {\n  SoundAccumulator.channel1Sample = 15;\n  SoundAccumulator.channel2Sample = 15;\n  SoundAccumulator.channel3Sample = 15;\n  SoundAccumulator.channel4Sample = 15;\n  SoundAccumulator.channel1DacEnabled = false;\n  SoundAccumulator.channel2DacEnabled = false;\n  SoundAccumulator.channel3DacEnabled = false;\n  SoundAccumulator.channel4DacEnabled = false;\n  SoundAccumulator.leftChannelSampleUnsignedByte = 127;\n  SoundAccumulator.rightChannelSampleUnsignedByte = 127;\n  SoundAccumulator.mixerVolumeChanged = true;\n  SoundAccumulator.mixerEnabledChanged = true;\n  SoundAccumulator.needToRemixSamples = false;\n}\n\n// Inlined because closure compiler inlines\nexport function accumulateSound(numberOfCycles: i32): void {\n  // Check if any of the individual channels will update\n  let channel1WillUpdate = Channel1.willChannelUpdate(numberOfCycles) || didChannelDacChange(Channel1.channelNumber);\n  let channel2WillUpdate = Channel2.willChannelUpdate(numberOfCycles) || didChannelDacChange(Channel2.channelNumber);\n  let channel3WillUpdate = Channel3.willChannelUpdate(numberOfCycles) || didChannelDacChange(Channel3.channelNumber);\n  let channel4WillUpdate = Channel4.willChannelUpdate(numberOfCycles) || didChannelDacChange(Channel4.channelNumber);\n\n  if (channel1WillUpdate) {\n    SoundAccumulator.channel1Sample = Channel1.getSampleFromCycleCounter();\n  }\n  if (channel2WillUpdate) {\n    SoundAccumulator.channel2Sample = Channel2.getSampleFromCycleCounter();\n  }\n  if (channel3WillUpdate) {\n    SoundAccumulator.channel3Sample = Channel3.getSampleFromCycleCounter();\n  }\n  if (channel4WillUpdate) {\n    SoundAccumulator.channel4Sample = Channel4.getSampleFromCycleCounter();\n  }\n\n  // If any channel updated, we need to re-mix our samples\n  if (channel1WillUpdate || channel2WillUpdate || channel3WillUpdate || channel4WillUpdate) {\n    SoundAccumulator.needToRemixSamples = true;\n  }\n\n  // Do Some downsampling magic\n  let downSampleCycleCounter = Sound.downSampleCycleCounter;\n  downSampleCycleCounter += numberOfCycles;\n  let maxDownSampleCycles = Sound.maxDownSampleCycles();\n  if (downSampleCycleCounter >= maxDownSampleCycles) {\n    // Reset the downsample counter\n    // Don't set to zero to catch overflowed cycles\n    downSampleCycleCounter -= maxDownSampleCycles;\n\n    if (SoundAccumulator.needToRemixSamples || SoundAccumulator.mixerVolumeChanged || SoundAccumulator.mixerEnabledChanged) {\n      mixChannelSamples(\n        SoundAccumulator.channel1Sample,\n        SoundAccumulator.channel2Sample,\n        SoundAccumulator.channel3Sample,\n        SoundAccumulator.channel4Sample\n      );\n    } else {\n      Sound.downSampleCycleCounter = downSampleCycleCounter;\n    }\n\n    // Finally Simply place the accumulated sample in memory\n    // Set our volumes in memory\n    // +1 so it can not be zero\n    setLeftAndRightOutputForAudioQueue(\n      SoundAccumulator.leftChannelSampleUnsignedByte + 1,\n      SoundAccumulator.rightChannelSampleUnsignedByte + 1,\n      AUDIO_BUFFER_LOCATION\n    );\n    let audioQueueIndex = Sound.audioQueueIndex + 1;\n    // Don't allow our audioQueueIndex to overflow into other parts of the wasmBoy memory map\n    // https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit#gid=0\n    // Not 0xFFFF because we need half of 64kb since we store left and right channel\n    let maxIndex = i32Portable(Sound.wasmBoyMemoryMaxBufferSize >> 1) - 1;\n    if (audioQueueIndex >= maxIndex) {\n      audioQueueIndex -= 1;\n    }\n    Sound.audioQueueIndex = audioQueueIndex;\n  }\n\n  Sound.downSampleCycleCounter = downSampleCycleCounter;\n}\n\n// Function used by SoundAccumulator to find out if a channel Dac Changed\nfunction didChannelDacChange(channelNumber: i32): boolean {\n  switch (channelNumber) {\n    case Channel1.channelNumber: {\n      let isDacEnabled = Channel1.isDacEnabled;\n      let channel1EnabledChanged = SoundAccumulator.channel1DacEnabled !== isDacEnabled;\n      SoundAccumulator.channel1DacEnabled = isDacEnabled;\n      return channel1EnabledChanged;\n    }\n    case Channel2.channelNumber: {\n      let isDacEnabled = Channel2.isDacEnabled;\n      let channel2EnabledChanged = SoundAccumulator.channel2DacEnabled !== isDacEnabled;\n      SoundAccumulator.channel2DacEnabled = isDacEnabled;\n      return channel2EnabledChanged;\n    }\n    case Channel3.channelNumber: {\n      let isDacEnabled = Channel3.isDacEnabled;\n      let channel3EnabledChanged = SoundAccumulator.channel3DacEnabled !== isDacEnabled;\n      SoundAccumulator.channel3DacEnabled = isDacEnabled;\n      return channel3EnabledChanged;\n    }\n    case Channel4.channelNumber: {\n      let isDacEnabled = Channel4.isDacEnabled;\n      let channel4EnabledChanged = SoundAccumulator.channel4DacEnabled !== isDacEnabled;\n      SoundAccumulator.channel4DacEnabled = isDacEnabled;\n      return channel4EnabledChanged;\n    }\n  }\n  return false;\n}\n","// https://emu-docs.org/Game%20Boy/gb_sound.txt\n// https://www.youtube.com/watch?v=HyzD8pNlpwI\n// https://gist.github.com/drhelius/3652407\n\n// For our wasm -> JS, we will be passing in our -1.0 to 1.0 volume\n// As an unsigned byte. Each channel will give 0 (representing -1.0), to\n// 30 (representing 1.0), and will be added together. in the fucntion\n// getSampleAsUnsignedByte() will do the conversion of getting the total\n// of all the channels, times the (mixer volume + 1), to give us an unsigned\n// byte from 0 (-1.0) to 254 (1.0)\nimport {\n  AUDIO_BUFFER_LOCATION,\n  CHANNEL_1_BUFFER_LOCATION,\n  CHANNEL_2_BUFFER_LOCATION,\n  CHANNEL_3_BUFFER_LOCATION,\n  CHANNEL_4_BUFFER_LOCATION\n} from '../constants';\nimport { getSaveStateMemoryOffset } from '../core';\nimport { SoundAccumulator, initializeSoundAccumulator, accumulateSound } from './accumulator';\nimport { Channel1 } from './channel1';\nimport { Channel2 } from './channel2';\nimport { Channel3 } from './channel3';\nimport { Channel4 } from './channel4';\nimport { Cpu } from '../cpu/index';\nimport { Config } from '../config';\nimport { eightBitStoreIntoGBMemory, loadBooleanDirectlyFromWasmMemory, storeBooleanDirectlyToWasmMemory } from '../memory/index';\nimport { checkBitOnByte, concatenateBytes, splitLowByte, splitHighByte, log } from '../helpers/index';\nimport { i32Portable } from '../portable/portable';\n\nexport class Sound {\n  // Current cycles\n  // This will be used for batch processing\n  // https://github.com/binji/binjgb/commit/e028f45e805bc0b0aa4697224a209f9ae514c954\n  // TODO: May Also need to do this for Reads\n  static currentCycles: i32 = 0;\n\n  // Number of cycles to run in each batch process\n  // This number should be in sync so that sound doesn't run too many cyles at once\n  // and does not exceed the minimum number of cyles for either down sampling, or\n  // How often we change the frame, or a channel's update process\n  // Number of cycles is 87, because:\n  // Number of cycles before downsampling a single sample\n  // TODO: Find out how to make this number bigger\n  // Or, don't call this in syncCycles, and make the lib responsible.\n  static batchProcessCycles(): i32 {\n    // return Cpu.GBCDoubleSpeed ? 174 : 87;\n    return 87 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // Channel control / On-OFF / Volume (RW)\n  static readonly memoryLocationNR50: i32 = 0xff24;\n  static NR50LeftMixerVolume: i32 = 0;\n  static NR50RightMixerVolume: i32 = 0;\n  static updateNR50(value: i32): void {\n    Sound.NR50LeftMixerVolume = (value >> 4) & 0x07;\n    Sound.NR50RightMixerVolume = value & 0x07;\n  }\n\n  // 0xFF25 selects which output each channel goes to, Referred to as NR51\n  static readonly memoryLocationNR51: i32 = 0xff25;\n  static NR51IsChannel1EnabledOnLeftOutput: boolean = true;\n  static NR51IsChannel2EnabledOnLeftOutput: boolean = true;\n  static NR51IsChannel3EnabledOnLeftOutput: boolean = true;\n  static NR51IsChannel4EnabledOnLeftOutput: boolean = true;\n  static NR51IsChannel1EnabledOnRightOutput: boolean = true;\n  static NR51IsChannel2EnabledOnRightOutput: boolean = true;\n  static NR51IsChannel3EnabledOnRightOutput: boolean = true;\n  static NR51IsChannel4EnabledOnRightOutput: boolean = true;\n  static updateNR51(value: i32): void {\n    Sound.NR51IsChannel4EnabledOnLeftOutput = checkBitOnByte(7, value);\n    Sound.NR51IsChannel3EnabledOnLeftOutput = checkBitOnByte(6, value);\n    Sound.NR51IsChannel2EnabledOnLeftOutput = checkBitOnByte(5, value);\n    Sound.NR51IsChannel1EnabledOnLeftOutput = checkBitOnByte(4, value);\n    Sound.NR51IsChannel4EnabledOnRightOutput = checkBitOnByte(3, value);\n    Sound.NR51IsChannel3EnabledOnRightOutput = checkBitOnByte(2, value);\n    Sound.NR51IsChannel2EnabledOnRightOutput = checkBitOnByte(1, value);\n    Sound.NR51IsChannel1EnabledOnRightOutput = checkBitOnByte(0, value);\n  }\n\n  // Sound on/off\n  static readonly memoryLocationNR52: i32 = 0xff26;\n  static NR52IsSoundEnabled: boolean = true;\n  static updateNR52(value: i32): void {\n    Sound.NR52IsSoundEnabled = checkBitOnByte(7, value);\n  }\n\n  // $FF30 -- $FF3F is the load register space for the 4-bit samples for channel 3\n  static readonly memoryLocationChannel3LoadRegisterStart: i32 = 0xff30;\n\n  // Need to count how often we need to increment our frame sequencer\n  // Which you can read about below\n  static frameSequenceCycleCounter: i32 = 0x0000;\n  static maxFrameSequenceCycles(): i32 {\n    // return Cpu.GBCDoubleSpeed ? 16384 : 8192;\n    return 8192 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // Frame sequencer controls what should be updated and and ticked\n  // Every time the sound is updated :) It is updated everytime the\n  // Cycle counter reaches the max cycle\n  static frameSequencer: i32 = 0x00;\n\n  // Also need to downsample our audio to average audio qualty\n  // https://www.reddit.com/r/EmuDev/comments/5gkwi5/gb_apu_sound_emulation/\n  // Want to do 44100hz, so CpuRate / Sound Rate, 4194304 / 44100 ~ 91 cycles\n  static downSampleCycleCounter: i32 = 0x00;\n  static sampleRate: i32 = 44100;\n  static maxDownSampleCycles(): i32 {\n    return Cpu.CLOCK_SPEED() / Sound.sampleRate;\n  }\n\n  // Our current sample number we are passing back to the wasmboy memory map\n  // Found that a static number of samples doesn't work well on mobile\n  // Will just update the queue index, grab as much as we can whenever we need more audio, then reset\n  // NOTE: Giving a really large sample rate gives more latency, but less pops!\n  //static readonly MAX_NUMBER_OF_SAMPLES: i32 = 4096;\n  static audioQueueIndex: i32 = 0x0000;\n  static wasmBoyMemoryMaxBufferSize: i32 = 0x20000;\n\n  // Save States\n  static readonly saveStateSlot: i32 = 6;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    // NR50\n    store<i32>(getSaveStateMemoryOffset(0x00, Sound.saveStateSlot), Sound.NR50LeftMixerVolume);\n    store<i32>(getSaveStateMemoryOffset(0x04, Sound.saveStateSlot), Sound.NR50RightMixerVolume);\n\n    // NR51\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x08, Sound.saveStateSlot), Sound.NR51IsChannel1EnabledOnLeftOutput);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x09, Sound.saveStateSlot), Sound.NR51IsChannel2EnabledOnLeftOutput);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0a, Sound.saveStateSlot), Sound.NR51IsChannel3EnabledOnLeftOutput);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0b, Sound.saveStateSlot), Sound.NR51IsChannel4EnabledOnLeftOutput);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0c, Sound.saveStateSlot), Sound.NR51IsChannel1EnabledOnRightOutput);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0d, Sound.saveStateSlot), Sound.NR51IsChannel2EnabledOnRightOutput);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0e, Sound.saveStateSlot), Sound.NR51IsChannel3EnabledOnRightOutput);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0f, Sound.saveStateSlot), Sound.NR51IsChannel4EnabledOnRightOutput);\n\n    // NR52\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x10, Sound.saveStateSlot), Sound.NR52IsSoundEnabled);\n\n    // Frame Sequencer\n    store<i32>(getSaveStateMemoryOffset(0x11, Sound.saveStateSlot), Sound.frameSequenceCycleCounter);\n    store<u8>(getSaveStateMemoryOffset(0x16, Sound.saveStateSlot), Sound.frameSequencer);\n\n    // Down Sampler\n    store<u8>(getSaveStateMemoryOffset(0x17, Sound.saveStateSlot), Sound.downSampleCycleCounter);\n\n    // Sound Accumulator\n    store<u8>(getSaveStateMemoryOffset(0x18, Sound.saveStateSlot), SoundAccumulator.channel1Sample);\n    store<u8>(getSaveStateMemoryOffset(0x19, Sound.saveStateSlot), SoundAccumulator.channel2Sample);\n    store<u8>(getSaveStateMemoryOffset(0x1a, Sound.saveStateSlot), SoundAccumulator.channel3Sample);\n    store<u8>(getSaveStateMemoryOffset(0x1b, Sound.saveStateSlot), SoundAccumulator.channel4Sample);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x1c, Sound.saveStateSlot), SoundAccumulator.channel1DacEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x1d, Sound.saveStateSlot), SoundAccumulator.channel2DacEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x1e, Sound.saveStateSlot), SoundAccumulator.channel3DacEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x1f, Sound.saveStateSlot), SoundAccumulator.channel4DacEnabled);\n    store<u8>(getSaveStateMemoryOffset(0x20, Sound.saveStateSlot), SoundAccumulator.leftChannelSampleUnsignedByte);\n    store<u8>(getSaveStateMemoryOffset(0x21, Sound.saveStateSlot), SoundAccumulator.rightChannelSampleUnsignedByte);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x22, Sound.saveStateSlot), SoundAccumulator.mixerVolumeChanged);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x23, Sound.saveStateSlot), SoundAccumulator.mixerEnabledChanged);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // NR50\n    Sound.NR50LeftMixerVolume = load<i32>(getSaveStateMemoryOffset(0x00, Sound.saveStateSlot));\n    Sound.NR50RightMixerVolume = load<i32>(getSaveStateMemoryOffset(0x04, Sound.saveStateSlot));\n\n    // NR51\n    Sound.NR51IsChannel1EnabledOnLeftOutput = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x08, Sound.saveStateSlot));\n    Sound.NR51IsChannel2EnabledOnLeftOutput = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x09, Sound.saveStateSlot));\n    Sound.NR51IsChannel3EnabledOnLeftOutput = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0a, Sound.saveStateSlot));\n    Sound.NR51IsChannel4EnabledOnLeftOutput = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0b, Sound.saveStateSlot));\n    Sound.NR51IsChannel1EnabledOnRightOutput = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0c, Sound.saveStateSlot));\n    Sound.NR51IsChannel2EnabledOnRightOutput = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0d, Sound.saveStateSlot));\n    Sound.NR51IsChannel3EnabledOnRightOutput = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0e, Sound.saveStateSlot));\n    Sound.NR51IsChannel4EnabledOnRightOutput = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0f, Sound.saveStateSlot));\n\n    // NR52\n    Sound.NR52IsSoundEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x10, Sound.saveStateSlot));\n\n    // Frame Sequencer\n    Sound.frameSequenceCycleCounter = load<i32>(getSaveStateMemoryOffset(0x11, Sound.saveStateSlot));\n    Sound.frameSequencer = load<u8>(getSaveStateMemoryOffset(0x16, Sound.saveStateSlot));\n\n    // DownSampler\n    Sound.downSampleCycleCounter = load<u8>(getSaveStateMemoryOffset(0x17, Sound.saveStateSlot));\n\n    // Sound Accumulator\n    SoundAccumulator.channel1Sample = load<u8>(getSaveStateMemoryOffset(0x18, Sound.saveStateSlot));\n    SoundAccumulator.channel2Sample = load<u8>(getSaveStateMemoryOffset(0x19, Sound.saveStateSlot));\n    SoundAccumulator.channel3Sample = load<u8>(getSaveStateMemoryOffset(0x1a, Sound.saveStateSlot));\n    SoundAccumulator.channel4Sample = load<u8>(getSaveStateMemoryOffset(0x1b, Sound.saveStateSlot));\n    SoundAccumulator.channel1DacEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x1c, Sound.saveStateSlot));\n    SoundAccumulator.channel2DacEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x1d, Sound.saveStateSlot));\n    SoundAccumulator.channel3DacEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x1e, Sound.saveStateSlot));\n    SoundAccumulator.channel4DacEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x1f, Sound.saveStateSlot));\n    SoundAccumulator.leftChannelSampleUnsignedByte = load<u8>(getSaveStateMemoryOffset(0x20, Sound.saveStateSlot));\n    SoundAccumulator.rightChannelSampleUnsignedByte = load<u8>(getSaveStateMemoryOffset(0x21, Sound.saveStateSlot));\n    SoundAccumulator.mixerVolumeChanged = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x22, Sound.saveStateSlot));\n    SoundAccumulator.mixerEnabledChanged = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x23, Sound.saveStateSlot));\n\n    // Finally clear the audio buffer\n    clearAudioBuffer();\n  }\n}\n\n// Initialize sound registers\n// From: https://emu-docs.org/Game%20Boy/gb_sound.txt\n// Inlined because closure compiler inlines\nexport function initializeSound(): void {\n  // Reset Stateful variables\n  Sound.currentCycles = 0;\n  Sound.NR50LeftMixerVolume = 0;\n  Sound.NR50RightMixerVolume = 0;\n  Sound.NR51IsChannel1EnabledOnLeftOutput = true;\n  Sound.NR51IsChannel2EnabledOnLeftOutput = true;\n  Sound.NR51IsChannel3EnabledOnLeftOutput = true;\n  Sound.NR51IsChannel4EnabledOnLeftOutput = true;\n  Sound.NR51IsChannel1EnabledOnRightOutput = true;\n  Sound.NR51IsChannel2EnabledOnRightOutput = true;\n  Sound.NR51IsChannel3EnabledOnRightOutput = true;\n  Sound.NR51IsChannel4EnabledOnRightOutput = true;\n  Sound.NR52IsSoundEnabled = true;\n  Sound.frameSequenceCycleCounter = 0x0000;\n  Sound.downSampleCycleCounter = 0x00;\n  Sound.frameSequencer = 0x00;\n  Sound.audioQueueIndex = 0x0000;\n\n  // intiialize our channels\n  Channel1.initialize();\n  Channel2.initialize();\n  Channel3.initialize();\n  Channel4.initialize();\n\n  // Other Sound Registers\n  eightBitStoreIntoGBMemory(Sound.memoryLocationNR50, 0x77);\n  Sound.updateNR50(0x77);\n  eightBitStoreIntoGBMemory(Sound.memoryLocationNR51, 0xf3);\n  Sound.updateNR51(0xf3);\n  eightBitStoreIntoGBMemory(Sound.memoryLocationNR52, 0xf1);\n  Sound.updateNR52(0xf1);\n\n  // Override/reset some variables if the boot ROM is enabled\n  // For both GB and GBC\n  if (Cpu.BootROMEnabled) {\n    eightBitStoreIntoGBMemory(Sound.memoryLocationNR50, 0x00);\n    Sound.updateNR50(0x00);\n    eightBitStoreIntoGBMemory(Sound.memoryLocationNR51, 0x00);\n    Sound.updateNR51(0x00);\n    eightBitStoreIntoGBMemory(Sound.memoryLocationNR52, 0x70);\n    Sound.updateNR52(0x70);\n  }\n\n  initializeSoundAccumulator();\n}\n\n// Function to batch process our audio after we skipped so many cycles\nexport function batchProcessAudio(): void {\n  let batchProcessCycles = Sound.batchProcessCycles();\n  let currentCycles = Sound.currentCycles;\n  while (currentCycles >= batchProcessCycles) {\n    updateSound(batchProcessCycles);\n    currentCycles -= batchProcessCycles;\n  }\n  Sound.currentCycles = currentCycles;\n}\n\n// Function for updating sound\nexport function updateSound(numberOfCycles: i32): void {\n  // Check if our frameSequencer updated\n  let frameSequencerUpdated = updateFrameSequencer(numberOfCycles);\n\n  if (Config.audioAccumulateSamples && !frameSequencerUpdated) {\n    accumulateSound(numberOfCycles);\n  } else {\n    calculateSound(numberOfCycles);\n  }\n}\n\n// Funciton to get the current Audio Queue index\nexport function getNumberOfSamplesInAudioBuffer(): i32 {\n  return Sound.audioQueueIndex;\n}\n\n// Function to reset the audio queue\nexport function clearAudioBuffer(): void {\n  Sound.audioQueueIndex = 0;\n}\n\n// Inlined because closure compiler inlines\nfunction calculateSound(numberOfCycles: i32): void {\n  // Update all of our channels\n  // All samples will be returned as 0 to 30\n  // 0 being -1.0, and 30 being 1.0\n  // (see blurb at top)\n  let channel1Sample = i32Portable(Channel1.getSample(numberOfCycles));\n  let channel2Sample = i32Portable(Channel2.getSample(numberOfCycles));\n  let channel3Sample = i32Portable(Channel3.getSample(numberOfCycles));\n  let channel4Sample = i32Portable(Channel4.getSample(numberOfCycles));\n  // TODO: Allow individual channels to be muted\n  // let channel1Sample: i32 = 15;\n  // let channel2Sample: i32 = 15;\n  // let channel3Sample: i32 = 15;\n  // let channel4Sample: i32 = 15;\n\n  // Save the samples in the accumulator\n  SoundAccumulator.channel1Sample = channel1Sample;\n  SoundAccumulator.channel2Sample = channel2Sample;\n  SoundAccumulator.channel3Sample = channel3Sample;\n  SoundAccumulator.channel4Sample = channel4Sample;\n\n  // Do Some downsampling magic\n  let downSampleCycleCounter = Sound.downSampleCycleCounter + numberOfCycles;\n  if (downSampleCycleCounter >= Sound.maxDownSampleCycles()) {\n    // Reset the downsample counter\n    // Don't set to zero to catch overflowed cycles\n    downSampleCycleCounter -= Sound.maxDownSampleCycles();\n\n    // Mix our samples\n    let mixedSample = mixChannelSamples(channel1Sample, channel2Sample, channel3Sample, channel4Sample);\n    let leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n    let rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n\n    // Set our volumes in memory\n    // +1 so it can not be zero\n    setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, AUDIO_BUFFER_LOCATION);\n    if (Config.enableAudioDebugging) {\n      // Channel 1\n      mixedSample = mixChannelSamples(channel1Sample, 15, 15, 15);\n      leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n      rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n      setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, CHANNEL_1_BUFFER_LOCATION);\n\n      // Channel 2\n      mixedSample = mixChannelSamples(15, channel2Sample, 15, 15);\n      leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n      rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n      setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, CHANNEL_2_BUFFER_LOCATION);\n\n      // Channel 3\n      mixedSample = mixChannelSamples(15, 15, channel3Sample, 15);\n      leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n      rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n      setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, CHANNEL_3_BUFFER_LOCATION);\n\n      // Channel 4\n      mixedSample = mixChannelSamples(15, 15, 15, channel4Sample);\n      leftChannelSampleUnsignedByte = splitHighByte(mixedSample);\n      rightChannelSampleUnsignedByte = splitLowByte(mixedSample);\n      setLeftAndRightOutputForAudioQueue(leftChannelSampleUnsignedByte + 1, rightChannelSampleUnsignedByte + 1, CHANNEL_4_BUFFER_LOCATION);\n    }\n    let audioQueueIndex = Sound.audioQueueIndex + 1;\n\n    // Don't allow our audioQueueIndex to overflow into other parts of the wasmBoy memory map\n    // https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit#gid=0\n    // Not 0xFFFF because we need half of 64kb since we store left and right channel\n    let maxIndex = i32Portable(Sound.wasmBoyMemoryMaxBufferSize >> 1) - 1;\n    if (audioQueueIndex >= maxIndex) {\n      audioQueueIndex -= 1;\n    }\n    Sound.audioQueueIndex = audioQueueIndex;\n  }\n\n  Sound.downSampleCycleCounter = downSampleCycleCounter;\n}\n\n// Inlined because closure compiler inlines\nfunction updateFrameSequencer(numberOfCycles: i32): boolean {\n  // APU runs at 4194304 / 512\n  // Or Cpu.clockSpeed / 512\n  // Which means, we need to update once every 8192 cycles :)\n  let maxFrameSequenceCycles = Sound.maxFrameSequenceCycles();\n  let frameSequenceCycleCounter = Sound.frameSequenceCycleCounter + numberOfCycles;\n  if (frameSequenceCycleCounter >= maxFrameSequenceCycles) {\n    // Reset the frameSequenceCycleCounter\n    // Not setting to zero as we do not want to drop cycles\n    frameSequenceCycleCounter -= maxFrameSequenceCycles;\n    Sound.frameSequenceCycleCounter = frameSequenceCycleCounter;\n\n    // Update our frame sequencer\n    // https://gist.github.com/drhelius/3652407\n    let frameSequencer = (Sound.frameSequencer + 1) & 7;\n\n    switch (frameSequencer) {\n      case 0:\n        // Update Length on Channels\n        Channel1.updateLength();\n        Channel2.updateLength();\n        Channel3.updateLength();\n        Channel4.updateLength();\n        break;\n      /* Do Nothing on one */\n      case 2:\n        // Update Sweep and Length on Channels\n        Channel1.updateLength();\n        Channel2.updateLength();\n        Channel3.updateLength();\n        Channel4.updateLength();\n\n        Channel1.updateSweep();\n        break;\n      /* Do Nothing on three */\n      case 4:\n        // Update Length on Channels\n        Channel1.updateLength();\n        Channel2.updateLength();\n        Channel3.updateLength();\n        Channel4.updateLength();\n        break;\n      /* Do Nothing on five */\n      case 6:\n        // Update Sweep and Length on Channels\n        Channel1.updateLength();\n        Channel2.updateLength();\n        Channel3.updateLength();\n        Channel4.updateLength();\n\n        Channel1.updateSweep();\n        break;\n      case 7:\n        // Update Envelope on channels\n        Channel1.updateEnvelope();\n        Channel2.updateEnvelope();\n        Channel4.updateEnvelope();\n        break;\n    }\n\n    // Save our frame sequencer\n    Sound.frameSequencer = frameSequencer;\n    return true;\n  } else {\n    Sound.frameSequenceCycleCounter = frameSequenceCycleCounter;\n  }\n\n  return false;\n}\n\nexport function mixChannelSamples(\n  channel1Sample: i32 = 15,\n  channel2Sample: i32 = 15,\n  channel3Sample: i32 = 15,\n  channel4Sample: i32 = 15\n): i32 {\n  // Do Some Cool mixing\n  // NR50 FF24 ALLL BRRR Vin L enable, Left vol, Vin R enable, Right vol\n  // NR51 FF25 NW21 NW21 Left enables, Right enables\n  // NR52 FF26 P--- NW21 Power control/status, Channel length statuses\n  // NW21 = 4 bits on byte\n  // 3 -> Channel 4, 2 -> Channel 3, 1 -> Channel 2, 0 -> Channel 1\n\n  // Matt's Proccess\n  // I push out 1024 samples at a time and use 96000 hz sampling rate, so I guess i'm a bit less than one frame,\n  // but I let the queue fill up with 4 x 1024 samples before I start waiting for the audio\n\n  // TODO: Vin Mixing\n\n  SoundAccumulator.mixerVolumeChanged = false;\n\n  // Get our channel volume for left/right\n  let leftChannelSample = 0;\n  let rightChannelSample = 0;\n\n  // Find the sample for the left if enabled\n  // other wise add silence (15) for the channel\n  leftChannelSample += Sound.NR51IsChannel1EnabledOnLeftOutput ? channel1Sample : 15;\n  leftChannelSample += Sound.NR51IsChannel2EnabledOnLeftOutput ? channel2Sample : 15;\n  leftChannelSample += Sound.NR51IsChannel3EnabledOnLeftOutput ? channel3Sample : 15;\n  leftChannelSample += Sound.NR51IsChannel4EnabledOnLeftOutput ? channel4Sample : 15;\n\n  // Find the sample for the right if enabled\n  // other wise add silence (15) for the channel\n  rightChannelSample += Sound.NR51IsChannel1EnabledOnRightOutput ? channel1Sample : 15;\n  rightChannelSample += Sound.NR51IsChannel2EnabledOnRightOutput ? channel2Sample : 15;\n  rightChannelSample += Sound.NR51IsChannel3EnabledOnRightOutput ? channel3Sample : 15;\n  rightChannelSample += Sound.NR51IsChannel4EnabledOnRightOutput ? channel4Sample : 15;\n\n  // Update our accumulator\n  SoundAccumulator.mixerEnabledChanged = false;\n  SoundAccumulator.needToRemixSamples = false;\n\n  // Finally multiply our volumes by the mixer volume\n  // Mixer volume can be at most 7 + 1\n  // Can be at most 7, because we only have 3 bits, 111 = 7\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Mixer\n  // Done in the getSampleAsUnsignedByte(), since we are doing some weirdness there :)\n\n  // Convert our samples from unsigned 32 to unsigned byte\n  // Reason being, We want to be able to pass in wasm memory as usigned byte. Javascript will handle the conversion back\n  let leftChannelSampleUnsignedByte: i32 = getSampleAsUnsignedByte(leftChannelSample, Sound.NR50LeftMixerVolume + 1);\n  let rightChannelSampleUnsignedByte: i32 = getSampleAsUnsignedByte(rightChannelSample, Sound.NR50RightMixerVolume + 1);\n\n  // Save these samples in the accumulator\n  SoundAccumulator.leftChannelSampleUnsignedByte = leftChannelSampleUnsignedByte;\n  SoundAccumulator.rightChannelSampleUnsignedByte = rightChannelSampleUnsignedByte;\n\n  return concatenateBytes(leftChannelSampleUnsignedByte, rightChannelSampleUnsignedByte);\n}\n\nfunction getSampleAsUnsignedByte(sample: i32, mixerVolume: i32): i32 {\n  // If the sample is silence, return silence as unsigned byte\n  // Silence is common, and should be checked for performance\n  if (sample === 60) {\n    return 127;\n  }\n\n  // convert to a signed, precise scale of -6000 to 6000 (cheap way of -1.0 to 1.0)\n  // Multiply by the mixer volume fraction (to find the actual volume)\n  const precision = 100000;\n  let convertedSample = sample - 60;\n  convertedSample = convertedSample * precision;\n\n  // Multiply by the mixer volume fraction (to find the actual volume)\n  convertedSample = (convertedSample * mixerVolume) >> 3;\n\n  // Convert back to scale of 0 to 120\n  convertedSample = i32Portable(convertedSample / precision) + 60;\n\n  // Finally, convert to an unsigned byte scale\n  // With Four Channels (0 to 30) and no global volume. Max is 120\n  // max unsigned byte goal is 254 (see blurb at top).\n  // 120 / 254 should give the correct conversion\n  // For example, 120 / 254 = 0.47244094488188976\n  // Multiply by 1000 to increase the float into an int\n  // so, 120 * 1000 / (0.47244094488188976 * 1000) should give approximate answer for max mixer volume\n  let maxDivider = i32Portable((120 * precision) / 254);\n  convertedSample = i32Portable((convertedSample * precision) / maxDivider);\n\n  // Ensure we have an i32 and not a float for JS builds\n  convertedSample = i32Portable(convertedSample);\n\n  return convertedSample;\n}\n\n// Function to set our left and right channels at the correct queue index\nexport function setLeftAndRightOutputForAudioQueue(leftVolume: i32, rightVolume: i32, bufferLocation: i32): void {\n  // Get our stereo index\n  let audioQueueOffset = bufferLocation + (Sound.audioQueueIndex << 1);\n\n  // Store our volumes\n  // +1 that way we don't have empty data to ensure that the value is set\n  store<u8>(audioQueueOffset + 0, <u8>(leftVolume + 1));\n  store<u8>(audioQueueOffset + 1, <u8>(rightVolume + 1));\n}\n","import { Cpu } from '../cpu/index';\nimport { getSaveStateMemoryOffset } from '../core';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  sixteenBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { setBitOnByte, resetBitOnByte, checkBitOnByte } from '../helpers/index';\n\nexport class Interrupts {\n  static masterInterruptSwitch: boolean = false;\n  // According to mooneye, interrupts are not handled until AFTER\n  // Next instruction\n  // https://github.com/Gekkio/mooneye-gb/blob/master/docs/accuracy.markdown\n  static masterInterruptSwitchDelay: boolean = false;\n\n  // Biut position for each part of the interrupts HW registers\n  static readonly bitPositionVBlankInterrupt: i32 = 0;\n  static readonly bitPositionLcdInterrupt: i32 = 1;\n  static readonly bitPositionTimerInterrupt: i32 = 2;\n  static readonly bitPositionSerialInterrupt: i32 = 3;\n  static readonly bitPositionJoypadInterrupt: i32 = 4;\n\n  static readonly memoryLocationInterruptEnabled: i32 = 0xffff; // A.K.A interrupt Flag (IE)\n  // Cache which Interrupts are enabled\n  static interruptsEnabledValue: i32 = 0;\n  static isVBlankInterruptEnabled: boolean = false;\n  static isLcdInterruptEnabled: boolean = false;\n  static isTimerInterruptEnabled: boolean = false;\n  static isSerialInterruptEnabled: boolean = false;\n  static isJoypadInterruptEnabled: boolean = false;\n  static updateInterruptEnabled(value: i32): void {\n    Interrupts.isVBlankInterruptEnabled = checkBitOnByte(Interrupts.bitPositionVBlankInterrupt, value);\n    Interrupts.isLcdInterruptEnabled = checkBitOnByte(Interrupts.bitPositionLcdInterrupt, value);\n    Interrupts.isTimerInterruptEnabled = checkBitOnByte(Interrupts.bitPositionTimerInterrupt, value);\n    Interrupts.isSerialInterruptEnabled = checkBitOnByte(Interrupts.bitPositionSerialInterrupt, value);\n    Interrupts.isJoypadInterruptEnabled = checkBitOnByte(Interrupts.bitPositionJoypadInterrupt, value);\n\n    Interrupts.interruptsEnabledValue = value;\n  }\n\n  static readonly memoryLocationInterruptRequest: i32 = 0xff0f; // A.K.A interrupt Flag (IF)\n  // Cache which Interrupts are requested\n  static interruptsRequestedValue: i32 = 0;\n  static isVBlankInterruptRequested: boolean = false;\n  static isLcdInterruptRequested: boolean = false;\n  static isTimerInterruptRequested: boolean = false;\n  static isSerialInterruptRequested: boolean = false;\n  static isJoypadInterruptRequested: boolean = false;\n  static updateInterruptRequested(value: i32): void {\n    Interrupts.isVBlankInterruptRequested = checkBitOnByte(Interrupts.bitPositionVBlankInterrupt, value);\n    Interrupts.isLcdInterruptRequested = checkBitOnByte(Interrupts.bitPositionLcdInterrupt, value);\n    Interrupts.isTimerInterruptRequested = checkBitOnByte(Interrupts.bitPositionTimerInterrupt, value);\n    Interrupts.isSerialInterruptRequested = checkBitOnByte(Interrupts.bitPositionSerialInterrupt, value);\n    Interrupts.isJoypadInterruptRequested = checkBitOnByte(Interrupts.bitPositionJoypadInterrupt, value);\n\n    Interrupts.interruptsRequestedValue = value;\n  }\n\n  // Function to return if we have any pending interrupts\n  static areInterruptsPending(): boolean {\n    return (Interrupts.interruptsRequestedValue & Interrupts.interruptsEnabledValue & 0x1f) > 0;\n  }\n\n  // Save States\n  static readonly saveStateSlot: i32 = 2;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    // Interrupt Master Interrupt Switch\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x00, Interrupts.saveStateSlot), Interrupts.masterInterruptSwitch);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x01, Interrupts.saveStateSlot), Interrupts.masterInterruptSwitchDelay);\n\n    // Interrupt Enabled\n    store<u8>(getSaveStateMemoryOffset(0x10, Interrupts.saveStateSlot), <u8>Interrupts.interruptsEnabledValue);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x11, Interrupts.saveStateSlot), Interrupts.isVBlankInterruptEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x12, Interrupts.saveStateSlot), Interrupts.isLcdInterruptEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x13, Interrupts.saveStateSlot), Interrupts.isTimerInterruptEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x14, Interrupts.saveStateSlot), Interrupts.isSerialInterruptEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x15, Interrupts.saveStateSlot), Interrupts.isJoypadInterruptEnabled);\n\n    // Interrupt Request\n    store<u8>(getSaveStateMemoryOffset(0x20, Interrupts.saveStateSlot), <u8>Interrupts.interruptsRequestedValue);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x21, Interrupts.saveStateSlot), Interrupts.isVBlankInterruptRequested);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x22, Interrupts.saveStateSlot), Interrupts.isLcdInterruptRequested);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x23, Interrupts.saveStateSlot), Interrupts.isTimerInterruptRequested);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x24, Interrupts.saveStateSlot), Interrupts.isSerialInterruptRequested);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x25, Interrupts.saveStateSlot), Interrupts.isJoypadInterruptRequested);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // Interrupt Master Interrupt Switch\n    Interrupts.masterInterruptSwitch = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x00, Interrupts.saveStateSlot));\n    Interrupts.masterInterruptSwitchDelay = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x01, Interrupts.saveStateSlot));\n\n    // Interrupt Enabled\n    Interrupts.interruptsEnabledValue = load<u8>(getSaveStateMemoryOffset(0x10, Interrupts.saveStateSlot));\n    Interrupts.isVBlankInterruptEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x11, Interrupts.saveStateSlot));\n    Interrupts.isLcdInterruptEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x12, Interrupts.saveStateSlot));\n    Interrupts.isTimerInterruptEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x13, Interrupts.saveStateSlot));\n    Interrupts.isSerialInterruptEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x14, Interrupts.saveStateSlot));\n    Interrupts.isJoypadInterruptEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x15, Interrupts.saveStateSlot));\n\n    // Interrupt Request\n    Interrupts.interruptsRequestedValue = load<u8>(getSaveStateMemoryOffset(0x20, Interrupts.saveStateSlot));\n    Interrupts.isVBlankInterruptRequested = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x21, Interrupts.saveStateSlot));\n    Interrupts.isLcdInterruptRequested = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x22, Interrupts.saveStateSlot));\n    Interrupts.isTimerInterruptRequested = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x23, Interrupts.saveStateSlot));\n    Interrupts.isSerialInterruptRequested = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x24, Interrupts.saveStateSlot));\n    Interrupts.isJoypadInterruptRequested = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x25, Interrupts.saveStateSlot));\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function initializeInterrupts(): void {\n  // Values from BGB\n\n  // IE\n  Interrupts.updateInterruptEnabled(0x00);\n  eightBitStoreIntoGBMemory(Interrupts.memoryLocationInterruptEnabled, Interrupts.interruptsEnabledValue);\n\n  // IF\n  Interrupts.updateInterruptRequested(0xe1);\n  eightBitStoreIntoGBMemory(Interrupts.memoryLocationInterruptRequest, Interrupts.interruptsRequestedValue);\n}\n\n// NOTE: Interrupts should be handled before reading an opcode\n// Inlined because closure compiler inlines\nexport function checkInterrupts(): i32 {\n  // First check for our delay was enabled\n  if (Interrupts.masterInterruptSwitchDelay) {\n    Interrupts.masterInterruptSwitch = true;\n    Interrupts.masterInterruptSwitchDelay = false;\n  }\n\n  // Check if we have an enabled and requested interrupt\n  let isAnInterruptRequestedAndEnabledValue: i32 = Interrupts.interruptsEnabledValue & Interrupts.interruptsRequestedValue & 0x1f;\n\n  if (isAnInterruptRequestedAndEnabledValue > 0) {\n    // Boolean to track if interrupts were handled\n    // Interrupt handling requires 20 cycles\n    // https://github.com/Gekkio/mooneye-gb/blob/master/docs/accuracy.markdown#what-is-the-exact-timing-of-cpu-servicing-an-interrupt\n    let wasInterruptHandled: boolean = false;\n\n    // Service our interrupts, if we have the master switch enabled\n    // https://www.reddit.com/r/EmuDev/comments/5ie3k7/infinite_loop_trying_to_pass_blarggs_interrupt/\n    if (Interrupts.masterInterruptSwitch && !Cpu.isHaltNoJump) {\n      if (Interrupts.isVBlankInterruptEnabled && Interrupts.isVBlankInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionVBlankInterrupt);\n        wasInterruptHandled = true;\n      } else if (Interrupts.isLcdInterruptEnabled && Interrupts.isLcdInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionLcdInterrupt);\n        wasInterruptHandled = true;\n      } else if (Interrupts.isTimerInterruptEnabled && Interrupts.isTimerInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionTimerInterrupt);\n        wasInterruptHandled = true;\n      } else if (Interrupts.isSerialInterruptEnabled && Interrupts.isSerialInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionSerialInterrupt);\n        wasInterruptHandled = true;\n      } else if (Interrupts.isJoypadInterruptEnabled && Interrupts.isJoypadInterruptRequested) {\n        _handleInterrupt(Interrupts.bitPositionJoypadInterrupt);\n        wasInterruptHandled = true;\n      }\n    }\n\n    let interuptHandlerCycles: i32 = 0;\n    if (wasInterruptHandled) {\n      // Interrupt handling requires 20 cycles, TCAGBD\n      interuptHandlerCycles = 20;\n      if (Cpu.isHalted()) {\n        // If the CPU was halted, now is the time to un-halt\n        // Should be done here when the jump occurs according to:\n        // https://www.reddit.com/r/EmuDev/comments/6fmjch/gb_glitches_in_links_awakening_and_pok%C3%A9mon_gold/\n        Cpu.exitHaltAndStop();\n        interuptHandlerCycles += 4;\n      }\n    }\n\n    if (Cpu.isHalted()) {\n      Cpu.exitHaltAndStop();\n    }\n\n    return interuptHandlerCycles;\n  }\n\n  return 0;\n}\n\nfunction _handleInterrupt(bitPosition: i32): void {\n  // Disable the master switch\n  setInterrupts(false);\n\n  // Disable the bit on the interruptRequest\n  let interruptRequest = eightBitLoadFromGBMemory(Interrupts.memoryLocationInterruptRequest);\n  interruptRequest = resetBitOnByte(bitPosition, interruptRequest);\n  Interrupts.interruptsRequestedValue = interruptRequest;\n  eightBitStoreIntoGBMemory(Interrupts.memoryLocationInterruptRequest, interruptRequest);\n\n  // Push the programCounter onto the stacks\n  // Push the next instruction, not the halt itself (TCAGBD).\n  Cpu.stackPointer = Cpu.stackPointer - 2;\n  if (Cpu.isHalted()) {\n    // TODO: This breaks Pokemon Yellow, And OG Link's awakening. Find out why...\n    // sixteenBitStoreIntoGBMemory(Cpu.stackPointer, Cpu.programCounter + 1);\n    sixteenBitStoreIntoGBMemory(Cpu.stackPointer, Cpu.programCounter);\n  } else {\n    sixteenBitStoreIntoGBMemory(Cpu.stackPointer, Cpu.programCounter);\n  }\n\n  // Jump to the correct interrupt location\n  // Also piggyback off of the switch to reset our HW Register caching\n  // http://www.codeslinger.co.uk/pages/projects/gameboy/interupts.html\n  switch (bitPosition) {\n    case Interrupts.bitPositionVBlankInterrupt:\n      Interrupts.isVBlankInterruptRequested = false;\n      Cpu.programCounter = 0x40;\n      break;\n    case Interrupts.bitPositionLcdInterrupt:\n      Interrupts.isLcdInterruptRequested = false;\n      Cpu.programCounter = 0x48;\n      break;\n    case Interrupts.bitPositionTimerInterrupt:\n      Interrupts.isTimerInterruptRequested = false;\n      Cpu.programCounter = 0x50;\n      break;\n    case Interrupts.bitPositionSerialInterrupt:\n      Interrupts.isSerialInterruptRequested = false;\n      Cpu.programCounter = 0x58;\n      break;\n    case Interrupts.bitPositionJoypadInterrupt:\n      Interrupts.isJoypadInterruptRequested = false;\n      Cpu.programCounter = 0x60;\n      break;\n  }\n}\n\nfunction _requestInterrupt(bitPosition: i32): void {\n  let interruptRequest = eightBitLoadFromGBMemory(Interrupts.memoryLocationInterruptRequest);\n\n  // Pass to set the correct interrupt bit on interruptRequest\n  interruptRequest = setBitOnByte(bitPosition, interruptRequest);\n\n  Interrupts.interruptsRequestedValue = interruptRequest;\n\n  eightBitStoreIntoGBMemory(Interrupts.memoryLocationInterruptRequest, interruptRequest);\n}\n\nexport function setInterrupts(value: boolean): void {\n  // If we are enabling interrupts,\n  // we want to wait 4 cycles before enabling\n  if (value) {\n    Interrupts.masterInterruptSwitchDelay = true;\n  } else {\n    Interrupts.masterInterruptSwitch = false;\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function requestVBlankInterrupt(): void {\n  Interrupts.isVBlankInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionVBlankInterrupt);\n}\n\n// Inlined because closure compiler inlines\nexport function requestLcdInterrupt(): void {\n  Interrupts.isLcdInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionLcdInterrupt);\n}\n\n// Inlined because closure compiler inlines\nexport function requestTimerInterrupt(): void {\n  Interrupts.isTimerInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionTimerInterrupt);\n}\n\n// Inlined because closure compiler inlines\nexport function requestJoypadInterrupt(): void {\n  Interrupts.isJoypadInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionJoypadInterrupt);\n}\n\n// Inlined because closure compiler inlines\nexport function requestSerialInterrupt(): void {\n  Interrupts.isSerialInterruptRequested = true;\n  _requestInterrupt(Interrupts.bitPositionSerialInterrupt);\n}\n","import { getSaveStateMemoryOffset } from '../core';\nimport { Cpu } from '../cpu/index';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\nimport { requestTimerInterrupt } from '../interrupts/index';\nimport { checkBitOnByte } from '../helpers/index';\n\nexport class Timers {\n  // Current cycles\n  // This will be used for batch processing\n  static currentCycles: i32 = 0;\n\n  // Number of cycles to run in each batch process\n  static batchProcessCycles(): i32 {\n    return 256;\n  }\n\n  // Divider Register = DIV\n  // Divider Register is 16 bits.\n  // Divider Register when read is just the upper 8 bits\n  // But internally is used as the full 16\n  // Essentially dividerRegister is an always counting clock\n  // DIV Drives everything, it is the heart of the timer.\n  // All other timing registers base them selves relative to the DIV register\n  // Think of the div register as like a cycle counter :)\n  // DIV will increment TIMA, whenever there is a falling edge, see below for that.\n  static readonly memoryLocationDividerRegister: i32 = 0xff04; // DIV\n  static dividerRegister: i32 = 0;\n  static updateDividerRegister(): void {\n    let oldDividerRegister = Timers.dividerRegister;\n    Timers.dividerRegister = 0;\n    eightBitStoreIntoGBMemory(Timers.memoryLocationDividerRegister, 0);\n\n    if (Timers.timerEnabled && _checkDividerRegisterFallingEdgeDetector(oldDividerRegister, 0)) {\n      _incrementTimerCounter();\n    }\n  }\n\n  // timerCounter = TIMA\n  // TIMA is the actual counter.\n  // Whenever the DIV gets the falling edge, and other obscure cases,\n  // This is incremented. When this overflows, we need to fire an interrupt.\n  static readonly memoryLocationTimerCounter: i32 = 0xff05;\n  static timerCounter: i32 = 0;\n  static timerCounterOverflowDelay: boolean = false;\n  static timerCounterWasReset: boolean = false;\n  static timerCounterMask: i32 = 0;\n\n  static updateTimerCounter(value: i32): void {\n    if (Timers.timerEnabled) {\n      // From binjgb, dont write TIMA if we were just reset\n      if (Timers.timerCounterWasReset) {\n        return;\n      }\n\n      // Mooneye Test, tima_write_reloading\n      // Writing in this strange delay cycle, will cancel\n      // Both the interrupt and the TMA reload\n      if (Timers.timerCounterOverflowDelay) {\n        Timers.timerCounterOverflowDelay = false;\n      }\n    }\n\n    Timers.timerCounter = value;\n  }\n\n  // Timer Modulo = TMA\n  // TMA is what TIMA (Notice the I :p) is counting from, and TIMA will load\n  // Whenever TIMA overflow.\n  // For instance, we count like 1,2,3,4,5,6,7,8,9, and then overflow to 10.\n  // TMA would be like \"Hey, start counting from 5 whenever we reset\"\n  // Then we would be like 5,6,7,8,9...5,6,7,8,9...etc...\n  static readonly memoryLocationTimerModulo: i32 = 0xff06;\n  static timerModulo: i32 = 0;\n  static updateTimerModulo(value: i32): void {\n    Timers.timerModulo = value;\n\n    // Mooneye Test, tma_write_reloading\n    // Don't update if we were reloading\n    if (Timers.timerEnabled && Timers.timerCounterWasReset) {\n      Timers.timerCounter = value;\n      Timers.timerCounterWasReset = false;\n    }\n  }\n\n  // Timer Control = TAC\n  // TAC Says how fast we are counting.\n  // TAC controls which bit we are watching for the falling edge on the DIV register\n  // And whenever the bit has the falling edge, we increment TIMA (The thing counting).\n  // Therefore, depending on the value, we will either count faster or slower.\n  static readonly memoryLocationTimerControl: i32 = 0xff07;\n  // Bit 2    - Timer Stop  (0=Stop, 1=Start)\n  // Bits 1-0 - Input Clock Select\n  //            00:   4096 Hz    (~4194 Hz SGB) (1024 cycles)\n  //            01: 262144 Hz  (~268400 Hz SGB) (16 cycles)\n  //            10:  65536 Hz   (~67110 Hz SGB) (64 cycles)\n  //            11:  16384 Hz   (~16780 Hz SGB) (256 cycles)\n  static timerEnabled: boolean = false;\n  static timerInputClock: i32 = 0;\n\n  static updateTimerControl(value: i32): void {\n    // Get some initial values\n    let oldTimerEnabled = Timers.timerEnabled;\n    Timers.timerEnabled = checkBitOnByte(2, value);\n    let newTimerInputClock = value & 0x03;\n\n    // Do some obscure behavior for if we should increment TIMA\n    // This does the timer increments from rapid_toggle mooneye tests\n    if (!oldTimerEnabled) {\n      let oldTimerCounterMaskBit = _getTimerCounterMaskBit(Timers.timerInputClock);\n      let newTimerCounterMaskBit = _getTimerCounterMaskBit(newTimerInputClock);\n      let shouldIncrementTimerCounter = false;\n      let dividerRegister = Timers.dividerRegister;\n\n      if (Timers.timerEnabled) {\n        shouldIncrementTimerCounter = checkBitOnByte(oldTimerCounterMaskBit, dividerRegister);\n      } else {\n        shouldIncrementTimerCounter =\n          checkBitOnByte(oldTimerCounterMaskBit, dividerRegister) && checkBitOnByte(newTimerCounterMaskBit, dividerRegister);\n      }\n\n      if (shouldIncrementTimerCounter) {\n        _incrementTimerCounter();\n      }\n    }\n\n    Timers.timerInputClock = newTimerInputClock;\n  }\n\n  // Save States\n  static readonly saveStateSlot: i32 = 5;\n\n  // Function to save the state of the class\n  // TODO: Save state for new properties on Timers\n  static saveState(): void {\n    // Batch Processing\n    store<i32>(getSaveStateMemoryOffset(0x00, Timers.saveStateSlot), Timers.currentCycles);\n\n    // Divider Register\n    store<i32>(getSaveStateMemoryOffset(0x04, Timers.saveStateSlot), Timers.dividerRegister);\n\n    // Timer Counter\n    store<i32>(getSaveStateMemoryOffset(0x08, Timers.saveStateSlot), Timers.timerCounter);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0c, Timers.saveStateSlot), Timers.timerCounterOverflowDelay);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0d, Timers.saveStateSlot), Timers.timerCounterWasReset);\n    store<i32>(getSaveStateMemoryOffset(0x0e, Timers.saveStateSlot), Timers.timerCounterMask);\n\n    // Timer Modulo\n    store<i32>(getSaveStateMemoryOffset(0x12, Timers.saveStateSlot), Timers.timerModulo);\n\n    // Timer Control\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x16, Timers.saveStateSlot), Timers.timerEnabled);\n    store<i32>(getSaveStateMemoryOffset(0x17, Timers.saveStateSlot), Timers.timerInputClock);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // Batch Processing\n    Timers.currentCycles = load<i32>(getSaveStateMemoryOffset(0x00, Timers.saveStateSlot));\n\n    // Divider Register\n    Timers.dividerRegister = load<i32>(getSaveStateMemoryOffset(0x04, Timers.saveStateSlot));\n\n    // Timer Counter\n    Timers.timerCounter = load<i32>(getSaveStateMemoryOffset(0x08, Timers.saveStateSlot));\n    Timers.timerCounterOverflowDelay = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0c, Timers.saveStateSlot));\n    Timers.timerCounterWasReset = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0d, Timers.saveStateSlot));\n    Timers.timerCounterMask = load<i32>(getSaveStateMemoryOffset(0x0e, Timers.saveStateSlot));\n\n    // Timer Modulo\n    Timers.timerModulo = load<i32>(getSaveStateMemoryOffset(0x12, Timers.saveStateSlot));\n\n    // Timer Control\n    Timers.timerEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x16, Timers.saveStateSlot));\n    Timers.timerInputClock = load<i32>(getSaveStateMemoryOffset(0x17, Timers.saveStateSlot));\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function initializeTimers(): void {\n  // Reset stateful Variables\n  Timers.currentCycles = 0;\n  Timers.dividerRegister = 0;\n  Timers.timerCounter = 0;\n  Timers.timerModulo = 0;\n  Timers.timerEnabled = false;\n  Timers.timerInputClock = 0;\n  Timers.timerCounterOverflowDelay = false;\n  Timers.timerCounterWasReset = false;\n\n  if (Cpu.GBCEnabled) {\n    // DIV\n    eightBitStoreIntoGBMemory(0xff04, 0x1e);\n    Timers.dividerRegister = 0x1ea0;\n\n    // 0xFF05 -> 0xFF06 = 0x00\n\n    // TAC\n    eightBitStoreIntoGBMemory(0xff07, 0xf8);\n    Timers.timerInputClock = 0xf8;\n  } else {\n    // DIV\n    eightBitStoreIntoGBMemory(0xff04, 0xab);\n    Timers.dividerRegister = 0xabcc;\n\n    // 0xFF05 -> 0xFF06 = 0x00\n\n    // TAC\n    eightBitStoreIntoGBMemory(0xff07, 0xf8);\n    Timers.timerInputClock = 0xf8;\n  }\n\n  // Override/reset some variables if the boot ROM is enabled\n  if (Cpu.BootROMEnabled) {\n    if (Cpu.GBCEnabled) {\n      // GBC\n    } else {\n      // GB\n      // DIV\n      eightBitStoreIntoGBMemory(0xff04, 0x00);\n      Timers.dividerRegister = 0x0004;\n    }\n  }\n}\n\n// Batch Process Timers\n// Only checked on writes\n// Function to batch process our Timers after we skipped so many cycles\nexport function batchProcessTimers(): void {\n  // TODO: Did a timer rewrite, make a proper batch processing\n  // For timers\n  updateTimers(Timers.currentCycles);\n  Timers.currentCycles = 0;\n}\n\nexport function updateTimers(numberOfCycles: i32): void {\n  // Want to increment 4 cycles at a time like an actual GB would\n  let cyclesIncreased = 0;\n  while (cyclesIncreased < numberOfCycles) {\n    let oldDividerRegister = Timers.dividerRegister;\n    let curDividerRegister = oldDividerRegister;\n\n    cyclesIncreased += 4;\n    curDividerRegister += 4;\n    curDividerRegister &= 0xffff;\n\n    Timers.dividerRegister = curDividerRegister;\n\n    if (Timers.timerEnabled) {\n      let timerCounterWasReset = Timers.timerCounterWasReset;\n      if (Timers.timerCounterOverflowDelay) {\n        Timers.timerCounter = Timers.timerModulo;\n        // Fire off timer interrupt\n        requestTimerInterrupt();\n        Timers.timerCounterOverflowDelay = false;\n        Timers.timerCounterWasReset = true;\n      } else if (timerCounterWasReset) {\n        Timers.timerCounterWasReset = false;\n      }\n\n      if (_checkDividerRegisterFallingEdgeDetector(oldDividerRegister, curDividerRegister)) {\n        _incrementTimerCounter();\n      }\n    }\n  }\n}\n\n// Function to increment our Timer Counter\n// This fires off interrupts once we overflow\nfunction _incrementTimerCounter(): void {\n  var counter = Timers.timerCounter;\n  if (++counter > 255) {\n    // Whenever the timer overflows, there is a slight delay (4 cycles)\n    // Of when TIMA gets TMA's value, and the interrupt is fired.\n    // Thus we will set the delay, which can be handled in the update timer or write trap\n    Timers.timerCounterOverflowDelay = true;\n    counter = 0;\n  }\n  Timers.timerCounter = counter;\n}\n\n// Function to act as our falling edge detector\n// Whenever we have a falling edge, we need to increment TIMA\n// http://gbdev.gg8.se/wiki/articles/Timer_Obscure_Behaviour\n// https://github.com/binji/binjgb/blob/master/src/emulator.c#L1944\nfunction _checkDividerRegisterFallingEdgeDetector(oldDividerRegister: i32, newDividerRegister: i32): boolean {\n  // Get our mask\n  let timerCounterMaskBit = _getTimerCounterMaskBit(Timers.timerInputClock);\n\n  // If the old register's watched bit was zero,\n  // but after adding the new registers wastch bit is now 1\n  return checkBitOnByte(timerCounterMaskBit, oldDividerRegister) && !checkBitOnByte(timerCounterMaskBit, newDividerRegister);\n}\n\n// Function to get our current tima mask bit\n// used for our falling edge detector\n// See The docs linked above, or TCAGB for this bit mapping\nfunction _getTimerCounterMaskBit(timerInputClock: i32): i32 {\n  switch (timerInputClock) {\n    case 0x00:\n      return 9;\n    case 0x01:\n      return 3;\n    case 0x02:\n      return 5;\n    case 0x03:\n      return 7;\n  }\n  return 0;\n}\n","// Link cable / serial implementation\n// http://gbdev.gg8.se/wiki/articles/Serial_Data_Transfer_(Link_Cable)\n// See TCAGBD, This is like Timer with the Falling Edge detectors\n\nimport { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory, eightBitStoreIntoGBMemory } from '../memory/index';\nimport { requestSerialInterrupt } from '../interrupts/index';\nimport { checkBitOnByte, resetBitOnByte } from '../helpers/index';\n\nexport class Serial {\n  // Cycle counter\n  static currentCycles: i32 = 0x00;\n\n  // Register locations\n  static readonly memoryLocationSerialTransferData: i32 = 0xff01; // SB\n  static readonly memoryLocationSerialTransferControl: i32 = 0xff02; // SC\n\n  // Number of bits transferred\n  static numberOfBitsTransferred: i32 = 0;\n\n  // Transfer control variables\n  static isShiftClockInternal: boolean = false;\n  static isClockSpeedFast: boolean = false;\n  static transferStartFlag: boolean = false;\n\n  static updateTransferControl(value: i32): boolean {\n    Serial.isShiftClockInternal = checkBitOnByte(0, value);\n    Serial.isClockSpeedFast = checkBitOnByte(1, value);\n    Serial.transferStartFlag = checkBitOnByte(7, value);\n\n    // Allow the original write, and return since we dont need to look anymore\n    return true;\n  }\n}\n\n// Function to initialize our serial values\n// Inlined because closure compiler inlines\nexport function initializeSerial(): void {\n  Serial.currentCycles = 0x00;\n  Serial.numberOfBitsTransferred = 0;\n\n  if (Cpu.GBCEnabled) {\n    // FF01 = 0x00\n    eightBitStoreIntoGBMemory(0xff02, 0x7c);\n    Serial.updateTransferControl(0x7c);\n  } else {\n    // FF01 = 0x00\n    eightBitStoreIntoGBMemory(0xff02, 0x7e);\n    Serial.updateTransferControl(0x7e);\n  }\n}\n\n// TODO: Finish serial\n// See minimal serial: https://github.com/binji/binjgb/commit/64dece05c4ef5a052c4b9b75eb3ddbbfc6677cbe\n// Inlined because closure compiler inlines\nexport function updateSerial(numberOfCycles: i32): void {\n  // If we aren't starting our transfer, or transferring,\n  // return\n  if (!Serial.transferStartFlag) {\n    return;\n  }\n\n  // Want to increment 4 cycles at a time like an actual GB would\n  let cyclesIncreased: i32 = 0;\n  while (cyclesIncreased < numberOfCycles) {\n    let oldCycles = Serial.currentCycles;\n    let curCycles = oldCycles;\n    cyclesIncreased += 4;\n    curCycles += 4;\n\n    if (curCycles > 0xffff) {\n      curCycles -= 0x10000;\n    }\n\n    Serial.currentCycles = curCycles;\n    if (_checkFallingEdgeDetector(oldCycles, curCycles)) {\n      // TODO: Since no actual connection, always transfer 1\n      // Need to fix this\n      let memoryLocationSerialTransferData = Serial.memoryLocationSerialTransferData;\n      let transferData = eightBitLoadFromGBMemory(memoryLocationSerialTransferData);\n      transferData = (transferData << 1) + 1;\n      transferData = transferData & 0xff;\n      eightBitStoreIntoGBMemory(memoryLocationSerialTransferData, transferData);\n      let numberOfBitsTransferred = Serial.numberOfBitsTransferred;\n\n      if (++numberOfBitsTransferred === 8) {\n        Serial.numberOfBitsTransferred = 0;\n        requestSerialInterrupt();\n\n        // Disable transfer start\n        let memoryLocationSerialTransferControl = Serial.memoryLocationSerialTransferControl;\n        let transferControl = eightBitLoadFromGBMemory(memoryLocationSerialTransferControl);\n        eightBitStoreIntoGBMemory(memoryLocationSerialTransferControl, resetBitOnByte(7, transferControl));\n        Serial.transferStartFlag = false;\n      } else {\n        Serial.numberOfBitsTransferred = numberOfBitsTransferred;\n      }\n    }\n  }\n}\n\n// Inlined because closure compiler inlines\nfunction _checkFallingEdgeDetector(oldCycles: i32, newCycles: i32): boolean {\n  // Get our mask\n  let maskBit = _getFallingEdgeMaskBit();\n\n  // If the old register's watched bit was zero,\n  // but after adding the new registers wastch bit is now 1\n  return checkBitOnByte(maskBit, oldCycles) && !checkBitOnByte(maskBit, newCycles);\n}\n\n// Function to get our current tima mask bit\n// used for our falling edge detector\n// See The docs linked above, or TCAGB for this bit mapping\n// Inlined because closure compiler inlines\nfunction _getFallingEdgeMaskBit(): i32 {\n  return Serial.isClockSpeedFast ? 2 : 7;\n}\n","import { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory } from '../memory/load';\nimport { requestJoypadInterrupt } from '../interrupts/index';\nimport { checkBitOnByte, setBitOnByte, resetBitOnByte } from '../helpers/index';\nimport { getSaveStateMemoryOffset } from '../core';\nimport {\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  sixteenBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\n\n// http://www.codeslinger.co.uk/pages/projects/gameboy/joypad.html\n// Joypad Register\n// Taken from pandocs\n// Bit 7 - Not used\n// Bit 6 - Not used\n// Bit 5 - P15 Select Button Keys (0=Select)\n// Bit 4 - P14 Select Direction Keys (0=Select)\n// Bit 3 - P13 Input Down or Start (0=Pressed) (Read Only)\n// Bit 2 - P12 Input Up or Select (0=Pressed) (Read Only)\n// Bit 1 - P11 Input Left or Button B (0=Pressed) (Read Only)\n// Bit 0 - P10 Input Right or Button A (0=Pressed) (Read Only)\n\n// Button Ids will be the following:\n// UP - 0\n// RIGHT - 1\n// DOWN - 2\n// LEFT - 3\n// A - 4\n// B - 5\n// SELECT - 6\n// START - 7\n\nexport class Joypad {\n  static up: boolean = false;\n  static down: boolean = false;\n  static left: boolean = false;\n  static right: boolean = false;\n  static a: boolean = false;\n  static b: boolean = false;\n  static select: boolean = false;\n  static start: boolean = false;\n\n  static readonly memoryLocationJoypadRegister: i32 = 0xff00;\n  // Cache some values on the Joypad register\n  static joypadRegisterFlipped: i32 = 0;\n  static isDpadType: boolean = false;\n  static isButtonType: boolean = false;\n  static updateJoypad(value: i32): void {\n    Joypad.joypadRegisterFlipped = value ^ 0xff;\n    Joypad.isDpadType = checkBitOnByte(4, Joypad.joypadRegisterFlipped);\n    Joypad.isButtonType = checkBitOnByte(5, Joypad.joypadRegisterFlipped);\n  }\n\n  // Save States\n  // Not doing anything for Joypad for now\n\n  static readonly saveStateSlot: i32 = 3;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    store<i32>(getSaveStateMemoryOffset(0x00, Joypad.saveStateSlot), Joypad.joypadRegisterFlipped);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x01, Joypad.saveStateSlot), Joypad.isDpadType);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x02, Joypad.saveStateSlot), Joypad.isButtonType);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Joypad.joypadRegisterFlipped = load<i32>(getSaveStateMemoryOffset(0x00, Joypad.saveStateSlot));\n\n    Joypad.isDpadType = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x01, Joypad.saveStateSlot));\n    Joypad.isButtonType = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x02, Joypad.saveStateSlot));\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function getJoypadState(): i32 {\n  // Get the joypad register\n  let joypadRegister: i32 = Joypad.joypadRegisterFlipped;\n\n  if (Joypad.isDpadType) {\n    // D-pad buttons\n\n    // Up\n    if (Joypad.up) {\n      joypadRegister = resetBitOnByte(2, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(2, joypadRegister);\n    }\n\n    // Right\n    if (Joypad.right) {\n      joypadRegister = resetBitOnByte(0, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(0, joypadRegister);\n    }\n\n    // Down\n    if (Joypad.down) {\n      joypadRegister = resetBitOnByte(3, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(3, joypadRegister);\n    }\n\n    // Left\n    if (Joypad.left) {\n      joypadRegister = resetBitOnByte(1, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(1, joypadRegister);\n    }\n  } else if (Joypad.isButtonType) {\n    // A\n    if (Joypad.a) {\n      joypadRegister = resetBitOnByte(0, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(0, joypadRegister);\n    }\n\n    // B\n    if (Joypad.b) {\n      joypadRegister = resetBitOnByte(1, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(1, joypadRegister);\n    }\n\n    // Select\n    if (Joypad.select) {\n      joypadRegister = resetBitOnByte(2, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(2, joypadRegister);\n    }\n\n    // Start\n    if (Joypad.start) {\n      joypadRegister = resetBitOnByte(3, joypadRegister);\n    } else {\n      joypadRegister = setBitOnByte(3, joypadRegister);\n    }\n  }\n\n  // Set the top 4 bits to on\n  joypadRegister = joypadRegister | 0xf0;\n\n  return joypadRegister;\n}\n\nexport function setJoypadState(up: i32, right: i32, down: i32, left: i32, a: i32, b: i32, select: i32, start: i32): void {\n  if (up > 0) {\n    _pressJoypadButton(0);\n  } else {\n    _releaseJoypadButton(0);\n  }\n\n  if (right > 0) {\n    _pressJoypadButton(1);\n  } else {\n    _releaseJoypadButton(1);\n  }\n\n  if (down > 0) {\n    _pressJoypadButton(2);\n  } else {\n    _releaseJoypadButton(2);\n  }\n\n  if (left > 0) {\n    _pressJoypadButton(3);\n  } else {\n    _releaseJoypadButton(3);\n  }\n\n  if (a > 0) {\n    _pressJoypadButton(4);\n  } else {\n    _releaseJoypadButton(4);\n  }\n\n  if (b > 0) {\n    _pressJoypadButton(5);\n  } else {\n    _releaseJoypadButton(5);\n  }\n\n  if (select > 0) {\n    _pressJoypadButton(6);\n  } else {\n    _releaseJoypadButton(6);\n  }\n\n  if (start > 0) {\n    _pressJoypadButton(7);\n  } else {\n    _releaseJoypadButton(7);\n  }\n}\n\nfunction _pressJoypadButton(buttonId: i32): void {\n  // Un stop the CPU\n  Cpu.isStopped = false;\n\n  // Check if the button state changed from not pressed\n  let isButtonStateChanging: boolean = false;\n  if (!_getJoypadButtonStateFromButtonId(buttonId)) {\n    isButtonStateChanging = true;\n  }\n\n  // Set our joypad state\n  _setJoypadButtonStateFromButtonId(buttonId, true);\n\n  // If the button state is changing, check for an interrupt\n  if (isButtonStateChanging) {\n    // Determine if it is a button or a dpad button\n    let isDpadTypeButton = false;\n    if (buttonId <= 3) {\n      isDpadTypeButton = true;\n    }\n\n    // Determine if we should request an interrupt\n    let shouldRequestInterrupt = false;\n\n    // Check if the game is looking for a dpad type button press\n    if (Joypad.isDpadType && isDpadTypeButton) {\n      shouldRequestInterrupt = true;\n    }\n\n    // Check if the game is looking for a button type button press\n    if (Joypad.isButtonType && !isDpadTypeButton) {\n      shouldRequestInterrupt = true;\n    }\n\n    // Finally, request the interrupt, if the button state actually changed\n    if (shouldRequestInterrupt) {\n      requestJoypadInterrupt();\n    }\n  }\n}\n\n// Inlined because closure compiler inlines\nfunction _releaseJoypadButton(buttonId: i32): void {\n  // Set our joypad state\n  _setJoypadButtonStateFromButtonId(buttonId, false);\n}\n\nfunction _getJoypadButtonStateFromButtonId(buttonId: i32): boolean {\n  switch (buttonId) {\n    case 0:\n      return Joypad.up;\n    case 1:\n      return Joypad.right;\n    case 2:\n      return Joypad.down;\n    case 3:\n      return Joypad.left;\n    case 4:\n      return Joypad.a;\n    case 5:\n      return Joypad.b;\n    case 6:\n      return Joypad.select;\n    case 7:\n      return Joypad.start;\n    default:\n      return false;\n  }\n}\n\nfunction _setJoypadButtonStateFromButtonId(buttonId: i32, isPressed: boolean): void {\n  switch (buttonId) {\n    case 0:\n      Joypad.up = isPressed;\n      break;\n    case 1:\n      Joypad.right = isPressed;\n      break;\n    case 2:\n      Joypad.down = isPressed;\n      break;\n    case 3:\n      Joypad.left = isPressed;\n      break;\n    case 4:\n      Joypad.a = isPressed;\n      break;\n    case 5:\n      Joypad.b = isPressed;\n      break;\n    case 6:\n      Joypad.select = isPressed;\n      break;\n    case 7:\n      Joypad.start = isPressed;\n      break;\n  }\n}\n","// Breakpoints for memory / cpu\nexport class Breakpoints {\n  static programCounter: i32 = -1;\n  static readGbMemory: i32 = -1;\n  static writeGbMemory: i32 = -1;\n  static reachedBreakpoint: boolean = false;\n}\n\nexport function breakpoint(): void {\n  Breakpoints.reachedBreakpoint = true;\n}\n\nexport function setProgramCounterBreakpoint(breakpoint: i32): void {\n  Breakpoints.programCounter = breakpoint;\n}\n\nexport function resetProgramCounterBreakpoint(): void {\n  Breakpoints.programCounter = -1;\n}\n\nexport function setReadGbMemoryBreakpoint(breakpoint: i32): void {\n  Breakpoints.readGbMemory = breakpoint;\n}\n\nexport function resetReadGbMemoryBreakpoint(): void {\n  Breakpoints.readGbMemory = -1;\n}\n\nexport function setWriteGbMemoryBreakpoint(breakpoint: i32): void {\n  Breakpoints.writeGbMemory = breakpoint;\n}\n\nexport function resetWriteGbMemoryBreakpoint(): void {\n  Breakpoints.writeGbMemory = -1;\n}\n","// Funcitons for setting and checking the LCD\nimport { Graphics } from './graphics';\n// Assembly script really not feeling the reexport\nimport { eightBitLoadFromGBMemory } from '../memory/load';\nimport { eightBitStoreIntoGBMemory } from '../memory/store';\nimport { updateHblankHdma } from '../memory/index';\nimport { requestLcdInterrupt, requestVBlankInterrupt } from '../interrupts/index';\nimport { checkBitOnByte, setBitOnByte, resetBitOnByte } from '../helpers/index';\nimport { FRAME_LOCATION, FRAME_SIZE } from '../constants';\n\nexport class Lcd {\n  // Memory Locations\n  // Also known at STAT\n  // LCD Status (0xFF41) bits Explanation\n  // 0                0                    000                    0             00\n  //       |Coicedence Interrupt|     |Mode Interrupts|  |coincidence flag|  | Mode |\n  // Modes:\n  // 0 or 00: H-Blank\n  // 1 or 01: V-Blank\n  // 2 or 10: Searching Sprites Atts\n  // 3 or 11: Transfering Data to LCD Driver\n  static readonly memoryLocationLcdStatus: i32 = 0xff41;\n  static currentLcdMode: i32 = 0;\n  // Function called in write traps to update our hardware registers\n  static updateLcdStatus(value: i32): void {\n    // Bottom three bits are read only\n    let currentLcdStatus: i32 = eightBitLoadFromGBMemory(Lcd.memoryLocationLcdStatus);\n    let valueNoBottomBits = value & 0xf8;\n    let lcdStatusOnlyBottomBits = currentLcdStatus & 0x07;\n    value = valueNoBottomBits | lcdStatusOnlyBottomBits;\n\n    // Top bit is always 1\n    value = setBitOnByte(7, value);\n\n    eightBitStoreIntoGBMemory(Lcd.memoryLocationLcdStatus, value);\n  }\n\n  static readonly memoryLocationCoincidenceCompare: i32 = 0xff45;\n  static coincidenceCompare: i32 = 0;\n\n  // Also known as LCDC\n  // http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n  // Bit 7 - LCD Display Enable (0=Off, 1=On)\n  // Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)\n  // Bit 5 - Window Display Enable (0=Off, 1=On)\n  // Bit 4 - BG & Window Tile Data Select (0=8800-97FF, 1=8000-8FFF)\n  // Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)\n  // Bit 2 - OBJ (Sprite) Size (0=8x8, 1=8x16)\n  // Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On)\n  // Bit 0 - BG Display (for CGB see below) (0=Off, 1=On\n  static readonly memoryLocationLcdControl: i32 = 0xff40;\n  // Decoupled LCDC for caching\n  static enabled: boolean = true;\n  static windowTileMapDisplaySelect: boolean = false;\n  static windowDisplayEnabled: boolean = false;\n  static bgWindowTileDataSelect: boolean = false;\n  static bgTileMapDisplaySelect: boolean = false;\n  static tallSpriteSize: boolean = false;\n  static spriteDisplayEnable: boolean = false;\n  static bgDisplayEnabled: boolean = false;\n\n  // Function called in write traps to update our hardware registers\n  static updateLcdControl(value: i32): void {\n    let wasLcdEnabled = Lcd.enabled;\n\n    Lcd.enabled = checkBitOnByte(7, value);\n    Lcd.windowTileMapDisplaySelect = checkBitOnByte(6, value);\n    Lcd.windowDisplayEnabled = checkBitOnByte(5, value);\n    Lcd.bgWindowTileDataSelect = checkBitOnByte(4, value);\n    Lcd.bgTileMapDisplaySelect = checkBitOnByte(3, value);\n    Lcd.tallSpriteSize = checkBitOnByte(2, value);\n    Lcd.spriteDisplayEnable = checkBitOnByte(1, value);\n    Lcd.bgDisplayEnabled = checkBitOnByte(0, value);\n\n    if (wasLcdEnabled && !Lcd.enabled) {\n      // Disable the LCD\n      resetLcd(true);\n    }\n\n    if (!wasLcdEnabled && Lcd.enabled) {\n      // Re-enable the LCD\n      resetLcd(false);\n    }\n  }\n}\n\nfunction resetLcd(shouldBlankScreen: boolean): void {\n  // Reset scanline cycle counter\n  Graphics.scanlineCycleCounter = 0;\n  Graphics.scanlineRegister = 0;\n  eightBitStoreIntoGBMemory(Graphics.memoryLocationScanlineRegister, 0);\n\n  // Set to mode 0\n  // https://www.reddit.com/r/EmuDev/comments/4w6479/gb_dr_mario_level_generation_issues/\n  let lcdStatus: i32 = eightBitLoadFromGBMemory(Lcd.memoryLocationLcdStatus);\n  lcdStatus = resetBitOnByte(1, lcdStatus);\n  lcdStatus = resetBitOnByte(0, lcdStatus);\n  Lcd.currentLcdMode = 0;\n\n  // Store the status in memory\n  eightBitStoreIntoGBMemory(Lcd.memoryLocationLcdStatus, lcdStatus);\n\n  // Blank the screen\n  if (shouldBlankScreen) {\n    for (let i = 0; i < FRAME_SIZE; ++i) {\n      store<u8>(FRAME_LOCATION + i, 255);\n    }\n  }\n}\n\n// Pass in the lcd status for performance\n// Inlined because closure compiler inlines\nexport function setLcdStatus(): void {\n  // Check if the Lcd was disabled\n  if (!Lcd.enabled) {\n    return;\n  }\n\n  // Get our current scanline, and lcd mode\n  let scanlineRegister: i32 = Graphics.scanlineRegister;\n  let lcdMode: i32 = Lcd.currentLcdMode;\n\n  // Default to  H-Blank\n  let newLcdMode = 0;\n\n  // Find our newLcd mode\n  if (scanlineRegister >= 144) {\n    // VBlank mode\n    newLcdMode = 1;\n  } else {\n    let scanlineCycleCounter = Graphics.scanlineCycleCounter;\n    let MIN_CYCLES_SPRITES_LCD_MODE = Graphics.MIN_CYCLES_SPRITES_LCD_MODE();\n    if (scanlineCycleCounter >= MIN_CYCLES_SPRITES_LCD_MODE) {\n      // Searching Sprites Atts\n      newLcdMode = 2;\n    } else if (scanlineCycleCounter >= MIN_CYCLES_SPRITES_LCD_MODE) {\n      // Transferring data to lcd\n      newLcdMode = 3;\n    }\n  }\n\n  if (lcdMode !== newLcdMode) {\n    // Get our lcd status\n    let lcdStatus: i32 = eightBitLoadFromGBMemory(Lcd.memoryLocationLcdStatus);\n\n    // Save our lcd mode\n    Lcd.currentLcdMode = newLcdMode;\n\n    let shouldRequestInterrupt = false;\n\n    // Set our LCD Status accordingly\n    switch (newLcdMode) {\n      case 0x00:\n        lcdStatus = resetBitOnByte(0, lcdStatus);\n        lcdStatus = resetBitOnByte(1, lcdStatus);\n        shouldRequestInterrupt = checkBitOnByte(3, lcdStatus);\n        break;\n      case 0x01:\n        lcdStatus = resetBitOnByte(1, lcdStatus);\n        lcdStatus = setBitOnByte(0, lcdStatus);\n        shouldRequestInterrupt = checkBitOnByte(4, lcdStatus);\n        break;\n      case 0x02:\n        lcdStatus = resetBitOnByte(0, lcdStatus);\n        lcdStatus = setBitOnByte(1, lcdStatus);\n        shouldRequestInterrupt = checkBitOnByte(5, lcdStatus);\n        break;\n      case 0x03:\n        lcdStatus = setBitOnByte(0, lcdStatus);\n        lcdStatus = setBitOnByte(1, lcdStatus);\n        break;\n    }\n\n    // Check if we want to request an interrupt, and we JUST changed modes\n    if (shouldRequestInterrupt) {\n      requestLcdInterrupt();\n    }\n\n    // Check for updating the Hblank HDMA\n    if (newLcdMode === 0) {\n      // Update the Hblank DMA, will simply return if not active\n      updateHblankHdma();\n    }\n\n    // Check for requesting a VBLANK interrupt\n    if (newLcdMode === 1) {\n      requestVBlankInterrupt();\n    }\n\n    // Check for the coincidence\n    lcdStatus = checkCoincidence(newLcdMode, lcdStatus);\n\n    // Finally, save our status\n    eightBitStoreIntoGBMemory(Lcd.memoryLocationLcdStatus, lcdStatus);\n  } else if (scanlineRegister === 153) {\n    // Special Case, need to check LYC\n    // Fix prehistorik man freeze\n    let lcdStatus: i32 = eightBitLoadFromGBMemory(Lcd.memoryLocationLcdStatus);\n    lcdStatus = checkCoincidence(newLcdMode, lcdStatus);\n    eightBitStoreIntoGBMemory(Lcd.memoryLocationLcdStatus, lcdStatus);\n  }\n}\n\nfunction checkCoincidence(lcdMode: i32, lcdStatus: i32): i32 {\n  // Check for the coincidence flag\n  // Need to check on every mode, and not just HBLANK, as checking on hblank breaks shantae, which checks on vblank\n  if ((lcdMode === 0 || lcdMode === 1) && Graphics.scanlineRegister === Lcd.coincidenceCompare) {\n    lcdStatus = setBitOnByte(2, lcdStatus);\n    if (checkBitOnByte(6, lcdStatus)) {\n      requestLcdInterrupt();\n    }\n  } else {\n    lcdStatus = resetBitOnByte(2, lcdStatus);\n  }\n\n  return lcdStatus;\n}\n","// Main Class and funcitons for rendering the gameboy display\nimport { FRAME_LOCATION, GAMEBOY_INTERNAL_MEMORY_LOCATION } from '../constants';\nimport { getSaveStateMemoryOffset } from '../core';\nimport { Lcd, setLcdStatus } from './lcd';\nimport { renderBackground, renderWindow } from './backgroundWindow';\nimport { renderSprites } from './sprites';\nimport { clearPriorityMap } from './priority';\nimport { resetTileCache } from './tiles';\nimport { initializeColors } from './colors';\nimport { Cpu } from '../cpu/index';\nimport { Config } from '../config';\nimport {\n  Memory,\n  eightBitLoadFromGBMemory,\n  eightBitStoreIntoGBMemory,\n  loadBooleanDirectlyFromWasmMemory,\n  storeBooleanDirectlyToWasmMemory\n} from '../memory/index';\n\nexport class Graphics {\n  // Current cycles\n  // This will be used for batch processing\n  static currentCycles: i32 = 0;\n\n  // Number of cycles to run in each batch process\n  // This number should be in sync so that graphics doesn't run too many cyles at once\n  // and does not exceed the minimum number of cyles for either scanlines, or\n  // How often we change the frame, or a channel's update process\n  static batchProcessCycles(): i32 {\n    return Graphics.MAX_CYCLES_PER_SCANLINE();\n  }\n\n  // Count the number of cycles to keep synced with cpu cycles\n  // Found GBC cycles by finding clock speed from Gb Cycles\n  // See TCAGBD For cycles\n  static scanlineCycleCounter: i32 = 0x00;\n\n  // TCAGBD says 456 per scanline, but 153 only a handful\n  static MAX_CYCLES_PER_SCANLINE(): i32 {\n    if (Graphics.scanlineRegister === 153) {\n      return 4 << (<i32>Cpu.GBCDoubleSpeed);\n    } else {\n      return 456 << (<i32>Cpu.GBCDoubleSpeed);\n    }\n  }\n\n  static MIN_CYCLES_SPRITES_LCD_MODE(): i32 {\n    // TODO: Confirm these clock cyles, double similar to scanline, which TCAGBD did\n    return 376 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  static MIN_CYCLES_TRANSFER_DATA_LCD_MODE(): i32 {\n    // TODO: Confirm these clock cyles, double similar to scanline, which TCAGBD did\n    return 249 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // LCD\n  // scanlineRegister also known as LY\n  // See: http://bgb.bircd.org/pandocs.txt , and search \" LY \"\n  static readonly memoryLocationScanlineRegister: i32 = 0xff44;\n  static scanlineRegister: i32 = 0;\n  static readonly memoryLocationDmaTransfer: i32 = 0xff46;\n\n  // Scroll and Window\n  static readonly memoryLocationScrollX: i32 = 0xff43;\n  static scrollX: i32 = 0;\n  static readonly memoryLocationScrollY: i32 = 0xff42;\n  static scrollY: i32 = 0;\n  static readonly memoryLocationWindowX: i32 = 0xff4b;\n  static windowX: i32 = 0;\n  static readonly memoryLocationWindowY: i32 = 0xff4a;\n  static windowY: i32 = 0;\n\n  // Tile Maps And Data\n  static readonly memoryLocationTileMapSelectZeroStart: i32 = 0x9800;\n  static readonly memoryLocationTileMapSelectOneStart: i32 = 0x9c00;\n  static readonly memoryLocationTileDataSelectZeroStart: i32 = 0x8800;\n  static readonly memoryLocationTileDataSelectOneStart: i32 = 0x8000;\n\n  // Sprites\n  static readonly memoryLocationSpriteAttributesTable: i32 = 0xfe00;\n\n  // Palettes\n  static readonly memoryLocationBackgroundPalette: i32 = 0xff47;\n  static readonly memoryLocationSpritePaletteOne: i32 = 0xff48;\n  static readonly memoryLocationSpritePaletteTwo: i32 = 0xff49;\n\n  // Screen data needs to be stored in wasm memory\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 1;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    // Graphics\n    store<i32>(getSaveStateMemoryOffset(0x00, Graphics.saveStateSlot), Graphics.scanlineCycleCounter);\n    store<u8>(getSaveStateMemoryOffset(0x04, Graphics.saveStateSlot), <u8>Graphics.scanlineRegister);\n    store<u8>(getSaveStateMemoryOffset(0x05, Graphics.saveStateSlot), <u8>Graphics.scrollX);\n    store<u8>(getSaveStateMemoryOffset(0x06, Graphics.saveStateSlot), <u8>Graphics.scrollY);\n    store<u8>(getSaveStateMemoryOffset(0x07, Graphics.saveStateSlot), <u8>Graphics.windowX);\n    store<u8>(getSaveStateMemoryOffset(0x08, Graphics.saveStateSlot), <u8>Graphics.windowY);\n\n    // LCD\n    store<u8>(getSaveStateMemoryOffset(0x09, Graphics.saveStateSlot), <u8>Lcd.currentLcdMode);\n    store<u8>(getSaveStateMemoryOffset(0x0a, Graphics.saveStateSlot), <u8>Lcd.coincidenceCompare);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0b, Graphics.saveStateSlot), Lcd.enabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0c, Graphics.saveStateSlot), Lcd.windowTileMapDisplaySelect);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0d, Graphics.saveStateSlot), Lcd.windowDisplayEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0e, Graphics.saveStateSlot), Lcd.bgWindowTileDataSelect);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0f, Graphics.saveStateSlot), Lcd.bgTileMapDisplaySelect);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x10, Graphics.saveStateSlot), Lcd.tallSpriteSize);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x11, Graphics.saveStateSlot), Lcd.spriteDisplayEnable);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x12, Graphics.saveStateSlot), Lcd.bgDisplayEnabled);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // Graphics\n    Graphics.scanlineCycleCounter = load<i32>(getSaveStateMemoryOffset(0x00, Graphics.saveStateSlot));\n    Graphics.scanlineRegister = load<u8>(getSaveStateMemoryOffset(0x04, Graphics.scanlineRegister));\n    Graphics.scrollX = load<u8>(getSaveStateMemoryOffset(0x05, Graphics.saveStateSlot));\n    Graphics.scrollY = load<u8>(getSaveStateMemoryOffset(0x06, Graphics.saveStateSlot));\n    Graphics.windowX = load<u8>(getSaveStateMemoryOffset(0x07, Graphics.saveStateSlot));\n    Graphics.windowY = load<u8>(getSaveStateMemoryOffset(0x08, Graphics.saveStateSlot));\n\n    // LCD\n    Lcd.currentLcdMode = load<u8>(getSaveStateMemoryOffset(0x09, Graphics.saveStateSlot));\n    Lcd.coincidenceCompare = load<u8>(getSaveStateMemoryOffset(0x0a, Graphics.saveStateSlot));\n    Lcd.enabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0b, Graphics.saveStateSlot));\n    Lcd.windowTileMapDisplaySelect = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0c, Graphics.saveStateSlot));\n    Lcd.windowDisplayEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0d, Graphics.saveStateSlot));\n    Lcd.bgWindowTileDataSelect = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0e, Graphics.saveStateSlot));\n    Lcd.bgTileMapDisplaySelect = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0f, Graphics.saveStateSlot));\n    Lcd.tallSpriteSize = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x10, Graphics.saveStateSlot));\n    Lcd.spriteDisplayEnable = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x11, Graphics.saveStateSlot));\n    Lcd.bgDisplayEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x12, Graphics.saveStateSlot));\n  }\n}\n\n// Batch Process Graphics\n// http://gameboy.mongenel.com/dmg/asmmemmap.html and http://gbdev.gg8.se/wiki/articles/Video_Display\n// Function to batch process our graphics after we skipped so many cycles\n// This is not currently checked in memory read/write\nexport function batchProcessGraphics(): void {\n  var batchProcessCycles = Graphics.batchProcessCycles();\n  while (Graphics.currentCycles >= batchProcessCycles) {\n    updateGraphics(batchProcessCycles);\n    Graphics.currentCycles -= batchProcessCycles;\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function initializeGraphics(): void {\n  // Reset Stateful Variables\n  Graphics.currentCycles = 0;\n  Graphics.scanlineCycleCounter = 0x00;\n  Graphics.scanlineRegister = 0;\n  Graphics.scrollX = 0;\n  Graphics.scrollY = 0;\n  Graphics.windowX = 0;\n  Graphics.windowY = 0;\n\n  Graphics.scanlineRegister = 0x90;\n\n  if (Cpu.GBCEnabled) {\n    eightBitStoreIntoGBMemory(0xff41, 0x81);\n    // 0xFF42 -> 0xFF43 = 0x00\n    eightBitStoreIntoGBMemory(0xff44, 0x90);\n    // 0xFF45 -> 0xFF46 = 0x00\n    eightBitStoreIntoGBMemory(0xff47, 0xfc);\n    // 0xFF48 -> 0xFF4B = 0x00\n  } else {\n    eightBitStoreIntoGBMemory(0xff41, 0x85);\n    // 0xFF42 -> 0xFF45 = 0x00\n    eightBitStoreIntoGBMemory(0xff46, 0xff);\n    eightBitStoreIntoGBMemory(0xff47, 0xfc);\n    eightBitStoreIntoGBMemory(0xff48, 0xff);\n    eightBitStoreIntoGBMemory(0xff49, 0xff);\n    // 0xFF4A -> 0xFF4B = 0x00\n    // GBC VRAM Banks (Handled by Memory, initializeCartridge)\n  }\n\n  // Scanline\n  // Bgb says LY is 90 on boot\n  Graphics.scanlineRegister = 0x90;\n\n  // LCDC register\n  eightBitStoreIntoGBMemory(0xff40, 0x91);\n\n  // GBC VRAM Banks\n  eightBitStoreIntoGBMemory(0xff4f, 0x00);\n  eightBitStoreIntoGBMemory(0xff70, 0x01);\n\n  // Override/reset some variables if the boot ROM is enabled\n  if (Cpu.BootROMEnabled) {\n    if (Cpu.GBCEnabled) {\n      // GBC\n      Graphics.scanlineRegister = 0x00;\n      eightBitStoreIntoGBMemory(0xff40, 0x00);\n      eightBitStoreIntoGBMemory(0xff41, 0x80);\n      eightBitStoreIntoGBMemory(0xff44, 0x00);\n    } else {\n      // GB\n      Graphics.scanlineRegister = 0x00;\n      eightBitStoreIntoGBMemory(0xff40, 0x00);\n      eightBitStoreIntoGBMemory(0xff41, 0x84);\n    }\n  }\n\n  initializeColors();\n}\n\nexport function updateGraphics(numberOfCycles: i32): void {\n  if (Lcd.enabled) {\n    Graphics.scanlineCycleCounter += numberOfCycles;\n\n    let graphicsDisableScanlineRendering = Config.graphicsDisableScanlineRendering;\n\n    while (Graphics.scanlineCycleCounter >= Graphics.MAX_CYCLES_PER_SCANLINE()) {\n      // Reset the scanlineCycleCounter\n      // Don't set to zero to catch extra cycles\n      Graphics.scanlineCycleCounter -= Graphics.MAX_CYCLES_PER_SCANLINE();\n\n      // Move to next scanline\n      // let scanlineRegister: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationScanlineRegister);\n      let scanlineRegister = Graphics.scanlineRegister;\n\n      // Check if we've reached the last scanline\n      if (scanlineRegister === 144) {\n        // Draw the scanline\n        if (!graphicsDisableScanlineRendering) {\n          _drawScanline(scanlineRegister);\n        } else {\n          _renderEntireFrame();\n        }\n\n        // Clear the priority map\n        clearPriorityMap();\n\n        // Reset the tile cache\n        resetTileCache();\n      } else if (scanlineRegister < 144) {\n        // Draw the scanline\n        if (!graphicsDisableScanlineRendering) {\n          _drawScanline(scanlineRegister);\n        }\n      }\n\n      // Post increment the scanline register after drawing\n      // TODO: Need to fix graphics timing\n      if (scanlineRegister > 153) {\n        // Check if we overflowed scanlines\n        // if so, reset our scanline number\n        scanlineRegister = 0;\n      } else {\n        scanlineRegister += 1;\n      }\n\n      // Store our new scanline value\n      Graphics.scanlineRegister = scanlineRegister;\n      // eightBitStoreIntoGBMemory(Graphics.memoryLocationScanlineRegister, scanlineRegister);\n    }\n  }\n\n  // Games like Pokemon crystal want the vblank right as it turns to the value, and not have it increment after\n  // It will break and lead to an infinite loop in crystal\n  // Therefore, we want to be checking/Setting our LCD status after the scanline updates\n  setLcdStatus();\n}\n\n// TODO: Make this a _drawPixelOnScanline, as values can be updated while drawing a scanline\nfunction _drawScanline(scanlineRegister: i32): void {\n  // Get our seleted tile data memory location\n  let tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectZeroStart;\n  if (Lcd.bgWindowTileDataSelect) {\n    tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectOneStart;\n  }\n\n  // Check if the background is enabled\n  // NOTE: On Gameboy color, Pandocs says this does something completely different\n  // LCDC.0 - 2) CGB in CGB Mode: BG and Window Master Priority\n  // When Bit 0 is cleared, the background and window lose their priority -\n  // the sprites will be always displayed on top of background and window,\n  // independently of the priority flags in OAM and BG Map attributes.\n  // TODO: Enable this different feature for GBC\n  if (Cpu.GBCEnabled || Lcd.bgDisplayEnabled) {\n    // Get our map memory location\n    let tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectZeroStart;\n    if (Lcd.bgTileMapDisplaySelect) {\n      tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectOneStart;\n    }\n\n    // Finally, pass everything to draw the background\n    renderBackground(scanlineRegister, tileDataMemoryLocation, tileMapMemoryLocation);\n  }\n\n  // Check if the window is enabled, and we are currently\n  // Drawing lines on the window\n  if (Lcd.windowDisplayEnabled) {\n    // Get our map memory location\n    let tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectZeroStart;\n    if (Lcd.windowTileMapDisplaySelect) {\n      tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectOneStart;\n    }\n\n    // Finally, pass everything to draw the background\n    renderWindow(scanlineRegister, tileDataMemoryLocation, tileMapMemoryLocation);\n  }\n\n  if (Lcd.spriteDisplayEnable) {\n    // Sprites are enabled, render them!\n    renderSprites(scanlineRegister, Lcd.tallSpriteSize);\n  }\n}\n\n// Function to render everything for a frame at once\n// This is to improve performance\n// See above for comments on how things are donw\nfunction _renderEntireFrame(): void {\n  // Scanline needs to be in sync while we draw, thus, we can't shortcut anymore than here\n  for (let i = 0; i <= 144; ++i) {\n    _drawScanline(<u8>i);\n  }\n}\n\n// Function to get the start of a RGB pixel (R, G, B)\n// Inlined because closure compiler inlines\nexport function getRgbPixelStart(x: i32, y: i32): i32 {\n  // Get the pixel number\n  // let pixelNumber: i32 = (y * 160) + x;\n  // Each pixel takes 3 slots, therefore, multiply by 3!\n  return (y * 160 + x) * 3;\n}\n\n// Also need to store current frame in memory to be read by JS\nexport function setPixelOnFrame(x: i32, y: i32, colorId: i32, color: i32): void {\n  // Currently only supports 160x144\n  // Storing in X, then y\n  // So need an offset\n  store<u8>(FRAME_LOCATION + getRgbPixelStart(x, y) + colorId, color);\n}\n\n// Function to shortcut the memory map, and load directly from the VRAM Bank\nexport function loadFromVramBank(gameboyOffset: i32, vramBankId: i32): u8 {\n  let wasmBoyAddress = gameboyOffset - Memory.videoRamLocation + GAMEBOY_INTERNAL_MEMORY_LOCATION + 0x2000 * (vramBankId & 0x01);\n  return load<u8>(wasmBoyAddress);\n}\n","// WasmBoy memory map:\n// https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing\nimport { getSaveStateMemoryOffset } from '../core';\nimport { eightBitLoadFromGBMemory, loadBooleanDirectlyFromWasmMemory } from './load';\nimport { eightBitStoreIntoGBMemory, storeBooleanDirectlyToWasmMemory } from './store';\n\nexport class Memory {\n  // ----------------------------------\n  // Gameboy Memory Map\n  // ----------------------------------\n  // https://github.com/AntonioND/giibiiadvance/blob/master/docs/TCAGBD.pdf\n  // http://gameboy.mongenel.com/dmg/asmmemmap.html\n  // using Arrays, first index is start, second is end\n  static readonly cartridgeRomLocation: i32 = 0x0000;\n\n  static readonly switchableCartridgeRomLocation: i32 = 0x4000;\n\n  static readonly videoRamLocation: i32 = 0x8000;\n\n  static readonly cartridgeRamLocation: i32 = 0xa000;\n\n  static readonly internalRamBankZeroLocation: i32 = 0xc000;\n\n  // This ram bank is switchable\n  static readonly internalRamBankOneLocation: i32 = 0xd000;\n\n  static readonly echoRamLocation: i32 = 0xe000;\n\n  static readonly spriteInformationTableLocation: i32 = 0xfe00;\n\n  static readonly spriteInformationTableLocationEnd: i32 = 0xfe9f;\n\n  static readonly unusableMemoryLocation: i32 = 0xfea0;\n  static readonly unusableMemoryEndLocation: i32 = 0xfeff;\n\n  // Hardware I/O, 0xFF00 -> 0xFF7F\n  // Zero Page, 0xFF80 -> 0xFFFE\n  // Intterupt Enable Flag, 0xFFFF\n\n  // ----------------------------------\n  // Rom/Ram Banking\n  // ----------------------------------\n  // http://gbdev.gg8.se/wiki/articles/Memory_Bank_Controllers#MBC3_.28max_2MByte_ROM_and.2For_32KByte_RAM_and_Timer.29\n  // http://www.codeslinger.co.uk/pages/projects/gameboy/banking.html\n  static currentRomBank: i32 = 0x00;\n  static currentRamBank: i32 = 0x00;\n  static isRamBankingEnabled: boolean = false;\n  static isMBC1RomModeEnabled: boolean = true;\n\n  // Cartridge Types\n  // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header\n  static isRomOnly: boolean = true;\n  static isMBC1: boolean = false;\n  static isMBC2: boolean = false;\n  static isMBC3: boolean = false;\n  static isMBC5: boolean = false;\n\n  // DMA\n  static memoryLocationHdmaSourceHigh: i32 = 0xff51;\n  static memoryLocationHdmaSourceLow: i32 = 0xff52;\n  static memoryLocationHdmaDestinationHigh: i32 = 0xff53;\n  static memoryLocationHdmaDestinationLow: i32 = 0xff54;\n  static memoryLocationHdmaTrigger: i32 = 0xff55;\n  // Cycles accumulated for DMA\n  static DMACycles: i32 = 0;\n  // Boolean we will mirror to indicate if Hdma is active\n  static isHblankHdmaActive: boolean = false;\n  static hblankHdmaTransferLengthRemaining: i32 = 0x00;\n  // Store the source and destination for performance, and update as needed\n  static hblankHdmaSource: i32 = 0x00;\n  static hblankHdmaDestination: i32 = 0x00;\n\n  // GBC Registers\n  static memoryLocationGBCVRAMBank: i32 = 0xff4f;\n  static memoryLocationGBCWRAMBank: i32 = 0xff70;\n\n  // Save States\n\n  static readonly saveStateSlot: i32 = 4;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    store<u16>(getSaveStateMemoryOffset(0x00, Memory.saveStateSlot), Memory.currentRomBank);\n    store<u16>(getSaveStateMemoryOffset(0x02, Memory.saveStateSlot), Memory.currentRamBank);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x04, Memory.saveStateSlot), Memory.isRamBankingEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x05, Memory.saveStateSlot), Memory.isMBC1RomModeEnabled);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x06, Memory.saveStateSlot), Memory.isRomOnly);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x07, Memory.saveStateSlot), Memory.isMBC1);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x08, Memory.saveStateSlot), Memory.isMBC2);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x09, Memory.saveStateSlot), Memory.isMBC3);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0a, Memory.saveStateSlot), Memory.isMBC5);\n\n    store<i32>(getSaveStateMemoryOffset(0x0b, Memory.saveStateSlot), Memory.DMACycles);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x0f, Memory.saveStateSlot), Memory.isHblankHdmaActive);\n    store<i32>(getSaveStateMemoryOffset(0x10, Memory.saveStateSlot), Memory.hblankHdmaTransferLengthRemaining);\n    store<i32>(getSaveStateMemoryOffset(0x14, Memory.saveStateSlot), Memory.hblankHdmaSource);\n    store<i32>(getSaveStateMemoryOffset(0x18, Memory.saveStateSlot), Memory.hblankHdmaDestination);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    Memory.currentRomBank = load<u16>(getSaveStateMemoryOffset(0x00, Memory.saveStateSlot));\n    Memory.currentRamBank = load<u16>(getSaveStateMemoryOffset(0x02, Memory.saveStateSlot));\n\n    Memory.isRamBankingEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x04, Memory.saveStateSlot));\n    Memory.isMBC1RomModeEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x05, Memory.saveStateSlot));\n\n    Memory.isRomOnly = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x06, Memory.saveStateSlot));\n    Memory.isMBC1 = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x07, Memory.saveStateSlot));\n    Memory.isMBC2 = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x08, Memory.saveStateSlot));\n    Memory.isMBC3 = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x09, Memory.saveStateSlot));\n    Memory.isMBC5 = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0a, Memory.saveStateSlot));\n\n    Memory.DMACycles = load<i32>(getSaveStateMemoryOffset(0x0b, Memory.saveStateSlot));\n    Memory.isHblankHdmaActive = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x0f, Memory.saveStateSlot));\n    Memory.hblankHdmaTransferLengthRemaining = load<i32>(getSaveStateMemoryOffset(0x10, Memory.saveStateSlot));\n    Memory.hblankHdmaSource = load<i32>(getSaveStateMemoryOffset(0x14, Memory.saveStateSlot));\n    Memory.hblankHdmaDestination = load<i32>(getSaveStateMemoryOffset(0x18, Memory.saveStateSlot));\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function initializeCartridge(): void {\n  // Reset stateful variables\n  Memory.isRamBankingEnabled = false;\n  Memory.isMBC1RomModeEnabled = true;\n\n  // Get our game MBC type from the cartridge header\n  // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header\n  let cartridgeType = eightBitLoadFromGBMemory(0x0147);\n\n  // Reset our Cartridge types\n  Memory.isRomOnly = cartridgeType === 0x00;\n  Memory.isMBC1 = cartridgeType >= 0x01 && cartridgeType <= 0x03;\n  Memory.isMBC2 = cartridgeType >= 0x05 && cartridgeType <= 0x06;\n  Memory.isMBC3 = cartridgeType >= 0x0f && cartridgeType <= 0x13;\n  Memory.isMBC5 = cartridgeType >= 0x19 && cartridgeType <= 0x1e;\n\n  Memory.currentRomBank = 0x01;\n  Memory.currentRamBank = 0x00;\n\n  // Set our GBC Banks\n  eightBitStoreIntoGBMemory(Memory.memoryLocationGBCVRAMBank, 0x00);\n  eightBitStoreIntoGBMemory(Memory.memoryLocationGBCWRAMBank, 0x01);\n}\n","import { getSaveStateMemoryOffset } from '../core';\nimport { loadBooleanDirectlyFromWasmMemory, storeBooleanDirectlyToWasmMemory } from '../memory/index';\nimport { Interrupts } from '../interrupts/index';\n\n// Everything Static as class instances just aren't quite there yet\n// https://github.com/AssemblyScript/assemblyscript/blob/master/tests/compiler/showcase.ts\nexport class Cpu {\n  // Status to track if we are currently executing the boot rom\n  static readonly memoryLocationBootROMSwitch: u16 = 0xff50;\n  static BootROMEnabled: boolean = false;\n\n  // Status to track if we are in Gameboy Color Mode, and GBC State\n  static GBCEnabled: boolean = false;\n\n  // Memory Location for the GBC Speed switch\n  // And the current status\n  static readonly memoryLocationSpeedSwitch: u16 = 0xff4d;\n  static GBCDoubleSpeed: boolean = false;\n\n  // 8-bit Cpu.registers\n  static registerA: u8 = 0;\n  static registerB: u8 = 0;\n  static registerC: u8 = 0;\n  static registerD: u8 = 0;\n  static registerE: u8 = 0;\n  static registerH: u8 = 0;\n  static registerL: u8 = 0;\n  static registerF: u8 = 0;\n\n  // 16-bit Cpu.registers\n  static stackPointer: u16 = 0;\n  // Boot rom from 0x00 to 0x99, all games start at 0x100\n  static programCounter: u16 = 0x00;\n\n  // Current number of cycles, shouldn't execeed max number of cycles\n  static currentCycles: i32 = 0;\n  static CLOCK_SPEED(): i32 {\n    // 2^23, thanks binji!\n    // return Cpu.GBCDoubleSpeed ? 8388608 : 4194304;\n    return 4194304 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // Cycles Per Frame = Clock Speed / fps\n  // So: 4194304 / 59.73\n  static MAX_CYCLES_PER_FRAME(): i32 {\n    // return Cpu.GBCDoubleSpeed ? 140448 : 70224;\n    return 70224 << (<i32>Cpu.GBCDoubleSpeed);\n  }\n\n  // HALT and STOP instructions need to stop running opcodes, but simply check timers\n  // https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // Matt said is should work to, so it must work!\n  // TCAGBD shows three different HALT states. Therefore, we need to handle each\n  static isHaltNormal: boolean = false;\n  static isHaltNoJump: boolean = false;\n  static isHaltBug: boolean = false;\n  static isStopped: boolean = false;\n\n  // See section 4.10 of TCAGBD\n  // Cpu Halting explained: https://www.reddit.com/r/EmuDev/comments/5ie3k7/infinite_loop_trying_to_pass_blarggs_interrupt/db7xnbe/\n  static enableHalt(): void {\n    if (Interrupts.masterInterruptSwitch) {\n      Cpu.isHaltNormal = true;\n      return;\n    }\n\n    let haltTypeValue = Interrupts.interruptsEnabledValue & Interrupts.interruptsRequestedValue & 0x1f;\n\n    if (haltTypeValue === 0) {\n      Cpu.isHaltNoJump = true;\n      return;\n    }\n\n    Cpu.isHaltBug = true;\n  }\n\n  static exitHaltAndStop(): void {\n    Cpu.isHaltNoJump = false;\n    Cpu.isHaltNormal = false;\n    Cpu.isHaltBug = false;\n    Cpu.isStopped = false;\n  }\n\n  static isHalted(): boolean {\n    return Cpu.isHaltNormal || Cpu.isHaltNoJump;\n  }\n\n  // Save States\n  static readonly saveStateSlot: u16 = 0;\n\n  // Function to save the state of the class\n  static saveState(): void {\n    // Registers\n    store<u8>(getSaveStateMemoryOffset(0x00, Cpu.saveStateSlot), Cpu.registerA);\n    store<u8>(getSaveStateMemoryOffset(0x01, Cpu.saveStateSlot), Cpu.registerB);\n    store<u8>(getSaveStateMemoryOffset(0x02, Cpu.saveStateSlot), Cpu.registerC);\n    store<u8>(getSaveStateMemoryOffset(0x03, Cpu.saveStateSlot), Cpu.registerD);\n    store<u8>(getSaveStateMemoryOffset(0x04, Cpu.saveStateSlot), Cpu.registerE);\n    store<u8>(getSaveStateMemoryOffset(0x05, Cpu.saveStateSlot), Cpu.registerH);\n    store<u8>(getSaveStateMemoryOffset(0x06, Cpu.saveStateSlot), Cpu.registerL);\n    store<u8>(getSaveStateMemoryOffset(0x07, Cpu.saveStateSlot), Cpu.registerF);\n\n    store<u16>(getSaveStateMemoryOffset(0x08, Cpu.saveStateSlot), Cpu.stackPointer);\n    store<u16>(getSaveStateMemoryOffset(0x0a, Cpu.saveStateSlot), Cpu.programCounter);\n\n    store<i32>(getSaveStateMemoryOffset(0x0c, Cpu.saveStateSlot), Cpu.currentCycles);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x11, Cpu.saveStateSlot), Cpu.isHaltNormal);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x12, Cpu.saveStateSlot), Cpu.isHaltNoJump);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x13, Cpu.saveStateSlot), Cpu.isHaltBug);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x14, Cpu.saveStateSlot), Cpu.isStopped);\n\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x15, Cpu.saveStateSlot), Cpu.BootROMEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x16, Cpu.saveStateSlot), Cpu.GBCEnabled);\n    storeBooleanDirectlyToWasmMemory(getSaveStateMemoryOffset(0x17, Cpu.saveStateSlot), Cpu.GBCDoubleSpeed);\n  }\n\n  // Function to load the save state from memory\n  static loadState(): void {\n    // Registers\n    Cpu.registerA = load<u8>(getSaveStateMemoryOffset(0x00, Cpu.saveStateSlot));\n    Cpu.registerB = load<u8>(getSaveStateMemoryOffset(0x01, Cpu.saveStateSlot));\n    Cpu.registerC = load<u8>(getSaveStateMemoryOffset(0x02, Cpu.saveStateSlot));\n    Cpu.registerD = load<u8>(getSaveStateMemoryOffset(0x03, Cpu.saveStateSlot));\n    Cpu.registerE = load<u8>(getSaveStateMemoryOffset(0x04, Cpu.saveStateSlot));\n    Cpu.registerH = load<u8>(getSaveStateMemoryOffset(0x05, Cpu.saveStateSlot));\n    Cpu.registerL = load<u8>(getSaveStateMemoryOffset(0x06, Cpu.saveStateSlot));\n    Cpu.registerF = load<u8>(getSaveStateMemoryOffset(0x07, Cpu.saveStateSlot));\n\n    Cpu.stackPointer = load<u16>(getSaveStateMemoryOffset(0x08, Cpu.saveStateSlot));\n    Cpu.programCounter = load<u16>(getSaveStateMemoryOffset(0x0a, Cpu.saveStateSlot));\n\n    Cpu.currentCycles = load<i32>(getSaveStateMemoryOffset(0x0c, Cpu.saveStateSlot));\n\n    Cpu.isHaltNormal = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x11, Cpu.saveStateSlot));\n    Cpu.isHaltNoJump = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x12, Cpu.saveStateSlot));\n    Cpu.isHaltBug = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x13, Cpu.saveStateSlot));\n    Cpu.isStopped = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x14, Cpu.saveStateSlot));\n\n    Cpu.BootROMEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x15, Cpu.saveStateSlot));\n    Cpu.GBCEnabled = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x16, Cpu.saveStateSlot));\n    Cpu.GBCDoubleSpeed = loadBooleanDirectlyFromWasmMemory(getSaveStateMemoryOffset(0x17, Cpu.saveStateSlot));\n  }\n}\n\n// Inlined because closure compiler does so\nexport function initializeCpu(): void {\n  // Reset all stateful Cpu variables\n  // Cpu.GBCEnabled is done by core/initialize\n  Cpu.GBCDoubleSpeed = false;\n  Cpu.registerA = 0;\n  Cpu.registerB = 0;\n  Cpu.registerC = 0;\n  Cpu.registerD = 0;\n  Cpu.registerE = 0;\n  Cpu.registerH = 0;\n  Cpu.registerL = 0;\n  Cpu.registerF = 0;\n  Cpu.stackPointer = 0;\n  Cpu.programCounter = 0x00;\n  Cpu.currentCycles = 0;\n  Cpu.isHaltNormal = false;\n  Cpu.isHaltNoJump = false;\n  Cpu.isHaltBug = false;\n  Cpu.isStopped = false;\n\n  // Everything is done by Boot ROM is enabled.\n  if (Cpu.BootROMEnabled) {\n    return;\n  }\n\n  if (Cpu.GBCEnabled) {\n    // CPU Registers\n    Cpu.registerA = 0x11;\n    Cpu.registerF = 0x80;\n    Cpu.registerB = 0x00;\n    Cpu.registerC = 0x00;\n    Cpu.registerD = 0xff;\n    Cpu.registerE = 0x56;\n    Cpu.registerH = 0x00;\n    Cpu.registerL = 0x0d;\n  } else {\n    // Cpu Registers\n    Cpu.registerA = 0x01;\n    Cpu.registerF = 0xb0;\n    Cpu.registerB = 0x00;\n    Cpu.registerC = 0x13;\n    Cpu.registerD = 0x00;\n    Cpu.registerE = 0xd8;\n    Cpu.registerH = 0x01;\n    Cpu.registerL = 0x4d;\n  }\n\n  // Cpu Control Flow\n  Cpu.programCounter = 0x100;\n  Cpu.stackPointer = 0xfffe;\n}\n","// Syncing and Tracking executed cycles\n\nimport { Config } from './config';\nimport { Cpu } from './cpu/index';\nimport { Graphics, updateGraphics, batchProcessGraphics } from './graphics/index';\nimport { Memory } from './memory/index';\nimport { Timers, updateTimers, batchProcessTimers } from './timers/index';\nimport { Sound, updateSound, batchProcessAudio } from './sound/index';\nimport { updateSerial } from './serial/serial';\n\nexport class Cycles {\n  // An even number below the max 32 bit integer\n  static cyclesPerCycleSet: i32 = 2000000000;\n  static cycleSets: i32 = 0;\n  static cycles: i32 = 0;\n}\n\nexport function getCyclesPerCycleSet(): i32 {\n  return Cycles.cyclesPerCycleSet;\n}\n\nexport function getCycleSets(): i32 {\n  return Cycles.cycleSets;\n}\n\nexport function getCycles(): i32 {\n  return Cycles.cycles;\n}\n\n// Inlined because closure compiler inlines\nfunction trackCyclesRan(numberOfCycles: i32): void {\n  let cycles = Cycles.cycles;\n  cycles += numberOfCycles;\n  if (cycles >= Cycles.cyclesPerCycleSet) {\n    Cycles.cycleSets += 1;\n    cycles -= Cycles.cyclesPerCycleSet;\n  }\n  Cycles.cycles = cycles;\n}\n\n// Inlined because closure compiler inlines\nexport function resetCycles(): void {\n  Cycles.cyclesPerCycleSet = 2000000000;\n  Cycles.cycleSets = 0;\n  Cycles.cycles = 0;\n}\n\n// Sync other GB Components with the number of cycles\nexport function syncCycles(numberOfCycles: i32): void {\n  // Check if we did a DMA TRansfer, if we did add the cycles\n  if (Memory.DMACycles > 0) {\n    numberOfCycles += Memory.DMACycles;\n    Memory.DMACycles = 0;\n  }\n\n  // Finally, Add our number of cycles to the CPU Cycles\n  Cpu.currentCycles += numberOfCycles;\n\n  // Check other Gameboy components\n  if (!Cpu.isStopped) {\n    if (Config.graphicsBatchProcessing) {\n      // Need to do this, since a lot of things depend on the scanline\n      // Batch processing will simply return if the number of cycles is too low\n      Graphics.currentCycles += numberOfCycles;\n      batchProcessGraphics();\n    } else {\n      updateGraphics(numberOfCycles);\n    }\n\n    if (Config.audioBatchProcessing) {\n      Sound.currentCycles += numberOfCycles;\n      batchProcessAudio();\n    } else {\n      updateSound(numberOfCycles);\n    }\n\n    updateSerial(numberOfCycles);\n  }\n\n  if (Config.timersBatchProcessing) {\n    // Batch processing will simply return if the number of cycles is too low\n    Timers.currentCycles += numberOfCycles;\n    batchProcessTimers();\n  } else {\n    updateTimers(numberOfCycles);\n  }\n\n  trackCyclesRan(numberOfCycles);\n}\n","// Functions involving executing/running the emulator after initializtion\n\nimport { setHasCoreStarted } from './core';\nimport { syncCycles } from './cycles';\nimport { Cpu, executeOpcode } from './cpu/index';\nimport { checkInterrupts } from './interrupts/index';\nimport { eightBitLoadFromGBMemory } from './memory/index';\nimport { getNumberOfSamplesInAudioBuffer } from './sound/index';\nimport { u16Portable } from './portable/portable';\n\nimport { Breakpoints } from './debug/breakpoints';\n\nexport class Execute {\n  // An even number bewlow the max 32 bit integer\n  static stepsPerStepSet: i32 = 2000000000;\n  static stepSets: i32 = 0;\n  static steps: i32 = 0;\n\n  // Response Codes from Execute Conditions\n  static RESPONSE_CONDITION_ERROR: i32 = -1;\n  static RESPONSE_CONDITION_FRAME: i32 = 0;\n  static RESPONSE_CONDITION_AUDIO: i32 = 1;\n  static RESPONSE_CONDITION_BREAKPOINT: i32 = 2;\n}\n\nexport function getStepsPerStepSet(): i32 {\n  return Execute.stepsPerStepSet;\n}\n\nexport function getStepSets(): i32 {\n  return Execute.stepSets;\n}\n\nexport function getSteps(): i32 {\n  return Execute.steps;\n}\n\n// Inlined because closure compiler inlines\nfunction trackStepsRan(steps: i32): void {\n  let esteps = Execute.steps;\n  esteps += steps;\n  if (esteps >= Execute.stepsPerStepSet) {\n    Execute.stepSets += 1;\n    esteps -= Execute.stepsPerStepSet;\n  }\n  Execute.steps = esteps;\n}\n\n// Inlined because closure compiler inlines\nexport function resetSteps(): void {\n  Execute.stepsPerStepSet = 2000000000;\n  Execute.stepSets = 0;\n  Execute.steps = 0;\n}\n\n// // Public funciton to run frames until,\n// the specified number of frames have run or error.\n// Return values:\n// -1 = error\n// 0 = render a frame\nexport function executeMultipleFrames(numberOfFrames: i32): i32 {\n  let frameResponse = 0;\n  let framesRun = 0;\n  while (framesRun < numberOfFrames && frameResponse >= 0) {\n    frameResponse = executeFrame();\n    framesRun += 1;\n  }\n\n  if (frameResponse < 0) {\n    return frameResponse;\n  }\n\n  return 0;\n}\n\n// Public funciton to run opcodes until,\n// a frame is ready, or error.\n// Return values:\n// -1 = error\n// 0 = render a frame\nexport function executeFrame(): i32 {\n  return executeUntilCondition(true, -1);\n}\n\n// Public Function to run opcodes until,\n// a frame is ready, audio bufer is filled, or error\nexport function executeFrameAndCheckAudio(maxAudioBuffer: i32 = 0): i32 {\n  return executeUntilCondition(true, maxAudioBuffer);\n}\n\n// Base function that executes steps, and checks conditions\n// Return values:\nexport function executeUntilCondition(checkMaxCyclesPerFrame: boolean = true, maxAudioBuffer: i32 = -1): i32 {\n  // Common tracking variables\n  let numberOfCycles = -1;\n  let audioBufferSize = 1024;\n\n  if (maxAudioBuffer > 0) {\n    audioBufferSize = maxAudioBuffer;\n  } else if (maxAudioBuffer < 0) {\n    audioBufferSize = -1;\n  }\n\n  let errorCondition: boolean = false;\n  let frameCondition: boolean = false;\n  let audioBufferCondition: boolean = false;\n\n  while (!errorCondition && !frameCondition && !audioBufferCondition && !Breakpoints.reachedBreakpoint) {\n    numberOfCycles = executeStep();\n\n    // Error Condition\n    if (numberOfCycles < 0) {\n      errorCondition = true;\n    } else if (Cpu.currentCycles >= Cpu.MAX_CYCLES_PER_FRAME()) {\n      frameCondition = true;\n    } else if (audioBufferSize > -1 && getNumberOfSamplesInAudioBuffer() >= audioBufferSize) {\n      audioBufferCondition = true;\n    }\n  }\n\n  // Find our exit reason\n  if (frameCondition) {\n    // Render a frame\n\n    // Reset our currentCycles\n    Cpu.currentCycles -= Cpu.MAX_CYCLES_PER_FRAME();\n\n    return Execute.RESPONSE_CONDITION_FRAME;\n  }\n\n  if (audioBufferCondition) {\n    return Execute.RESPONSE_CONDITION_AUDIO;\n  }\n\n  if (Breakpoints.reachedBreakpoint) {\n    Breakpoints.reachedBreakpoint = false;\n    return Execute.RESPONSE_CONDITION_BREAKPOINT;\n  }\n\n  // TODO: Boot ROM handling\n\n  // There was an error, return -1, and push the program counter back to grab the error opcode\n  Cpu.programCounter = u16Portable(Cpu.programCounter - 1);\n  return -1;\n}\n\n// Function to execute an opcode, and update other gameboy hardware.\n// http://www.codeslinger.co.uk/pages/projects/gameboy/beginning.html\nexport function executeStep(): i32 {\n  // Set has started to 1 since we ran a emulation step\n  setHasCoreStarted(true);\n\n  // Check if we are in the halt bug\n  if (Cpu.isHaltBug) {\n    // Need to not increment program counter,\n    // thus, running the next opcode twice\n\n    // E.g\n    // 0x76 - halt\n    // FA 34 12 - ld a,(1234)\n    // Becomes\n    // FA FA 34 ld a,(34FA)\n    // 12 ld (de),a\n\n    let haltBugOpcode: i32 = <u8>eightBitLoadFromGBMemory(Cpu.programCounter);\n    // Execute opcode will handle the actual PC behavior\n    let haltBugCycles: i32 = executeOpcode(haltBugOpcode);\n    syncCycles(haltBugCycles);\n    Cpu.exitHaltAndStop();\n  }\n\n  // Interrupts should be handled before reading an opcode\n  // https://github.com/Gekkio/mooneye-gb/blob/master/docs/accuracy.markdown#what-is-the-exact-timing-of-cpu-servicing-an-interrupt\n  let interruptCycles: i32 = checkInterrupts();\n  if (interruptCycles > 0) {\n    syncCycles(interruptCycles);\n  }\n\n  // Get the opcode, and additional bytes to be handled\n  // Number of cycles defaults to 4, because while we're halted, we run 4 cycles (according to matt :))\n  let numberOfCycles = 4;\n  let opcode = 0;\n\n  // If we are not halted or stopped, run instructions\n  // If we are halted, this will be skipped and just sync the 4 cycles\n  if (!Cpu.isHalted() && !Cpu.isStopped) {\n    opcode = <u8>eightBitLoadFromGBMemory(Cpu.programCounter);\n    numberOfCycles = executeOpcode(opcode);\n  }\n\n  // blarggFixes, don't allow register F to have the bottom nibble\n  Cpu.registerF = Cpu.registerF & 0xf0;\n\n  // Check if there was an error decoding the opcode\n  if (numberOfCycles <= 0) {\n    return numberOfCycles;\n  }\n\n  // Sync other GB Components with the number of cycles\n  syncCycles(numberOfCycles);\n\n  // Update our steps\n  trackStepsRan(1);\n\n  // Check if we reached the CPU breakpoint\n  if (Cpu.programCounter === Breakpoints.programCounter) {\n    Breakpoints.reachedBreakpoint = true;\n  }\n\n  return numberOfCycles;\n}\n","// Imports\nimport { WASMBOY_WASM_PAGES, WASMBOY_STATE_LOCATION } from './constants';\nimport { Config } from './config';\nimport { resetCycles } from './cycles';\nimport { resetSteps } from './execute';\nimport { Cpu, initializeCpu } from './cpu/index';\nimport { Graphics, initializeGraphics, initializePalette } from './graphics/index';\nimport { Interrupts, initializeInterrupts } from './interrupts/index';\nimport { Joypad } from './joypad/index';\nimport { Memory, initializeCartridge, initializeDma, eightBitStoreIntoGBMemory, eightBitLoadFromGBMemory } from './memory/index';\nimport { Timers, initializeTimers } from './timers/index';\nimport { Sound, initializeSound, Channel1, Channel2, Channel3, Channel4 } from './sound/index';\nimport { initializeSerial } from './serial/serial';\n\n// Grow our memory to the specified size\nif (memory.size() < WASMBOY_WASM_PAGES) {\n  memory.grow(WASMBOY_WASM_PAGES - memory.size());\n}\n\n// Function to track if the core has started\nlet hasStarted: boolean = false;\nexport function setHasCoreStarted(value: boolean): void {\n  hasStarted = value;\n}\n\nexport function hasCoreStarted(): i32 {\n  return <i32>hasStarted;\n}\n\n// Function to configure & initialize wasmboy\nexport function config(\n  enableBootRom: i32,\n  useGbcWhenAvailable: i32,\n  audioBatchProcessing: i32,\n  graphicsBatchProcessing: i32,\n  timersBatchProcessing: i32,\n  graphicsDisableScanlineRendering: i32,\n  audioAccumulateSamples: i32,\n  tileRendering: i32,\n  tileCaching: i32,\n  enableAudioDebugging: i32\n): void {\n  // TODO: depending on the boot rom, initialization may be different\n  // From: http://www.codeslinger.co.uk/pages/projects/gameboy/hardware.html\n  // All values default to zero in memory, so not setting them yet\n  // log('initializing (includeBootRom=$0)', 1, enableBootRom);\n\n  Config.enableBootRom = enableBootRom > 0;\n  Config.useGbcWhenAvailable = useGbcWhenAvailable > 0;\n  Config.audioBatchProcessing = audioBatchProcessing > 0;\n  Config.graphicsBatchProcessing = graphicsBatchProcessing > 0;\n  Config.timersBatchProcessing = timersBatchProcessing > 0;\n  Config.graphicsDisableScanlineRendering = graphicsDisableScanlineRendering > 0;\n  Config.audioAccumulateSamples = audioAccumulateSamples > 0;\n  Config.tileRendering = tileRendering > 0;\n  Config.tileCaching = tileCaching > 0;\n  Config.enableAudioDebugging = enableAudioDebugging > 0;\n\n  initialize();\n}\n\n// Function to initiialize the core\nfunction initialize(): void {\n  // Initialization variables from BGB\n\n  // First, try to switch to Gameboy Color Mode\n  // Get our GBC support from the cartridge header\n  // http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header\n  let gbcType = eightBitLoadFromGBMemory(0x0143);\n\n  // Detecting GBC http://bgb.bircd.org/pandocs.htm#cgbregisters\n  if (gbcType === 0xc0 || (Config.useGbcWhenAvailable && gbcType === 0x80)) {\n    Cpu.GBCEnabled = true;\n  } else {\n    Cpu.GBCEnabled = false;\n  }\n\n  // Reset hasStarted, since we are now reset\n  setHasCoreStarted(false);\n\n  // Reset our cycles ran\n  resetCycles();\n  resetSteps();\n\n  if (Config.enableBootRom) {\n    Cpu.BootROMEnabled = true;\n  } else {\n    Cpu.BootROMEnabled = false;\n  }\n\n  // Call our respective classes intialization\n  // NOTE: Boot ROM Only handles some initialization, thus we need to check in each one\n  // respecitvely :p\n  initializeCpu();\n  initializeCartridge();\n  initializeDma();\n  initializeGraphics();\n  initializePalette();\n  initializeSound();\n  initializeInterrupts();\n  initializeTimers();\n  initializeSerial();\n  initializeVarious();\n}\n\nfunction initializeVarious(): void {\n  // Various Other Registers\n  if (Cpu.GBCEnabled) {\n    // Various other registers\n    eightBitStoreIntoGBMemory(0xff70, 0xf8);\n    eightBitStoreIntoGBMemory(0xff4f, 0xfe);\n    eightBitStoreIntoGBMemory(0xff4d, 0x7e);\n    eightBitStoreIntoGBMemory(0xff00, 0xcf);\n\n    eightBitStoreIntoGBMemory(0xff0f, 0xe1);\n    // 0xFFFF = 0x00\n\n    // Undocumented from Pandocs\n    eightBitStoreIntoGBMemory(0xff6c, 0xfe);\n    eightBitStoreIntoGBMemory(0xff75, 0x8f);\n  } else {\n    eightBitStoreIntoGBMemory(0xff70, 0xff);\n    eightBitStoreIntoGBMemory(0xff4f, 0xff);\n    eightBitStoreIntoGBMemory(0xff4d, 0xff);\n    eightBitStoreIntoGBMemory(0xff00, 0xcf);\n\n    eightBitStoreIntoGBMemory(0xff0f, 0xe1);\n    // 0xFFFF = 0x00\n  }\n}\n\n// Function to return if we are currently playing a GBC ROM\nexport function isGBC(): i32 {\n  return <i32>Cpu.GBCEnabled;\n}\n\n// Function to return an address to store into save state memory\n// this is to regulate our 20 slots\n// https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing\n// Inlined because closure compiler inlines\nexport function getSaveStateMemoryOffset(offset: i32, saveStateSlot: i32): i32 {\n  // 50 bytes per save state memory partiton sli32\n  return WASMBOY_STATE_LOCATION + offset + 50 * saveStateSlot;\n}\n\n// Function to save state to memory for all of our classes\nexport function saveState(): void {\n  Cpu.saveState();\n  Graphics.saveState();\n  Interrupts.saveState();\n  Joypad.saveState();\n  Memory.saveState();\n  Timers.saveState();\n  Sound.saveState();\n  Channel1.saveState();\n  Channel2.saveState();\n  Channel3.saveState();\n  Channel4.saveState();\n\n  // Reset hasStarted, since we are now reset\n  setHasCoreStarted(false);\n\n  // Don't want to reset cycles here, as this does not reset the emulator\n}\n\n// Function to load state from memory for all of our classes\nexport function loadState(): void {\n  Cpu.loadState();\n  Graphics.loadState();\n  Interrupts.loadState();\n  Joypad.loadState();\n  Memory.loadState();\n  Timers.loadState();\n  Sound.loadState();\n  Channel1.loadState();\n  Channel2.loadState();\n  Channel3.loadState();\n  Channel4.loadState();\n\n  // Reset hasStarted, since we are now reset\n  setHasCoreStarted(false);\n\n  // Reset our cycles ran\n  resetCycles();\n  resetSteps();\n}\n","// Load/Read functionality for memory\nimport { checkReadTraps } from './readTraps';\nimport { getWasmBoyOffsetFromGameBoyOffset } from './memoryMap';\nimport { concatenateBytes } from '../helpers/index';\nimport { Breakpoints } from '../debug/breakpoints';\n\nexport function eightBitLoadFromGBMemory(gameboyOffset: i32): i32 {\n  return <i32>load<u8>(getWasmBoyOffsetFromGameBoyOffset(gameboyOffset));\n}\n\nexport function eightBitLoadFromGBMemoryWithTraps(offset: i32): i32 {\n  if (offset === Breakpoints.readGbMemory) {\n    Breakpoints.reachedBreakpoint = true;\n  }\n\n  let readTrapResult = checkReadTraps(offset);\n  return readTrapResult === -1 ? eightBitLoadFromGBMemory(offset) : <u8>readTrapResult;\n}\n\n// TODO: Rename this to sixteenBitLoadFromGBMemoryWithTraps\n// Inlined because closure compiler inlines\nexport function sixteenBitLoadFromGBMemory(offset: i32): i32 {\n  // Get our low byte\n  let lowByteReadTrapResult = checkReadTraps(offset);\n  let lowByte = lowByteReadTrapResult === -1 ? eightBitLoadFromGBMemory(offset) : lowByteReadTrapResult;\n\n  // Get the next offset for the second byte\n  let nextOffset = offset + 1;\n\n  // Get our high byte\n  let highByteReadTrapResult = checkReadTraps(nextOffset);\n  let highByte = highByteReadTrapResult === -1 ? eightBitLoadFromGBMemory(nextOffset) : highByteReadTrapResult;\n\n  // Concatenate the bytes and return\n  return concatenateBytes(highByte, lowByte);\n}\n\nexport function loadBooleanDirectlyFromWasmMemory(offset: i32): boolean {\n  return <i32>load<u8>(offset) > 0;\n}\n","// WasmBoy memory map:\n// https://docs.google.com/spreadsheets/d/17xrEzJk5-sCB9J2mMJcVnzhbE-XH_NvczVSQH9OHvRk/edit?usp=sharing\nimport {\n  VIDEO_RAM_LOCATION,\n  WORK_RAM_LOCATION,\n  OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION,\n  CARTRIDGE_RAM_LOCATION,\n  BOOT_ROM_LOCATION,\n  CARTRIDGE_ROM_LOCATION\n} from '../constants';\nimport { Memory } from './memory';\nimport { eightBitLoadFromGBMemory } from './load';\nimport { getRomBankAddress, getRamBankAddress } from './banking';\nimport { Cpu } from '../cpu/index';\n\n// Private function to translate a offset meant for the gameboy memory map\n// To the wasmboy memory map\n// Following: http://gameboy.mongenel.com/dmg/asmmemmap.html\n// And https://github.com/Dooskington/GameLad/wiki/Part-11---Memory-Bank-Controllers\n// Performance help from @dcodeIO, and awesome-gbdev\nexport function getWasmBoyOffsetFromGameBoyOffset(gameboyOffset: i32): i32 {\n  // Get the top byte and switch\n  let gameboyOffsetHighByte = gameboyOffset >> 12;\n  switch (gameboyOffsetHighByte) {\n    case 0x00:\n      // Check if we are currently executing the boot rom\n      // Otherwise, bottom 0x0000 -> 0x03FF is Cartridge ROM Ram Bank 1\n      if (Cpu.BootROMEnabled) {\n        if (Cpu.GBCEnabled) {\n          // See: http://gbdev.gg8.se/wiki/articles/Gameboy_Bootstrap_ROM\n          // \"The rom dump includes the 256 byte rom (0x0000-0x00FF) and the,\n          // 1792 byte rom (0x0200-0x08FF) which Dr. Decapitator observed,\n          // but not the 512 byte rom,\n          // which may be cpu microcode or lcd color lookup related.\"\n\n          // First 0xFF bytes are BOOT rom\n          if (gameboyOffset < 0x0100) {\n            return gameboyOffset + BOOT_ROM_LOCATION;\n          }\n\n          // 0x100 -> 0x1FF is the actual ROM\n\n          // Everything from 0x200 -> 0x8FF is BOOT ROM Again\n          if (gameboyOffset > 0x01ff && gameboyOffset < 0x0900) {\n            return gameboyOffset + BOOT_ROM_LOCATION;\n          }\n        } else if (!Cpu.GBCEnabled && gameboyOffset < 0x0100) {\n          return gameboyOffset + BOOT_ROM_LOCATION;\n        }\n      }\n    case 0x01:\n    case 0x02:\n    case 0x03:\n      // Cartridge ROM - Bank 0 (fixed)\n      // 0x0000 -> 0x0D2400\n      return gameboyOffset + CARTRIDGE_ROM_LOCATION;\n    case 0x04:\n    case 0x05:\n    case 0x06:\n    case 0x07:\n      // Cartridge ROM - Switchable Banks 1-xx\n      // 0x4000 -> (0x0D2400 + 0x4000)\n      return getRomBankAddress(gameboyOffset) + CARTRIDGE_ROM_LOCATION;\n    case 0x08:\n    case 0x09:\n      // Video RAM\n      // 0x8000 -> 0x000400\n      let vramBankId = 0;\n      if (Cpu.GBCEnabled) {\n        // Find our current VRAM Bank\n        vramBankId = eightBitLoadFromGBMemory(Memory.memoryLocationGBCVRAMBank) & 0x01;\n        // Even though We added another 0x2000, the Cartridge ram is pulled out of our Internal Memory Space\n        // Therefore, we do not need to adjust for this extra 0x2000\n      }\n\n      return gameboyOffset - Memory.videoRamLocation + VIDEO_RAM_LOCATION + 0x2000 * vramBankId;\n    case 0x0a:\n    case 0x0b:\n      // Cartridge RAM - A.K.A External RAM\n      // 0xA000 -> 0x008400\n      return getRamBankAddress(gameboyOffset) + CARTRIDGE_RAM_LOCATION;\n    case 0x0c:\n      // Gameboy Ram Bank 0\n      // 0xC000 -> 0x000400\n      // Don't need to add head, since we move out 0x200 from the cartridge ram\n      return gameboyOffset - Memory.internalRamBankZeroLocation + WORK_RAM_LOCATION;\n    case 0x0d:\n      // Gameboy Ram Banks, Switchable in GBC Mode\n      // 0xD000 -> 0x000400\n      // In CGB Mode 32 KBytes internal RAM are available.\n      // This memory is divided into 8 banks of 4 KBytes each.\n      // Bank 0 is always available in memory at C000-CFFF,\n      // Bank 1-7 can be selected into the address space at D000-DFFF.\n      // http://gbdev.gg8.se/wiki/articles/CGB_Registers#FF70_-_SVBK_-_CGB_Mode_Only_-_WRAM_Bank\n      // Get the last 3 bits to find our wram ID\n      let wramBankId = 0;\n      if (Cpu.GBCEnabled) {\n        wramBankId = eightBitLoadFromGBMemory(Memory.memoryLocationGBCWRAMBank) & 0x07;\n      }\n      wramBankId = wramBankId < 1 ? 1 : wramBankId;\n      // (0x1000 * (wramBankId - 1)) -> To find the correct wram bank.\n      // wramBankId - 1, because we alreayd have the space for wramBank 1, and are currently in it\n      // So need to address space for 6 OTHER banks\n      return gameboyOffset - Memory.internalRamBankZeroLocation + WORK_RAM_LOCATION + 0x1000 * (wramBankId - 1);\n    default:\n      // Everything Else after Gameboy Ram Banks\n      // 0xE000 -> 0x000400\n      // 0x6000 For the Extra WRAM Banks\n      return gameboyOffset - Memory.echoRamLocation + OTHER_GAMEBOY_INTERNAL_MEMORY_LOCATION;\n  }\n}\n","// Function to handle rom/rambanking\nimport { Memory } from './memory';\nimport { concatenateBytes, checkBitOnByte, splitLowByte } from '../helpers/index';\n\n// Inlined because closure compiler inlines\nexport function handleBanking(offset: i32, value: i32): void {\n  // Is rom Only does not bank\n  if (Memory.isRomOnly) {\n    return;\n  }\n\n  let isMBC1 = Memory.isMBC1;\n  let isMBC2 = Memory.isMBC2;\n\n  // Enable Ram Banking\n  if (offset <= 0x1fff) {\n    if (isMBC2 && !checkBitOnByte(4, <u8>value)) {\n      // Do Nothing\n      return;\n    } else {\n      let romEnableByte = value & 0x0f;\n      if (romEnableByte === 0x00) {\n        Memory.isRamBankingEnabled = false;\n      } else if (romEnableByte === 0x0a) {\n        Memory.isRamBankingEnabled = true;\n      }\n    }\n  } else if (offset <= 0x3fff) {\n    let isMBC5 = Memory.isMBC5;\n    if (!isMBC5 || offset <= 0x2fff) {\n      // Change Low Bits on the Current Rom Bank\n      let currentRomBank = Memory.currentRomBank;\n      if (isMBC2) {\n        currentRomBank = value & 0x0f;\n      }\n\n      // Set the number of bottom bytes from the MBC type\n      let romBankLowerBits = value;\n      if (isMBC1) {\n        // Only want the bottom 5\n        romBankLowerBits = romBankLowerBits & 0x1f;\n        currentRomBank &= 0xe0;\n      } else if (Memory.isMBC3) {\n        // Only Want the bottom 7\n        romBankLowerBits = romBankLowerBits & 0x7f;\n        currentRomBank &= 0x80;\n      } else if (isMBC5) {\n        // Going to switch the whole thing\n        currentRomBank &= 0x00;\n      }\n\n      // Set the lower bytes\n      currentRomBank |= romBankLowerBits;\n      Memory.currentRomBank = currentRomBank;\n      return;\n    } else {\n      // TODO: MBC5 High bits Rom bank, check if this works, not sure about the value\n      let lowByte = splitLowByte(Memory.currentRomBank);\n      let highByte = <i32>(value > 0);\n      Memory.currentRomBank = concatenateBytes(highByte, lowByte);\n    }\n  } else if (!isMBC2 && offset <= 0x5fff) {\n    // ROM / RAM Banking, MBC2 doesn't do this\n    if (isMBC1 && Memory.isMBC1RomModeEnabled) {\n      // Do an upper bit rom bank for MBC 1\n      // Remove upper bits of currentRomBank\n      let currentRomBank = Memory.currentRomBank & 0x1f;\n      let romBankHigherBits = value & 0xe0;\n\n      currentRomBank |= romBankHigherBits;\n      Memory.currentRomBank = currentRomBank;\n      return;\n    }\n\n    if (Memory.isMBC3) {\n      if (value >= 0x08 && value <= 0x0c) {\n        // TODO: MBC3 RTC Register Select\n      }\n    }\n\n    let ramBankBits: i32 = value;\n\n    if (!Memory.isMBC5) {\n      // Get the bottom 2 bits\n      ramBankBits &= 0x03;\n    } else {\n      // Get the bottom nibble\n      ramBankBits &= 0x0f;\n    }\n\n    // Set our ram bank\n    Memory.currentRamBank = ramBankBits;\n    return;\n  } else if (!isMBC2 && offset <= 0x7fff) {\n    if (isMBC1) {\n      Memory.isMBC1RomModeEnabled = checkBitOnByte(0, <u8>value);\n    }\n    // TODO: MBC3 Latch Clock Data\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function getRomBankAddress(gameboyOffset: i32): i32 {\n  let currentRomBank: u32 = Memory.currentRomBank;\n  if (!Memory.isMBC5 && currentRomBank === 0) {\n    currentRomBank = 1;\n  }\n\n  // Adjust our gameboy offset relative to zero for the gameboy memory map\n  return <i32>(0x4000 * currentRomBank + (gameboyOffset - Memory.switchableCartridgeRomLocation));\n}\n\n// Inlined because closure compiler inlines\nexport function getRamBankAddress(gameboyOffset: i32): i32 {\n  // Adjust our gameboy offset relative to zero for the gameboy memory map\n  return <i32>(0x2000 * Memory.currentRamBank + (gameboyOffset - Memory.cartridgeRamLocation));\n}\n","// Store / Write memory access\nimport { checkWriteTraps } from './writeTraps';\nimport { getWasmBoyOffsetFromGameBoyOffset } from './memoryMap';\nimport { splitHighByte, splitLowByte } from '../helpers/index';\nimport { Breakpoints } from '../debug/breakpoints';\n\nexport function eightBitStoreIntoGBMemory(gameboyOffset: i32, value: i32): void {\n  store<u8>(getWasmBoyOffsetFromGameBoyOffset(gameboyOffset), value);\n}\n\nexport function eightBitStoreIntoGBMemoryWithTraps(offset: i32, value: i32): void {\n  if (offset === Breakpoints.writeGbMemory) {\n    Breakpoints.reachedBreakpoint = true;\n  }\n\n  if (checkWriteTraps(offset, value)) {\n    eightBitStoreIntoGBMemory(offset, value);\n  }\n}\n\nexport function sixteenBitStoreIntoGBMemoryWithTraps(offset: i32, value: i32): void {\n  // Dividing into two seperate eight bit calls to help with debugging tilemap overwrites\n  // Split the value into two seperate bytes\n  let highByte = splitHighByte(value);\n  let lowByte = splitLowByte(value);\n\n  if (checkWriteTraps(offset, lowByte)) {\n    eightBitStoreIntoGBMemory(offset, lowByte);\n  }\n\n  let nextOffset = offset + 1;\n  if (checkWriteTraps(nextOffset, highByte)) {\n    eightBitStoreIntoGBMemory(nextOffset, highByte);\n  }\n}\n\nexport function sixteenBitStoreIntoGBMemory(offset: i32, value: i32): void {\n  // Dividing into two seperate eight bit calls to help with debugging tilemap overwrites\n  // Split the value into two seperate bytes\n  let highByte = splitHighByte(value);\n  let lowByte = splitLowByte(value);\n\n  eightBitStoreIntoGBMemory(offset + 0, lowByte);\n  eightBitStoreIntoGBMemory(offset + 1, highByte);\n}\n\nexport function storeBooleanDirectlyToWasmMemory(offset: i32, value: boolean): void {\n  store<u8>(offset, <i32>value);\n}\n","import { Cpu } from '../cpu/index';\nimport { Memory } from './memory';\nimport { eightBitLoadFromGBMemoryWithTraps, eightBitLoadFromGBMemory } from './load';\nimport { eightBitStoreIntoGBMemoryWithTraps, eightBitStoreIntoGBMemory } from './store';\nimport { concatenateBytes, checkBitOnByte, setBitOnByte, resetBitOnByte } from '../helpers/index';\n\n// Inlined because closure compiler inlines\nexport function initializeDma(): void {\n  if (Cpu.GBCEnabled) {\n    // GBC DMA\n    eightBitStoreIntoGBMemory(0xff51, 0xff);\n    eightBitStoreIntoGBMemory(0xff52, 0xff);\n    eightBitStoreIntoGBMemory(0xff53, 0xff);\n    eightBitStoreIntoGBMemory(0xff54, 0xff);\n    eightBitStoreIntoGBMemory(0xff55, 0xff);\n  } else {\n    // GB DMA\n    eightBitStoreIntoGBMemory(0xff51, 0xff);\n    eightBitStoreIntoGBMemory(0xff52, 0xff);\n    eightBitStoreIntoGBMemory(0xff53, 0xff);\n    eightBitStoreIntoGBMemory(0xff54, 0xff);\n    eightBitStoreIntoGBMemory(0xff55, 0xff);\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function startDmaTransfer(sourceAddressOffset: i32): void {\n  let sourceAddress = sourceAddressOffset << 8;\n  for (let i = 0; i <= 0x9f; ++i) {\n    let spriteInformationByte = eightBitLoadFromGBMemory(sourceAddress + i);\n    let spriteInformationAddress = Memory.spriteInformationTableLocation + i;\n    eightBitStoreIntoGBMemory(spriteInformationAddress, spriteInformationByte);\n  }\n\n  // TCAGBD:  This copy (DMA) needs 160 × 4 + 4 clocks to complete in both double speed and single speeds modes\n  // Increment all of our Cycle coiunters in ../cpu/opcodes\n  Memory.DMACycles = 644;\n}\n\n// https://gist.github.com/drhelius/3394856\n// http://bgb.bircd.org/pandocs.htm\n// Inlined because closure compiler inlines\nexport function startHdmaTransfer(hdmaTriggerByteToBeWritten: i32): void {\n  // Check if we are Gbc\n  if (!Cpu.GBCEnabled) {\n    return;\n  }\n\n  // Check if we are trying to terminate an already active HBLANK HDMA\n  if (Memory.isHblankHdmaActive && !checkBitOnByte(7, hdmaTriggerByteToBeWritten)) {\n    // Don't reset anything, just set bit 7 to 1 on the trigger byte\n    Memory.isHblankHdmaActive = false;\n    let hdmaTriggerByte = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaTrigger);\n    eightBitStoreIntoGBMemory(Memory.memoryLocationHdmaTrigger, setBitOnByte(7, hdmaTriggerByte));\n    return;\n  }\n\n  // Get our source and destination for the HDMA\n  let hdmaSource = getHdmaSourceFromMemory();\n  let hdmaDestination = getHdmaDestinationFromMemory();\n\n  // Get the length from the trigger\n  // Lower 7 bits, Add 1, times 16\n  // https://gist.github.com/drhelius/3394856\n  let transferLength = resetBitOnByte(7, hdmaTriggerByteToBeWritten);\n  transferLength = (transferLength + 1) << 4;\n\n  // Get bit 7 of the trigger for the HDMA type\n  if (checkBitOnByte(7, hdmaTriggerByteToBeWritten)) {\n    // H-Blank DMA\n    Memory.isHblankHdmaActive = true;\n    Memory.hblankHdmaTransferLengthRemaining = transferLength;\n    Memory.hblankHdmaSource = hdmaSource;\n    Memory.hblankHdmaDestination = hdmaDestination;\n\n    // This will be handled in updateHblankHdma()\n\n    // Since we return false in write traps, we need to now write the byte\n    // Be sure to reset bit 7, to show that the hdma is active\n    eightBitStoreIntoGBMemory(Memory.memoryLocationHdmaTrigger, resetBitOnByte(7, hdmaTriggerByteToBeWritten));\n  } else {\n    // General DMA\n    hdmaTransfer(hdmaSource, hdmaDestination, transferLength);\n\n    // Stop the DMA\n    eightBitStoreIntoGBMemory(Memory.memoryLocationHdmaTrigger, 0xff);\n  }\n}\n\n// Inlined because closure compiler inlines\nexport function updateHblankHdma(): void {\n  if (!Memory.isHblankHdmaActive) {\n    return;\n  }\n\n  // Get our amount of bytes to transfer (Only 0x10 bytes at a time)\n  let bytesToTransfer = 0x10;\n  let hblankHdmaTransferLengthRemaining = Memory.hblankHdmaTransferLengthRemaining;\n  if (hblankHdmaTransferLengthRemaining < bytesToTransfer) {\n    // Set to the difference\n    bytesToTransfer = hblankHdmaTransferLengthRemaining;\n  }\n\n  // Do the transfer (Only 0x10 bytes at a time)\n  hdmaTransfer(Memory.hblankHdmaSource, Memory.hblankHdmaDestination, bytesToTransfer);\n\n  // Update our source and destination\n  Memory.hblankHdmaSource += bytesToTransfer;\n  Memory.hblankHdmaDestination += bytesToTransfer;\n  hblankHdmaTransferLengthRemaining -= bytesToTransfer;\n  Memory.hblankHdmaTransferLengthRemaining = hblankHdmaTransferLengthRemaining;\n\n  let memoryLocationHdmaTrigger = Memory.memoryLocationHdmaTrigger;\n  if (hblankHdmaTransferLengthRemaining <= 0) {\n    // End the transfer\n    Memory.isHblankHdmaActive = false;\n    // Need to clear the HDMA with 0xFF, which sets bit 7 to 1 to show the HDMA has ended\n    eightBitStoreIntoGBMemory(memoryLocationHdmaTrigger, 0xff);\n  } else {\n    // Set our new transfer length, make sure it is in the weird format,\n    // and make sure bit 7 is 0, to show that the HDMA is Active\n    let remainingTransferLength = hblankHdmaTransferLengthRemaining;\n    let transferLengthAsByte = (remainingTransferLength >> 4) - 1;\n    eightBitStoreIntoGBMemory(memoryLocationHdmaTrigger, resetBitOnByte(7, transferLengthAsByte));\n  }\n}\n\n// Simple Function to transfer the bytes from a destination to a source for a general pourpose or Hblank HDMA\nfunction hdmaTransfer(hdmaSource: i32, hdmaDestination: i32, transferLength: i32): void {\n  for (let i = 0; i < transferLength; ++i) {\n    let sourceByte = eightBitLoadFromGBMemoryWithTraps(hdmaSource + i);\n    // get the hdmaDestination with wrapping\n    // See issue #61: https://github.com/torch2424/wasmBoy/issues/61\n    let hdmaDestinationWithWrapping = hdmaDestination + i;\n    while (hdmaDestinationWithWrapping > 0x9fff) {\n      // Simply clear the top 3 bits\n      hdmaDestinationWithWrapping -= 0x2000;\n    }\n    eightBitStoreIntoGBMemoryWithTraps(hdmaDestinationWithWrapping, sourceByte);\n  }\n\n  // Set our Cycles used for the HDMA\n  // Since DMA in GBC Double Speed Mode takes 80 micro seconds,\n  // And HDMA takes 8 micro seconds per 0x10 bytes in GBC Double Speed mode (and GBC Normal Mode)\n  // Will assume (644 / 10) cycles for GBC Double Speed Mode,\n  // and (644 / 10 / 2) for GBC Normal Mode\n  let hdmaCycles = 32 << (<i32>Cpu.GBCDoubleSpeed);\n  hdmaCycles = hdmaCycles * (transferLength >> 4);\n  Memory.DMACycles += hdmaCycles;\n}\n\n// Function to get our HDMA Source\n// Follows the poan docs\n// Inlined because closure compiler inlines\nfunction getHdmaSourceFromMemory(): i32 {\n  // Get our source for the HDMA\n  let hdmaSourceHigh = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaSourceHigh);\n  let hdmaSourceLow = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaSourceLow);\n\n  let hdmaSource = concatenateBytes(hdmaSourceHigh, hdmaSourceLow);\n\n  // And off the appopriate bits for the source and destination\n  // And off the bottom 4 bits\n  hdmaSource = hdmaSource & 0xfff0;\n\n  return hdmaSource;\n}\n\n// Function to get our HDMA Destination\n// Follows the poan docs\n// Inlined because closure compiler inlines\nfunction getHdmaDestinationFromMemory(): i32 {\n  let hdmaDestinationHigh = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaDestinationHigh);\n  let hdmaDestinationLow = eightBitLoadFromGBMemory(Memory.memoryLocationHdmaDestinationLow);\n\n  let hdmaDestination = concatenateBytes(hdmaDestinationHigh, hdmaDestinationLow);\n\n  // Can only be in VRAM, 0x8000 -> 0x9FF0\n  // Pan docs says to knock off upper 3 bits, and lower 4 bits\n  // Which gives us: 0001111111110000 or 0x1FF0\n  // Meaning we must add 0x8000\n  hdmaDestination = hdmaDestination & 0x1ff0;\n  hdmaDestination += Memory.videoRamLocation;\n\n  return hdmaDestination;\n}\n","import { getCarryFlag } from '../cpu/index';\nimport { u8Portable } from '../portable/portable';\n\n// Grouped registers\n// possible overload these later to performace actions\n// AF, BC, DE, HL\nexport function concatenateBytes(highByte: i32, lowByte: i32): i32 {\n  //https://stackoverflow.com/questions/38298412/convert-two-bytes-into-signed-16-bit-integer-in-javascript\n  return ((highByte & 0xff) << 8) | (lowByte & 0xff);\n}\n\nexport function splitHighByte(groupedByte: i32): i32 {\n  return (groupedByte & 0xff00) >> 8;\n}\n\nexport function splitLowByte(groupedByte: i32): i32 {\n  return groupedByte & 0x00ff;\n}\n\nexport function rotateByteLeft(value: u8): u8 {\n  // Rotate left\n  // https://stackoverflow.com/questions/19204750/how-do-i-perform-a-circular-rotation-of-a-byte\n  // 4-bit example:\n  // 1010 -> 0100 | 0001\n  return u8Portable((value << 1) | (value >> 7));\n}\n\nexport function rotateByteLeftThroughCarry(value: u8): u8 {\n  // Example: https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // Through carry meaning, instead of raotating the bit that gets dropped off, but the carry there instead\n  return u8Portable((value << 1) | getCarryFlag());\n}\n\nexport function rotateByteRight(value: u8): u8 {\n  // Rotate right\n  // 4-bit example:\n  // 1010 -> 0101 | 0000\n  return u8Portable((value >> 1) | (value << 7));\n}\n\nexport function rotateByteRightThroughCarry(value: u8): u8 {\n  // Example: https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // Through carry meaning, instead of raotating the bit that gets dropped off, put the carry there instead\n  return u8Portable((value >> 1) | (getCarryFlag() << 7));\n}\n\nexport function setBitOnByte(bitPosition: i32, byte: i32): i32 {\n  return byte | (0x01 << bitPosition);\n}\n\nexport function resetBitOnByte(bitPosition: i32, byte: i32): i32 {\n  return byte & ~(0x01 << bitPosition);\n}\n\nexport function checkBitOnByte(bitPosition: i32, byte: i32): boolean {\n  // Perforamnce improvements\n  // https://github.com/AssemblyScript/assemblyscript/issues/40\n  return (byte & (1 << bitPosition)) != 0;\n}\n\n// Declared importObject functions\ndeclare function consoleLog(arg0: i32, arg1: i32): void;\ndeclare function consoleLogTimeout(arg0: i32, arg1: i32, timeout: i32): void;\n\nexport function log(arg0: i32, arg1: i32): void {\n  consoleLog(arg0, arg1);\n}\n\nexport function logTimeout(arg0: i32, arg1: i32, timeout: i32): void {\n  consoleLogTimeout(arg0, arg1, timeout);\n}\n","// Imports\nimport { Cpu } from './index';\nimport { handleCbOpcode } from './cbOpcodes';\nimport {\n  setZeroFlag,\n  getZeroFlag,\n  setSubtractFlag,\n  getSubtractFlag,\n  setHalfCarryFlag,\n  getHalfCarryFlag,\n  setCarryFlag,\n  getCarryFlag,\n  checkAndSetEightBitHalfCarryFlag,\n  checkAndSetSixteenBitFlagsAddOverflow\n} from './flags';\nimport {\n  addARegister,\n  addAThroughCarryRegister,\n  subARegister,\n  subAThroughCarryRegister,\n  andARegister,\n  xorARegister,\n  orARegister,\n  cpARegister,\n  relativeJump\n} from './instructions';\nimport { syncCycles } from '../cycles';\nimport {\n  rotateByteLeft,\n  rotateByteLeftThroughCarry,\n  rotateByteRight,\n  rotateByteRightThroughCarry,\n  concatenateBytes,\n  splitHighByte,\n  splitLowByte,\n  checkBitOnByte,\n  resetBitOnByte,\n  setBitOnByte\n} from '../helpers/index';\nimport {\n  Memory,\n  eightBitLoadFromGBMemoryWithTraps,\n  eightBitStoreIntoGBMemoryWithTraps,\n  sixteenBitStoreIntoGBMemoryWithTraps,\n  eightBitLoadFromGBMemory,\n  sixteenBitLoadFromGBMemory\n} from '../memory/index';\nimport { setInterrupts } from '../interrupts/index';\nimport { u8Portable, u16Portable, i8Portable } from '../portable/portable';\n\n// Take in any opcode, and decode it, and return the number of cycles\n// Program counter can be gotten from getProgramCounter();\n// Setting return value to i32 instead of u16, as we want to return a negative number on error\n// https://rednex.github.io/rgbds/gbz80.7.html\n// http://pastraiser.com/cpu/gameboy/gameboyopcodes.html\nexport function executeOpcode(opcode: i32): i32 {\n  // Always implement the program counter by one\n  // Any other value can just subtract or add however much offset before reaching this line\n  let programCounter = Cpu.programCounter;\n  programCounter = u16Portable(programCounter + 1);\n\n  // Check if we are in the halt bug\n  if (Cpu.isHaltBug) {\n    // Need to not increment program counter,\n    // thus, running the next opcode twice\n\n    // E.g\n    // 0x76 - halt\n    // FA 34 12 - ld a,(1234)\n    // Becomes\n    // FA FA 34 ld a,(34FA)\n    // 12 ld (de),a\n    programCounter = u16Portable(programCounter - 1);\n  }\n  Cpu.programCounter = programCounter;\n\n  // Split our opcode into a high nibble to speed up performance\n  // Running 255 if statements is slow, even in wasm haha!\n  let opcodeHighNibble = opcode & 0xf0;\n  opcodeHighNibble = opcodeHighNibble >> 4;\n\n  // NOTE: @binji rule of thumb: it takes 4 cpu cycles to read one byte\n  // Therefore isntructions that use more than just the opcode (databyte one and two) will take at least\n  // 8 cyckles to use getDataByteOne(), and two cycles to use the concatented\n\n  // Not using a switch statement to avoid cannot redeclare this variable errors\n  // And it would be a ton of work :p\n\n  switch (opcodeHighNibble) {\n    case 0x00:\n      return handleOpcode0x(opcode);\n    case 0x01:\n      return handleOpcode1x(opcode);\n    case 0x02:\n      return handleOpcode2x(opcode);\n    case 0x03:\n      return handleOpcode3x(opcode);\n    case 0x04:\n      return handleOpcode4x(opcode);\n    case 0x05:\n      return handleOpcode5x(opcode);\n    case 0x06:\n      return handleOpcode6x(opcode);\n    case 0x07:\n      return handleOpcode7x(opcode);\n    case 0x08:\n      return handleOpcode8x(opcode);\n    case 0x09:\n      return handleOpcode9x(opcode);\n    case 0x0a:\n      return handleOpcodeAx(opcode);\n    case 0x0b:\n      return handleOpcodeBx(opcode);\n    case 0x0c:\n      return handleOpcodeCx(opcode);\n    case 0x0d:\n      return handleOpcodeDx(opcode);\n    case 0x0e:\n      return handleOpcodeEx(opcode);\n    default:\n      return handleOpcodeFx(opcode);\n  }\n}\n\n// Wrapper functions around loading and storing memory, and syncing those cycles\nexport function eightBitLoadSyncCycles(gameboyOffset: i32): u8 {\n  syncCycles(4);\n  return <u8>eightBitLoadFromGBMemoryWithTraps(gameboyOffset);\n}\n\nexport function eightBitStoreSyncCycles(gameboyOffset: i32, value: i32): void {\n  syncCycles(4);\n  eightBitStoreIntoGBMemoryWithTraps(gameboyOffset, value);\n}\n\nexport function sixteenBitLoadSyncCycles(gameboyOffset: i32): u16 {\n  syncCycles(8);\n  // sixteen bit load has traps even though it has no label\n  return <u16>sixteenBitLoadFromGBMemory(gameboyOffset);\n}\n\nexport function sixteenBitStoreSyncCycles(gameboyOffset: i32, value: i32): void {\n  syncCycles(8);\n  sixteenBitStoreIntoGBMemoryWithTraps(gameboyOffset, value);\n}\n\n// Functions to access the next operands of a opcode, reffering to them as \"dataBytes\"\nfunction getDataByteOne(): u8 {\n  syncCycles(4);\n  return <u8>eightBitLoadFromGBMemory(Cpu.programCounter);\n}\n\nfunction getDataByteTwo(): u8 {\n  syncCycles(4);\n  return <u8>eightBitLoadFromGBMemory(u16Portable(Cpu.programCounter + 1));\n}\n// Get our concatenated databyte one and getDataByteTwo()\n// Find and replace with : getConcatenatedDataByte()\nfunction getConcatenatedDataByte(): u16 {\n  return <u16>concatenateBytes(getDataByteTwo(), getDataByteOne());\n}\n\nfunction handleOpcode0x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x00:\n      // NOP\n      // 1  4\n      // No Operation\n      return 4;\n    case 0x01: {\n      // LD BC,d16\n      // 3  12\n\n      // 8 cycles\n      let concatenatedDataByte: i32 = getConcatenatedDataByte();\n\n      Cpu.registerB = <u8>splitHighByte(concatenatedDataByte);\n      Cpu.registerC = <u8>splitLowByte(concatenatedDataByte);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n\n      return 4;\n    }\n    case 0x02: {\n      // LD (BC),A\n      // 1  8\n      // () means load into address pointed by BC\n\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerB, Cpu.registerC), Cpu.registerA);\n      return 4;\n    }\n    case 0x03: {\n      // INC BC\n      // 1  8\n      let registerBC3: u16 = <u16>concatenateBytes(Cpu.registerB, Cpu.registerC);\n      registerBC3++;\n      Cpu.registerB = <u8>splitHighByte(registerBC3);\n      Cpu.registerC = <u8>splitLowByte(registerBC3);\n      return 8;\n    }\n    case 0x04: {\n      // INC B\n      // 1  4\n      // Z 0 H -\n      let registerB = Cpu.registerB;\n      checkAndSetEightBitHalfCarryFlag(registerB, 1);\n      registerB = u8Portable(registerB + 1);\n      Cpu.registerB = registerB;\n      setZeroFlag(<i32>(registerB === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x05: {\n      // DEC B\n      // 1  4\n      // Z 1 H -\n      let registerB = Cpu.registerB;\n      checkAndSetEightBitHalfCarryFlag(registerB, -1);\n      registerB = u8Portable(registerB - 1);\n      Cpu.registerB = registerB;\n      setZeroFlag(<i32>(registerB === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x06: {\n      // LD B,d8\n      // 2  8\n\n      // 4 cycles\n      Cpu.registerB = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n\n      return 4;\n    }\n    case 0x07: {\n      // RLCA\n      // 1  4\n      // 0 0 0 C\n      // Check for the carry\n      let registerA = Cpu.registerA;\n      setCarryFlag(<i32>((registerA & 0x80) === 0x80));\n      Cpu.registerA = rotateByteLeft(registerA);\n      // Set all other flags to zero\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      return 4;\n    }\n    case 0x08: {\n      // LD (a16),SP\n      // 3  20\n      // Load the stack pointer into the 16 bit address represented by the two data bytes\n\n      // 16 cycles, 8 from data byte, 8 from sixteenbit store\n      sixteenBitStoreSyncCycles(getConcatenatedDataByte(), Cpu.stackPointer);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n\n      return 4;\n    }\n    case 0x09: {\n      // ADD HL,BC\n      // 1 8\n      // - 0 H C\n      let registerHL: u16 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      let registerBC9: u16 = <u16>concatenateBytes(Cpu.registerB, Cpu.registerC);\n      checkAndSetSixteenBitFlagsAddOverflow(<u16>registerHL, <u16>registerBC9, false);\n      let result: u16 = u16Portable(<u16>(registerHL + registerBC9));\n      Cpu.registerH = <u8>splitHighByte(<u16>result);\n      Cpu.registerL = <u8>splitLowByte(<u16>result);\n      setSubtractFlag(0);\n      return 8;\n    }\n    case 0x0a: {\n      // LD A,(BC)\n      // 1 8\n\n      // 4 cycles from load\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerB, Cpu.registerC));\n      return 4;\n    }\n    case 0x0b: {\n      // DEC BC\n      // 1  8\n      let registerBCB: u16 = <u16>concatenateBytes(Cpu.registerB, Cpu.registerC);\n      registerBCB = u16Portable(registerBCB - 1);\n      Cpu.registerB = <u8>splitHighByte(registerBCB);\n      Cpu.registerC = <u8>splitLowByte(registerBCB);\n      return 8;\n    }\n    case 0x0c: {\n      // INC C\n      // 1  4\n      // Z 0 H -\n      let registerC = Cpu.registerC;\n      checkAndSetEightBitHalfCarryFlag(registerC, 1);\n      registerC = u8Portable(registerC + 1);\n      Cpu.registerC = registerC;\n      setZeroFlag(<i32>(registerC === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x0d: {\n      // DEC C\n      // 1  4\n      // Z 1 H -\n      let registerC = Cpu.registerC;\n      checkAndSetEightBitHalfCarryFlag(registerC, -1);\n      registerC = u8Portable(registerC - 1);\n      Cpu.registerC = registerC;\n      setZeroFlag(<i32>(registerC === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x0e: {\n      // LD C,d8\n      // 2 8\n\n      // 4 cycles\n      Cpu.registerC = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n\n      return 4;\n    }\n    case 0x0f: {\n      // RRCA\n      // 1 4\n      // 0 0 0 C\n      // Check for the last bit, to see if it will be carried\n      let registerA = Cpu.registerA;\n      setCarryFlag(<i32>((registerA & 0x01) > 0));\n      Cpu.registerA = rotateByteRight(registerA);\n      // Set all other flags to zero\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      return 4;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcode1x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x10: {\n      // STOP 0\n      // 2 4\n      // Enter CPU very low power mode. Also used to switch between double and normal speed CPU modes in GBC.\n      // Meaning Don't Decode anymore opcodes , or updated the LCD until joypad interrupt (or when button is pressed if I am wrong)\n      // See HALT\n\n      // If we are in gameboy color mode, set the new speed\n      if (Cpu.GBCEnabled) {\n        // 4 cycles\n        let speedSwitch: i32 = eightBitLoadSyncCycles(Cpu.memoryLocationSpeedSwitch);\n        if (checkBitOnByte(0, speedSwitch)) {\n          // Reset the prepare bit\n          speedSwitch = resetBitOnByte(0, speedSwitch);\n\n          // Switch to the new mode, and set the speed switch to the OTHER speed, to represent our new speed\n          if (!checkBitOnByte(7, speedSwitch)) {\n            Cpu.GBCDoubleSpeed = true;\n            speedSwitch = setBitOnByte(7, speedSwitch);\n          } else {\n            Cpu.GBCDoubleSpeed = false;\n            speedSwitch = resetBitOnByte(7, speedSwitch);\n          }\n\n          // Store the final speed switch\n          // 4 cycles\n          eightBitStoreSyncCycles(Cpu.memoryLocationSpeedSwitch, speedSwitch);\n\n          // Cycle accurate gameboy docs says this takes 76 clocks\n          // 76 - 8 cycles (from load/store) = 68\n          return 68;\n        }\n      }\n\n      // NOTE: This breaks Blarggs CPU tests if CGB Stop is not implemented\n      Cpu.isStopped = true;\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x11: {\n      // LD DE,d16\n      // 3  12\n\n      // 8 cycles\n      let concatenatedDataByte = getConcatenatedDataByte();\n\n      Cpu.registerD = <u8>splitHighByte(concatenatedDataByte);\n      Cpu.registerE = <u8>splitLowByte(concatenatedDataByte);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    case 0x12: {\n      // LD (DE),A\n      // 1 8\n\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerD, Cpu.registerE), Cpu.registerA);\n      return 4;\n    }\n    case 0x13: {\n      // INC DE\n      // 1 8\n      let registerDE3 = <u16>concatenateBytes(Cpu.registerD, Cpu.registerE);\n      registerDE3 = u16Portable(registerDE3 + 1);\n      Cpu.registerD = <u8>splitHighByte(registerDE3);\n      Cpu.registerE = <u8>splitLowByte(registerDE3);\n      return 8;\n    }\n    case 0x14: {\n      // INC D\n      // 1  4\n      // Z 0 H -\n      let registerD = Cpu.registerD;\n      checkAndSetEightBitHalfCarryFlag(registerD, 1);\n      registerD = u8Portable(registerD + 1);\n      Cpu.registerD = registerD;\n      setZeroFlag(<i32>(Cpu.registerD === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x15: {\n      // DEC D\n      // 1  4\n      // Z 1 H -\n      let registerD = Cpu.registerD;\n      checkAndSetEightBitHalfCarryFlag(registerD, -1);\n      registerD = u8Portable(registerD - 1);\n      Cpu.registerD = registerD;\n      setZeroFlag(<i32>(Cpu.registerD === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x16: {\n      // LD D,d8\n      // 2 8\n\n      // 4 cycles\n      Cpu.registerD = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x17: {\n      // RLA\n      // 1 4\n      // 0 0 0 C\n      // Check for the carry\n      // setting has first bit since we need to use carry\n      let hasHighbit = (Cpu.registerA & 0x80) === 0x80;\n      Cpu.registerA = rotateByteLeftThroughCarry(Cpu.registerA);\n      // OR the carry flag to the end\n      setCarryFlag(<i32>hasHighbit);\n      // Set all other flags to zero\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      return 4;\n    }\n    case 0x18: {\n      // JR r8\n      // 2  12\n      // NOTE: Discoved dataByte is signed\n      // However the relative Jump Function handles this\n\n      // 4 cycles\n      relativeJump(getDataByteOne());\n      return 8;\n    }\n    // Relative Jump Function Handles program counter\n    case 0x19: {\n      // ADD HL,DE\n      // 1  8\n      // - 0 H C\n      let registerHL = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      let registerDE9 = <u16>concatenateBytes(Cpu.registerD, Cpu.registerE);\n      checkAndSetSixteenBitFlagsAddOverflow(<u16>registerHL, <u16>registerDE9, false);\n      let result = u16Portable(<u16>(registerHL + registerDE9));\n      Cpu.registerH = <u8>splitHighByte(<u16>result);\n      Cpu.registerL = <u8>splitLowByte(<u16>result);\n      setSubtractFlag(0);\n      return 8;\n    }\n    case 0x1a: {\n      // LD A,(DE)\n      // 1 8\n      let registerDEA = <u16>concatenateBytes(Cpu.registerD, Cpu.registerE);\n      // 4 cycles\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(registerDEA);\n      return 4;\n    }\n    case 0x1b: {\n      // DEC DE\n      // 1 8\n      let registerDEB = <u16>concatenateBytes(Cpu.registerD, Cpu.registerE);\n      registerDEB = u16Portable(registerDEB - 1);\n      Cpu.registerD = <u8>splitHighByte(registerDEB);\n      Cpu.registerE = <u8>splitLowByte(registerDEB);\n      return 8;\n    }\n    case 0x1c: {\n      // INC E\n      // 1  4\n      // Z 0 H -\n      let registerE = Cpu.registerE;\n      checkAndSetEightBitHalfCarryFlag(registerE, 1);\n      registerE = u8Portable(registerE + 1);\n      Cpu.registerE = registerE;\n      setZeroFlag(<i32>(registerE === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x1d: {\n      // DEC E\n      // 1  4\n      // Z 1 H -\n      let registerE = Cpu.registerE;\n      checkAndSetEightBitHalfCarryFlag(registerE, -1);\n      registerE = u8Portable(registerE - 1);\n      Cpu.registerE = registerE;\n      setZeroFlag(<i32>(registerE === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x1e: {\n      // LD E,d8\n      // 2 8\n\n      // 4 cycles\n      Cpu.registerE = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x1f: {\n      // RRA\n      // 1 4\n      // 0 0 0 C\n      // Check for the carry\n      // setting has low bit since we need to use carry\n      let hasLowBit = (Cpu.registerA & 0x01) === 0x01;\n      Cpu.registerA = rotateByteRightThroughCarry(Cpu.registerA);\n\n      setCarryFlag(<i32>hasLowBit);\n      // Set all other flags to zero\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      return 4;\n    }\n  }\n\n  return -1;\n}\n\nfunction handleOpcode2x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x20: {\n      // JR NZ,r8\n      // 2  12/8\n      // NOTE: NZ stands for not [flag], so in this case, not zero flag\n      // Also, / means, if condition. so if met, 12 cycles, otherwise 8 cycles\n      if (getZeroFlag() === 0) {\n        // 4 cycles\n        relativeJump(getDataByteOne());\n        // Relative Jump Funciton handles program counter\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      }\n      return 8;\n    }\n    case 0x21: {\n      // LD HL,d16\n      // 3  12\n      // 8 cycles\n      let sixteenBitDataByte = getConcatenatedDataByte();\n      Cpu.registerH = <u8>splitHighByte(sixteenBitDataByte);\n      Cpu.registerL = <u8>splitLowByte(sixteenBitDataByte);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    case 0x22: {\n      // LD (HL+),A\n      // 1 8\n      let registerHL2 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      eightBitStoreSyncCycles(registerHL2, Cpu.registerA);\n      registerHL2 = u16Portable(registerHL2 + 1);\n      Cpu.registerH = <u8>splitHighByte(registerHL2);\n      Cpu.registerL = <u8>splitLowByte(registerHL2);\n      return 4;\n    }\n    case 0x23: {\n      // INC HL\n      // 1  8\n      let registerHL3 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      registerHL3 = u16Portable(registerHL3 + 1);\n      Cpu.registerH = <u8>splitHighByte(registerHL3);\n      Cpu.registerL = <u8>splitLowByte(registerHL3);\n      return 8;\n    }\n    case 0x24: {\n      // INC H\n      // 1  4\n      // Z 0 H -\n      let registerH = Cpu.registerH;\n      checkAndSetEightBitHalfCarryFlag(registerH, 1);\n      registerH = u8Portable(registerH + 1);\n      Cpu.registerH = registerH;\n      setZeroFlag(<i32>(registerH === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x25: {\n      // DEC H\n      // 1  4\n      // Z 1 H -\n      let registerH = Cpu.registerH;\n      checkAndSetEightBitHalfCarryFlag(registerH, -1);\n      registerH = u8Portable(registerH - 1);\n      Cpu.registerH = registerH;\n      setZeroFlag(<i32>(registerH === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x26: {\n      // LD H,d8\n      // 2 8\n\n      // 4 cycles\n      Cpu.registerH = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x27: {\n      // DAA\n      // 1 4\n      // Z - 0 C\n      let adjustedRegister: u8 = 0;\n      let adjustment: u8 = 0;\n\n      if (getHalfCarryFlag() > 0) {\n        adjustment = adjustment | 0x06;\n      }\n      if (getCarryFlag() > 0) {\n        adjustment = adjustment | 0x60;\n      }\n\n      let registerA = Cpu.registerA;\n      if (getSubtractFlag() > 0) {\n        adjustedRegister = u8Portable(registerA - <u8>adjustment);\n      } else {\n        if ((registerA & 0x0f) > 0x09) {\n          adjustment = adjustment | 0x06;\n        }\n        if (registerA > 0x99) {\n          adjustment = adjustment | 0x60;\n        }\n        adjustedRegister = u8Portable(registerA + <u8>adjustment);\n      }\n\n      // Now set our flags to the correct values\n      setZeroFlag(<i32>(adjustedRegister === 0));\n      setCarryFlag(<i32>((adjustment & 0x60) !== 0));\n      setHalfCarryFlag(0);\n\n      Cpu.registerA = <u8>adjustedRegister;\n      return 4;\n    }\n    case 0x28: {\n      // JR Z,r8\n      // 2  12/8\n      if (getZeroFlag() > 0) {\n        // 4 cycles\n        relativeJump(getDataByteOne());\n        // Relative Jump funciton handles pogram counter\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      }\n      return 8;\n    }\n    case 0x29: {\n      // ADD HL,HL\n      // 1  8\n      // - 0 H C\n      let registerHL9 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      checkAndSetSixteenBitFlagsAddOverflow(registerHL9, registerHL9, false);\n      registerHL9 = u16Portable(registerHL9 * 2);\n      Cpu.registerH = <u8>splitHighByte(registerHL9);\n      Cpu.registerL = <u8>splitLowByte(registerHL9);\n      setSubtractFlag(0);\n      return 8;\n    }\n    case 0x2a: {\n      // LD A,(HL+)\n      // 1  8\n      let registerHLA = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(registerHLA);\n      registerHLA = u16Portable(registerHLA + 1);\n      Cpu.registerH = <u8>splitHighByte(registerHLA);\n      Cpu.registerL = <u8>splitLowByte(registerHLA);\n      return 4;\n    }\n    case 0x2b: {\n      // DEC HL\n      // 1 8\n      let registerHLB = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      registerHLB = u16Portable(registerHLB - 1);\n      Cpu.registerH = <u8>splitHighByte(registerHLB);\n      Cpu.registerL = <u8>splitLowByte(registerHLB);\n      return 8;\n    }\n    case 0x2c: {\n      // INC L\n      // 1  4\n      // Z 0 H -\n      let registerL = Cpu.registerL;\n      checkAndSetEightBitHalfCarryFlag(registerL, 1);\n      registerL = u8Portable(registerL + 1);\n      Cpu.registerL = registerL;\n      setZeroFlag(<i32>(registerL === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x2d: {\n      // DEC L\n      // 1  4\n      // Z 1 H -\n      let registerL = Cpu.registerL;\n      checkAndSetEightBitHalfCarryFlag(registerL, -1);\n      registerL = u8Portable(registerL - 1);\n      Cpu.registerL = registerL;\n      setZeroFlag(<i32>(registerL === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x2e: {\n      // LD L,d8\n      // 2  8\n      // 4 cycles\n      Cpu.registerL = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x2f: {\n      // CPL\n      // 1 4\n      // - 1 1 -\n      Cpu.registerA = ~Cpu.registerA;\n      setSubtractFlag(1);\n      setHalfCarryFlag(1);\n      return 4;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcode3x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x30: {\n      // JR NC,r8\n      // 2 12 / 8\n      if (getCarryFlag() === 0) {\n        // 4 cycles\n        relativeJump(getDataByteOne());\n        // Relative Jump function handles program counter\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      }\n      return 8;\n    }\n    case 0x31: {\n      // LD SP,d16\n      // 3 12\n      // 8 cycles\n      Cpu.stackPointer = getConcatenatedDataByte();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    case 0x32: {\n      // LD (HL-),A\n      // 1 8\n      let registerHL2 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      eightBitStoreSyncCycles(registerHL2, Cpu.registerA);\n      registerHL2 = u16Portable(registerHL2 - 1);\n      Cpu.registerH = <u8>splitHighByte(registerHL2);\n      Cpu.registerL = <u8>splitLowByte(registerHL2);\n      return 4;\n    }\n    case 0x33: {\n      // INC SP\n      // 1 8\n      Cpu.stackPointer = u16Portable(Cpu.stackPointer + 1);\n      return 8;\n    }\n    case 0x34: {\n      // INC (HL)\n      // 1  12\n      // Z 0 H -\n      let registerHL4 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      let valueAtHL4 = <u8>eightBitLoadSyncCycles(registerHL4);\n      // Creating a varible for this to fix assemblyscript overflow bug\n      // Requires explicit casting\n      // https://github.com/AssemblyScript/assemblyscript/issues/26\n      let incrementer: u8 = 1;\n      checkAndSetEightBitHalfCarryFlag(<u8>valueAtHL4, <i16>incrementer);\n      valueAtHL4 = u8Portable(<u8>valueAtHL4 + <u8>incrementer);\n\n      setZeroFlag(<i32>(valueAtHL4 === 0));\n      setSubtractFlag(0);\n      // 4 cycles\n      eightBitStoreSyncCycles(registerHL4, <u8>valueAtHL4);\n      return 4;\n    }\n    case 0x35: {\n      // DEC (HL)\n      // 1  12\n      // Z 1 H -\n      let registerHL5 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      let valueAtHL5 = <u8>eightBitLoadSyncCycles(registerHL5);\n      // NOTE: This opcode may not overflow correctly,\n      // Please see previous opcode\n      checkAndSetEightBitHalfCarryFlag(valueAtHL5, -1);\n      valueAtHL5 = u8Portable(valueAtHL5 - 1);\n      setZeroFlag(<i32>(valueAtHL5 === 0));\n      setSubtractFlag(1);\n      // 4 cycles\n      eightBitStoreSyncCycles(registerHL5, valueAtHL5);\n      return 4;\n    }\n    case 0x36: {\n      // LD (HL),d8\n      // 2  12\n      // 8 cycles, 4 from store, 4 from data byte\n      eightBitStoreSyncCycles(<u16>concatenateBytes(Cpu.registerH, Cpu.registerL), getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x37: {\n      // SCF\n      // 1  4\n      // - 0 0 1\n      // Simply set the carry flag\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      setCarryFlag(1);\n      return 4;\n    }\n    case 0x38: {\n      // JR C,r8\n      // 2 12/8\n      if (getCarryFlag() === 1) {\n        // 4 cycles\n        relativeJump(getDataByteOne());\n        // Relative Jump Funciton handles program counter\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      }\n      return 8;\n    }\n    case 0x39: {\n      // ADD HL,SP\n      // 1 8\n      // - 0 H C\n      let registerHL9 = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      checkAndSetSixteenBitFlagsAddOverflow(<u16>registerHL9, Cpu.stackPointer, false);\n      let result = u16Portable(<u16>(registerHL9 + Cpu.stackPointer));\n      Cpu.registerH = <u8>splitHighByte(<u16>result);\n      Cpu.registerL = <u8>splitLowByte(<u16>result);\n      setSubtractFlag(0);\n      return 8;\n    }\n    case 0x3a: {\n      // LD A,(HL-)\n      // 1 8\n      let registerHLA = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      // 4 cycles\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(registerHLA);\n      registerHLA = u16Portable(registerHLA - 1);\n      Cpu.registerH = <u8>splitHighByte(registerHLA);\n      Cpu.registerL = <u8>splitLowByte(registerHLA);\n      return 4;\n    }\n    case 0x3b: {\n      // DEC SP\n      // 1 8\n      Cpu.stackPointer = u16Portable(Cpu.stackPointer - 1);\n      return 8;\n    }\n    case 0x3c: {\n      // INC A\n      // 1  4\n      // Z 0 H -\n      let registerA = Cpu.registerA;\n      checkAndSetEightBitHalfCarryFlag(registerA, 1);\n      registerA = u8Portable(registerA + 1);\n      Cpu.registerA = registerA;\n      setZeroFlag(<i32>(registerA === 0));\n      setSubtractFlag(0);\n      return 4;\n    }\n    case 0x3d: {\n      // DEC A\n      // 1  4\n      // Z 1 H -\n      let registerA = Cpu.registerA;\n      checkAndSetEightBitHalfCarryFlag(registerA, -1);\n      registerA = u8Portable(registerA - 1);\n      Cpu.registerA = registerA;\n      setZeroFlag(<i32>(registerA === 0));\n      setSubtractFlag(1);\n      return 4;\n    }\n    case 0x3e: {\n      // LD A,d8\n      // 2 8\n      // 4 cycles\n      Cpu.registerA = getDataByteOne();\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0x3f: {\n      // CCF\n      // 1 4\n      // - 0 0 C\n      setSubtractFlag(0);\n      setHalfCarryFlag(0);\n      setCarryFlag(<i32>(getCarryFlag() <= 0));\n      return 4;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcode4x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x40:\n      // LD B,B\n      // 1 4\n      // Load B into B, Do nothing\n      return 4;\n    case 0x41:\n      // LD B,C\n      // 1 4\n      Cpu.registerB = Cpu.registerC;\n      return 4;\n    case 0x42:\n      // LD B,D\n      // 1 4\n      Cpu.registerB = Cpu.registerD;\n      return 4;\n    case 0x43:\n      // LD B,E\n      // 1 4\n      Cpu.registerB = Cpu.registerE;\n      return 4;\n    case 0x44:\n      // LD B,H\n      // 1 4\n      Cpu.registerB = Cpu.registerH;\n      return 4;\n    case 0x45:\n      // LD B,L\n      // 1 4\n      Cpu.registerB = Cpu.registerL;\n      return 4;\n    case 0x46:\n      // LD B,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerB = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x47:\n      // LD B,A\n      // 1 4\n      Cpu.registerB = Cpu.registerA;\n      return 4;\n    case 0x48:\n      // LD C,B\n      // 1 4\n      Cpu.registerC = Cpu.registerB;\n      return 4;\n    case 0x49:\n      // LD C,C\n      // 1 4\n      // Do nothing\n      return 4;\n    case 0x4a:\n      // LD C,D\n      // 1 4\n      Cpu.registerC = Cpu.registerD;\n      return 4;\n    case 0x4b:\n      // LD C,E\n      // 1 4\n      Cpu.registerC = Cpu.registerE;\n      return 4;\n    case 0x4c:\n      // LD C,H\n      // 1 4\n      Cpu.registerC = Cpu.registerH;\n      return 4;\n    case 0x4d:\n      // LD C,L\n      // 1 4\n      Cpu.registerC = Cpu.registerL;\n      return 4;\n    case 0x4e:\n      // LD C,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerC = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x4f:\n      // LD C,A\n      // 1 4\n      Cpu.registerC = Cpu.registerA;\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode5x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x50:\n      // LD D,B\n      // 1 4\n      Cpu.registerD = Cpu.registerB;\n      return 4;\n    case 0x51:\n      // LD D,C\n      // 1 4\n      Cpu.registerD = Cpu.registerC;\n      return 4;\n    case 0x52:\n      // LD D,D\n      // 1 4\n      // Do Nothing\n      return 4;\n    case 0x53:\n      // LD D,E\n      // 1 4\n      Cpu.registerD = Cpu.registerE;\n      return 4;\n    case 0x54:\n      // LD D,H\n      // 1 4\n      Cpu.registerD = Cpu.registerH;\n      return 4;\n    case 0x55:\n      // LD D,L\n      // 1 4\n      Cpu.registerD = Cpu.registerL;\n      return 4;\n    case 0x56:\n      // LD D,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerD = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x57:\n      // LD D,A\n      // 1 4\n      Cpu.registerD = Cpu.registerA;\n      return 4;\n    case 0x58:\n      // LD E,B\n      // 1 4\n      Cpu.registerE = Cpu.registerB;\n      return 4;\n    case 0x59:\n      // LD E,C\n      // 1 4\n      Cpu.registerE = Cpu.registerC;\n      return 4;\n    case 0x5a:\n      // LD E,D\n      // 1 4\n      Cpu.registerE = Cpu.registerD;\n      return 4;\n    case 0x5b:\n      // LD E,E\n      // 1 4\n      // Do Nothing\n      return 4;\n    case 0x5c:\n      // LD E,H\n      // 1 4\n      Cpu.registerE = Cpu.registerH;\n      return 4;\n    case 0x5d:\n      // LD E,L\n      // 1 4\n      Cpu.registerE = Cpu.registerL;\n      return 4;\n    case 0x5e:\n      // LD E,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerE = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x5f:\n      // LD E,A\n      // 1 4\n      Cpu.registerE = Cpu.registerA;\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode6x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x60:\n      // LD H,B\n      // 1 4\n      Cpu.registerH = Cpu.registerB;\n      return 4;\n    case 0x61:\n      // LD H,C\n      // 1 4\n      Cpu.registerH = Cpu.registerC;\n      return 4;\n    case 0x62:\n      // LD H,D\n      // 1 4\n      Cpu.registerH = Cpu.registerD;\n      return 4;\n    case 0x63:\n      // LD H,E\n      // 1 4\n      Cpu.registerH = Cpu.registerE;\n      return 4;\n    case 0x64:\n      // LD H,H\n      // 1 4\n      Cpu.registerH = Cpu.registerH;\n      return 4;\n    case 0x65:\n      // LD H,L\n      // 1 4\n      Cpu.registerH = Cpu.registerL;\n      return 4;\n    case 0x66:\n      // LD H,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerH = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x67:\n      // LD H,A\n      // 1 4\n      Cpu.registerH = Cpu.registerA;\n      return 4;\n    case 0x68:\n      // LD L,B\n      // 1 4\n      Cpu.registerL = Cpu.registerB;\n      return 4;\n    case 0x69:\n      // LD L,C\n      // 1 4\n      Cpu.registerL = Cpu.registerC;\n      return 4;\n    case 0x6a:\n      // LD L,D\n      // 1 4\n      Cpu.registerL = Cpu.registerD;\n      return 4;\n    case 0x6b:\n      // LD L,E\n      // 1 4\n      Cpu.registerL = Cpu.registerE;\n      return 4;\n    case 0x6c:\n      // LD L,H\n      // 1 4\n      Cpu.registerL = Cpu.registerH;\n      return 4;\n    case 0x6d:\n      // LD L,L\n      // 1 4\n      Cpu.registerL = Cpu.registerL;\n      return 4;\n    case 0x6e:\n      // LD L,(HL)\n      // 1 8\n      // 4 cycles\n      Cpu.registerL = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x6f:\n      // LD L,A\n      // 1 4\n      Cpu.registerL = Cpu.registerA;\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode7x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x70:\n      // LD (HL),B\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerB);\n      return 4;\n    case 0x71:\n      // LD (HL),C\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerC);\n      return 4;\n    case 0x72:\n      // LD (HL),D\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerD);\n      return 4;\n    case 0x73:\n      // LD (HL),E\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerE);\n      return 4;\n    case 0x74:\n      // LD (HL),H\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerH);\n      return 4;\n    case 0x75:\n      // LD (HL),L\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerL);\n      return 4;\n    case 0x76:\n      // HALT\n      // 1 4\n      // Enter CPU very low power mode\n      // Meaning Don't Decode anymore opcodes until an interrupt occurs\n      // Still need to do timers and things\n\n      // Can't Halt during an HDMA\n      // https://gist.github.com/drhelius/3394856\n      if (!Memory.isHblankHdmaActive) {\n        Cpu.enableHalt();\n      }\n      return 4;\n    case 0x77:\n      // LD (HL),A\n      // 1 8\n      // 4 cycles\n      eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), Cpu.registerA);\n      return 4;\n    case 0x78:\n      // LD A,B\n      // 1 4\n      Cpu.registerA = Cpu.registerB;\n      return 4;\n    case 0x79:\n      // LD A,C\n      // 1 4\n      Cpu.registerA = Cpu.registerC;\n      return 4;\n    case 0x7a:\n      // LD A,D\n      // 1 4\n      Cpu.registerA = Cpu.registerD;\n      return 4;\n    case 0x7b:\n      // LD A,E\n      // 1 4\n      Cpu.registerA = Cpu.registerE;\n      return 4;\n    case 0x7c:\n      // LD A,H\n      // 1 4\n      Cpu.registerA = Cpu.registerH;\n      return 4;\n    case 0x7d:\n      // LD A,L\n      // 1 4\n      Cpu.registerA = Cpu.registerL;\n      return 4;\n    case 0x7e:\n      // LD A,(HL)\n      // 1 8\n      // NOTE: Thanks to @binji for catching that this should be 8 cycles, not 4\n      // 4 cycles\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 4;\n    case 0x7f:\n      // LD A,A\n      // 1 4\n      // Do Nothing\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode8x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x80:\n      // ADD A,B\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerB);\n      return 4;\n    case 0x81:\n      // ADD A,C\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerC);\n      return 4;\n    case 0x82:\n      // ADD A,D\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerD);\n      return 4;\n    case 0x83:\n      // ADD A,E\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerE);\n      return 4;\n    case 0x84:\n      // ADD A,H\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerH);\n      return 4;\n    case 0x85:\n      // ADD A,L\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerL);\n      return 4;\n    case 0x86:\n      // ADD A,(HL)\n      // 1 8\n      // Z 0 H C\n      // 4 cycles\n      let valueAtHL6: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      addARegister(<u8>valueAtHL6);\n      return 4;\n    case 0x87:\n      // ADD A,A\n      // 1 4\n      // Z 0 H C\n      addARegister(Cpu.registerA);\n      return 4;\n    case 0x88:\n      // ADC A,B\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerB);\n      return 4;\n    case 0x89:\n      // ADC A,C\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerC);\n      return 4;\n    case 0x8a:\n      // ADC A,D\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerD);\n      return 4;\n    case 0x8b:\n      // ADC A,E\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerE);\n      return 4;\n    case 0x8c:\n      // ADC A,H\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerH);\n      return 4;\n    case 0x8d:\n      // ADC A,L\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerL);\n      return 4;\n    case 0x8e:\n      // ADC A,(HL)\n      // 1 8\n      // Z 0 H C\n      // 4 cycles\n      let valueAtHLE: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      addAThroughCarryRegister(<u8>valueAtHLE);\n      return 4;\n    case 0x8f:\n      // ADC A,A\n      // 1 4\n      // Z 0 H C\n      addAThroughCarryRegister(Cpu.registerA);\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcode9x(opcode: i32): i32 {\n  switch (opcode) {\n    case 0x90:\n      // SUB B\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerB);\n      return 4;\n    case 0x91:\n      // SUB C\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerC);\n      return 4;\n    case 0x92:\n      // SUB D\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerD);\n      return 4;\n    case 0x93:\n      // SUB E\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerE);\n      return 4;\n    case 0x94:\n      // SUB H\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerH);\n      return 4;\n    case 0x95:\n      // SUB L\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerL);\n      return 4;\n    case 0x96:\n      // SUB (HL)\n      // 1  8\n      // Z 1 H C\n      // 4 cycles\n      let valueAtHL6: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      subARegister(<u8>valueAtHL6);\n      return 4;\n    case 0x97:\n      // SUB A\n      // 1  4\n      // Z 1 H C\n      subARegister(Cpu.registerA);\n      return 4;\n    case 0x98:\n      // SBC A,B\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerB);\n      return 4;\n    case 0x99:\n      // SBC A,C\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerC);\n      return 4;\n    case 0x9a:\n      // SBC A,D\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerD);\n      return 4;\n    case 0x9b:\n      // SBC A,E\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerE);\n      return 4;\n    case 0x9c:\n      // SBC A,H\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerH);\n      return 4;\n    case 0x9d:\n      // SBC A,L\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerL);\n      return 4;\n    case 0x9e:\n      // SBC A,(HL)\n      // 1  8\n      // Z 1 H C\n      // 4 cycles\n      let valueAtHLE: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      subAThroughCarryRegister(<u8>valueAtHLE);\n      return 4;\n    case 0x9f:\n      // SBC A,A\n      // 1  4\n      // Z 1 H C\n      subAThroughCarryRegister(Cpu.registerA);\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcodeAx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xa0:\n      // AND B\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerB);\n      return 4;\n    case 0xa1:\n      // AND C\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerC);\n      return 4;\n    case 0xa2:\n      // AND D\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerD);\n      return 4;\n    case 0xa3:\n      // AND E\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerE);\n      return 4;\n    case 0xa4:\n      // AND H\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerH);\n      return 4;\n    case 0xa5:\n      // AND L\n      // 1  4\n      // Z 0 1 0\n      andARegister(Cpu.registerL);\n      return 4;\n    case 0xa6:\n      // AND (HL)\n      // 1  8\n      // Z 0 1 0\n      // 4 cycles\n      let valueAtHL6: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      andARegister(<u8>valueAtHL6);\n      return 4;\n    case 0xa7:\n      // AND A\n      // 1  4\n      // Z 0 1 0\n      // NOTE: & Yourself, does nothing\n      andARegister(Cpu.registerA);\n      return 4;\n    case 0xa8:\n      // XOR B\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerB);\n      return 4;\n    case 0xa9:\n      // XOR C\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerC);\n      return 4;\n    case 0xaa:\n      // XOR D\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerD);\n      return 4;\n    case 0xab:\n      // XOR E\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerE);\n      return 4;\n    case 0xac:\n      // XOR H\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerH);\n      return 4;\n    case 0xad:\n      // XOR L\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerL);\n      return 4;\n    case 0xae:\n      // XOR (HL)\n      // 1  8\n      // Z 0 0 0\n      // 4 cycles\n      let valueAtHLE: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      xorARegister(<u8>valueAtHLE);\n      return 4;\n    case 0xaf:\n      // XOR A\n      // 1  4\n      // Z 0 0 0\n      xorARegister(Cpu.registerA);\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcodeBx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xb0:\n      // OR B\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerB);\n      return 4;\n    case 0xb1:\n      // OR C\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerC);\n      return 4;\n    case 0xb2:\n      // OR D\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerD);\n      return 4;\n    case 0xb3:\n      // OR E\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerE);\n      return 4;\n    case 0xb4:\n      // OR H\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerH);\n      return 4;\n    case 0xb5:\n      // OR L\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerL);\n      return 4;\n    case 0xb6:\n      // OR (HL)\n      // 1  8\n      // Z 0 0 0\n      // 4 cycles\n      let valueAtHL6: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      orARegister(<u8>valueAtHL6);\n      return 4;\n    case 0xb7:\n      // OR A\n      // 1  4\n      // Z 0 0 0\n      orARegister(Cpu.registerA);\n      return 4;\n    case 0xb8:\n      // CP B\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerB);\n      return 4;\n    case 0xb9:\n      // CP C\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerC);\n      return 4;\n    case 0xba:\n      // CP D\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerD);\n      return 4;\n    case 0xbb:\n      // CP E\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerE);\n      return 4;\n    case 0xbc:\n      // CP H\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerH);\n      return 4;\n    case 0xbd:\n      // CP L\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerL);\n      return 4;\n    case 0xbe:\n      // CP (HL)\n      // 1  8\n      // Z 1 H C\n      // 4 cycles\n      let valueAtHLE: u8 = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      cpARegister(<u8>valueAtHLE);\n      return 4;\n    case 0xbf:\n      // CP A\n      // 1  4\n      // Z 1 H C\n      cpARegister(Cpu.registerA);\n      return 4;\n  }\n  return -1;\n}\n\nfunction handleOpcodeCx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xc0: {\n      // RET NZ\n      // 1  20/8\n      if (getZeroFlag() === 0) {\n        // 8 cycles\n        let stackPointer = Cpu.stackPointer;\n        Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n        Cpu.stackPointer = u16Portable(stackPointer + 2);\n        return 12;\n      } else {\n        return 8;\n      }\n    }\n    case 0xc1: {\n      // POP BC\n      // 1  12\n      // 8 cycles\n      let registerBC1: i32 = sixteenBitLoadSyncCycles(Cpu.stackPointer);\n      Cpu.stackPointer = u16Portable(Cpu.stackPointer + 2);\n      Cpu.registerB = <u8>splitHighByte(registerBC1);\n      Cpu.registerC = <u8>splitLowByte(registerBC1);\n      return 4;\n    }\n    case 0xc2: {\n      // JP NZ,a16\n      // 3  16/12\n      if (getZeroFlag() === 0) {\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xc3: {\n      // JP a16\n      // 3  16\n      // 8 cycles\n      Cpu.programCounter = getConcatenatedDataByte();\n      return 8;\n    }\n    case 0xc4: {\n      // CALL NZ,a16\n      // 3  24/12\n      if (getZeroFlag() === 0) {\n        let stackPointer = u16Portable(Cpu.stackPointer - 2);\n        Cpu.stackPointer = stackPointer;\n        // 8 cycles\n        sixteenBitStoreSyncCycles(stackPointer, u16Portable(Cpu.programCounter + 2));\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xc5: {\n      // PUSH BC\n      // 1  16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, concatenateBytes(Cpu.registerB, Cpu.registerC));\n      return 8;\n    }\n    case 0xc6: {\n      // ADD A,d8\n      // 2 8\n      // Z 0 H C\n      // 4 cycles\n      addARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xc7: {\n      // RST 00H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x00;\n      return 8;\n    }\n    case 0xc8: {\n      // RET Z\n      // 1  20/8\n      if (getZeroFlag() === 1) {\n        // 8 cycles\n        let stackPointer = Cpu.stackPointer;\n        Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n        Cpu.stackPointer = u16Portable(stackPointer + 2);\n        return 12;\n      } else {\n        return 8;\n      }\n    }\n    case 0xc9: {\n      // RET\n      // 1 16\n      // 8 cycles\n      let stackPointer = Cpu.stackPointer;\n      Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      return 8;\n    }\n    case 0xca: {\n      // JP Z,a16\n      // 3 16/12\n      if (getZeroFlag() === 1) {\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xcb: {\n      // PREFIX CB\n      // 1  4\n      // 4 cycles\n      let cbCycles: i32 = handleCbOpcode(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return cbCycles;\n    }\n    case 0xcc: {\n      // CALL Z,a16\n      // 3  24/12\n      if (getZeroFlag() === 1) {\n        let stackPointer = u16Portable(Cpu.stackPointer - 2);\n        Cpu.stackPointer = stackPointer;\n        // 8 cycles\n        sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter + 2);\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xcd: {\n      // CALL a16\n      // 3  24\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, u16Portable(Cpu.programCounter + 2));\n      // 8 cycles\n      Cpu.programCounter = getConcatenatedDataByte();\n      return 8;\n    }\n    case 0xce: {\n      // ADC A,d8\n      // 2  8\n      // Z 0 H C\n      // 4 cycles\n      addAThroughCarryRegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xcf: {\n      // RST 08H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x08;\n      return 8;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcodeDx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xd0: {\n      // RET NC\n      // 1  20/8\n      if (getCarryFlag() === 0) {\n        // 8 cycles\n        let stackPointer = Cpu.stackPointer;\n        Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n        Cpu.stackPointer = u16Portable(stackPointer + 2);\n        return 12;\n      } else {\n        return 8;\n      }\n    }\n    case 0xd1: {\n      // POP DE\n      // 1  12\n      // 8 cycles\n      let stackPointer = Cpu.stackPointer;\n      let registerDE1: i32 = sixteenBitLoadSyncCycles(stackPointer);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      Cpu.registerD = <u8>splitHighByte(registerDE1);\n      Cpu.registerE = <u8>splitLowByte(registerDE1);\n      return 4;\n    }\n    case 0xd2: {\n      // JP NC,a16\n      // 3  16/12\n      if (getCarryFlag() === 0) {\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    /* No Opcode for: 0xD3 */\n    case 0xd4: {\n      // CALL NC,a16\n      // 3  24/12\n      if (getCarryFlag() === 0) {\n        let stackPointer = u16Portable(Cpu.stackPointer - 2);\n        Cpu.stackPointer = stackPointer;\n        // 8 cycles\n        sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter + 2);\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    case 0xd5: {\n      // PUSH DE\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, concatenateBytes(Cpu.registerD, Cpu.registerE));\n      return 8;\n    }\n    case 0xd6: {\n      // SUB d8\n      // 2  8\n      // Z 1 H C\n      // 4 cycles\n      subARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xd7: {\n      // RST 10H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x10;\n      return 8;\n    }\n    case 0xd8: {\n      // RET C\n      // 1  20/8\n      if (getCarryFlag() === 1) {\n        let stackPointer = Cpu.stackPointer;\n        // 8 cycles\n        Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n        Cpu.stackPointer = u16Portable(stackPointer + 2);\n        return 12;\n      } else {\n        return 8;\n      }\n    }\n    case 0xd9: {\n      // RETI\n      // 1  16\n      let stackPointer = Cpu.stackPointer;\n      // 8 cycles\n      Cpu.programCounter = <u16>sixteenBitLoadSyncCycles(stackPointer);\n      // Enable interrupts\n      setInterrupts(true);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      return 8;\n    }\n    case 0xda: {\n      // JP C,a16\n      // 3 16/12\n      if (getCarryFlag() === 1) {\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    /* No Opcode for: 0xDB */\n    case 0xdc: {\n      // CALL C,a16\n      // 3  24/12\n      if (getCarryFlag() === 1) {\n        let stackPointer = u16Portable(Cpu.stackPointer - 2);\n        Cpu.stackPointer = stackPointer;\n        // 8 cycles\n        sixteenBitStoreSyncCycles(stackPointer, u16Portable(Cpu.programCounter + 2));\n        // 8 cycles\n        Cpu.programCounter = getConcatenatedDataByte();\n        return 8;\n      } else {\n        Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n        return 12;\n      }\n    }\n    /* No Opcode for: 0xDD */\n    case 0xde: {\n      // SBC A,d8\n      // 2 8\n      // Z 1 H C\n      // 4 cycles\n      subAThroughCarryRegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xdf: {\n      // RST 18H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x18;\n      return 8;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcodeEx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xe0: {\n      // LDH (a8),A\n      // 2  12\n\n      // Store value in high RAM ($FF00 + a8)\n      // 4 cycles\n      let largeDataByteOne: i32 = getDataByteOne();\n      // 4 cycles\n      eightBitStoreSyncCycles(0xff00 + largeDataByteOne, Cpu.registerA);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xe1: {\n      // POP HL\n      // 1  12\n      // 8 cycles\n      let stackPointer = Cpu.stackPointer;\n      let registerHL1: i32 = sixteenBitLoadSyncCycles(stackPointer);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      Cpu.registerH = <u8>splitHighByte(registerHL1);\n      Cpu.registerL = <u8>splitLowByte(registerHL1);\n      return 4;\n    }\n    case 0xe2: {\n      // LD (C),A\n      // 1  8\n      // NOTE: Table says 2 Program counter,\n      // But stepping through the boot rom, should be one\n      // Also should change 0xF2\n\n      // Store value in high RAM ($FF00 + register c)\n      // 4 cycles\n      eightBitStoreSyncCycles(0xff00 + <i32>Cpu.registerC, Cpu.registerA);\n      return 4;\n    }\n    /* No Opcode for: 0xE3, 0xE4 */\n    case 0xe5: {\n      // PUSH HL\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, concatenateBytes(Cpu.registerH, Cpu.registerL));\n      return 8;\n    }\n    case 0xe6: {\n      // AND d8\n      // 2  8\n      // Z 0 1 0\n      // 4 cycles\n      andARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xe7: {\n      // RST 20H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x20;\n      return 8;\n    }\n    case 0xe8: {\n      // ADD SP, r8\n      // 2 16\n      // 0 0 H C\n      // NOTE: Discoved dataByte is signed\n      // 4 cycles\n      let signedDataByteOne = i8Portable(<i8>getDataByteOne());\n\n      checkAndSetSixteenBitFlagsAddOverflow(Cpu.stackPointer, signedDataByteOne, true);\n      Cpu.stackPointer = u16Portable(Cpu.stackPointer + signedDataByteOne);\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 12;\n    }\n    case 0xe9: {\n      // JP HL\n      // 1 4\n      Cpu.programCounter = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      return 4;\n    }\n    case 0xea: {\n      // LD (a16),A\n      // 3 16\n      // 12 cycles, 4 from store, 8 from concatenated data byte\n      eightBitStoreSyncCycles(getConcatenatedDataByte(), Cpu.registerA);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    /* No Opcode for: 0xEB, 0xEC, 0xED */\n    case 0xee: {\n      // XOR d8\n      // 2 8\n      // Z 0 0 0\n      // 4 cycles\n      xorARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xef: {\n      // RST 28H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x28;\n      return 8;\n    }\n  }\n  return -1;\n}\n\nfunction handleOpcodeFx(opcode: i32): i32 {\n  switch (opcode) {\n    case 0xf0: {\n      // LDH A,(a8)\n      // 2 12\n      // 4 cycles\n      let largeDataByteOne: i32 = getDataByteOne();\n      // 4 cycles\n      Cpu.registerA = u8Portable(<u8>eightBitLoadSyncCycles(0xff00 + largeDataByteOne));\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xf1: {\n      // POP AF\n      // 1 12\n      // Z N H C (But No work require, flags are already set)\n      // 8 cycles\n      let stackPointer = Cpu.stackPointer;\n      let registerAF1: i32 = <u16>sixteenBitLoadSyncCycles(stackPointer);\n      Cpu.stackPointer = u16Portable(stackPointer + 2);\n      Cpu.registerA = <u8>splitHighByte(registerAF1);\n      Cpu.registerF = <u8>splitLowByte(registerAF1);\n      return 4;\n    }\n    case 0xf2: {\n      // LD A,(C)\n      // 1 8\n      // 4 cycles\n      Cpu.registerA = u8Portable(<u8>eightBitLoadSyncCycles(0xff00 + <i32>Cpu.registerC));\n      return 4;\n    }\n    case 0xf3: {\n      // DI\n      // 1 4\n      setInterrupts(false);\n      return 4;\n    }\n    /* No Opcode for: 0xF4 */\n    case 0xf5: {\n      // PUSH AF\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, concatenateBytes(Cpu.registerA, Cpu.registerF));\n      return 8;\n    }\n    case 0xf6: {\n      // OR d8\n      // 2 8\n      // Z 0 0 0\n      // 4 cycles\n      orARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xf7: {\n      // RST 30H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x30;\n      return 8;\n    }\n    case 0xf8: {\n      // LD HL,SP+r8\n      // 2 12\n      // 0 0 H C\n      // NOTE: Discoved dataByte is signed\n      // 4 cycles\n      let signedDataByteOne = i8Portable(<i8>getDataByteOne());\n      let stackPointer = Cpu.stackPointer;\n\n      // First, let's handle flags\n      setZeroFlag(0);\n      setSubtractFlag(0);\n      checkAndSetSixteenBitFlagsAddOverflow(stackPointer, signedDataByteOne, true);\n      let registerHL = u16Portable(stackPointer + signedDataByteOne);\n      Cpu.registerH = <u8>splitHighByte(registerHL);\n      Cpu.registerL = <u8>splitLowByte(registerHL);\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 8;\n    }\n    case 0xf9: {\n      // LD SP,HL\n      // 1 8\n      Cpu.stackPointer = <u16>concatenateBytes(Cpu.registerH, Cpu.registerL);\n      return 8;\n    }\n    case 0xfa: {\n      // LD A,(a16)\n      // 3 16\n      // 12 cycles, 4 from load, 8 from concatenated data byte\n      Cpu.registerA = <u8>eightBitLoadSyncCycles(getConcatenatedDataByte());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 2);\n      return 4;\n    }\n    case 0xfb: {\n      // EI\n      // 1 4\n      setInterrupts(true);\n      return 4;\n    }\n    /* No Opcode for: 0xFC, 0xFD */\n    case 0xfe: {\n      // CP d8\n      // 2 8\n      // Z 1 H C\n      // 4 cycles\n      cpARegister(getDataByteOne());\n      Cpu.programCounter = u16Portable(Cpu.programCounter + 1);\n      return 4;\n    }\n    case 0xff: {\n      // RST 38H\n      // 1 16\n      let stackPointer = u16Portable(Cpu.stackPointer - 2);\n      Cpu.stackPointer = stackPointer;\n      // 8 cycles\n      sixteenBitStoreSyncCycles(stackPointer, Cpu.programCounter);\n      Cpu.programCounter = 0x38;\n      return 8;\n    }\n  }\n  return -1;\n}\n","// Portable Code for JS Wasm Benchmarking\n// https://github.com/AssemblyScript/assemblyscript/wiki/Writing-portable-code\n// https://github.com/AssemblyScript/assemblyscript/blob/master/std/portable/index.js\n\nexport function u8Portable(param: u8): u8 {\n  return param & 0xff;\n}\n\nexport function i16Portable(param: i16): i16 {\n  return (param << 16) >> 16;\n}\n\nexport function u16Portable(param: u16): u16 {\n  return param & 0xffff;\n}\n\nexport function i8Portable(param: i8): i8 {\n  return (param << 24) >> 24;\n}\n\nexport function i32Portable(param: i32): i32 {\n  return param | 0;\n}\n","// Functions for rendering the background\nimport { FRAME_LOCATION } from '../constants';\nimport { Cpu } from '../cpu/index';\nimport { Config } from '../config';\nimport { Graphics, loadFromVramBank, setPixelOnFrame, getRgbPixelStart } from './graphics';\nimport { getColorizedGbHexColorFromPalette, getRgbColorFromPalette, getColorComponentFromRgb } from './palette';\nimport { getRedFromHexColor, getGreenFromHexColor, getBlueFromHexColor } from './colors';\nimport { addPriorityforPixel, getPriorityforPixel } from './priority';\nimport { TileCache, drawPixelsFromLineOfTile, getTileDataAddress } from './tiles';\n// Assembly script really not feeling the reexport\n// using Skip Traps, because LCD has unrestricted access\n// http://gbdev.gg8.se/wiki/articles/Video_Display#LCD_OAM_DMA_Transfers\nimport { eightBitLoadFromGBMemory } from '../memory/load';\nimport { checkBitOnByte, resetBitOnByte } from '../helpers/index';\nimport { i32Portable } from '../portable/portable';\n\n// NOTE: i32Portable wraps modulo here as somehow it gets converted to a double:\n// https://github.com/torch2424/wasmboy/issues/216\n\n// Inlined because closure compiler inlines\nexport function renderBackground(scanlineRegister: i32, tileDataMemoryLocation: i32, tileMapMemoryLocation: i32): void {\n  // NOTE: Camera is reffering to what you can see inside the 160x144 viewport of the entire rendered 256x256 map.\n\n  // Get our scrollX and scrollY (u16 to play nice with assemblyscript)\n  // let scrollX: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationScrollX);\n  // let scrollY: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationScrollY);\n  let scrollX: i32 = Graphics.scrollX;\n  let scrollY: i32 = Graphics.scrollY;\n\n  // Get our current pixel y positon on the 160x144 camera (Row that the scanline draws across)\n  // this is done by getting the current scroll Y position,\n  // and adding it do what Y Value the scanline is drawing on the camera.\n  let pixelYPositionInMap: i32 = scanlineRegister + scrollY;\n\n  // Gameboy camera will \"wrap\" around the background map,\n  // meaning that if the pixelValue is 350, then we need to subtract 256 (decimal) to get it's actual value\n  // pixel values (scrollX and scrollY) range from 0x00 - 0xFF\n  pixelYPositionInMap &= 0x100 - 1;\n\n  // Draw the Background scanline\n  drawBackgroundWindowScanline(scanlineRegister, tileDataMemoryLocation, tileMapMemoryLocation, pixelYPositionInMap, 0, scrollX);\n}\n\n// Inlined because closure compiler inlines\nexport function renderWindow(scanlineRegister: i32, tileDataMemoryLocation: i32, tileMapMemoryLocation: i32): void {\n  // Get our windowX and windowY\n  // let windowX: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationWindowX);\n  // let windowY: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationWindowY);\n  let windowX: i32 = Graphics.windowX;\n  let windowY: i32 = Graphics.windowY;\n\n  // NOTE: Camera is reffering to what you can see inside the 160x144 viewport of the entire rendered 256x256 map.\n\n  // First ensure that the scanline is greater than our window\n  if (scanlineRegister < windowY) {\n    // Window is not within the current camera view\n    return;\n  }\n\n  // WindowX is offset by 7\n  windowX -= 7;\n\n  // Get our current pixel y positon on the 160x144 camera (Row that the scanline draws across)\n  let pixelYPositionInMap = scanlineRegister - windowY;\n\n  // xOffset is simply a neagative window x\n  // NOTE: This can become negative zero?\n  // https://github.com/torch2424/wasmboy/issues/216\n  let xOffset = i32Portable(-windowX);\n\n  // Draw the Background scanline\n  drawBackgroundWindowScanline(scanlineRegister, tileDataMemoryLocation, tileMapMemoryLocation, pixelYPositionInMap, windowX, xOffset);\n}\n\n// Function frankenstein'd together to allow background and window to share the same draw scanline function\nfunction drawBackgroundWindowScanline(\n  scanlineRegister: i32,\n  tileDataMemoryLocation: i32,\n  tileMapMemoryLocation: i32,\n  pixelYPositionInMap: i32,\n  iStart: i32,\n  xOffset: i32\n): void {\n  // Get our tile Y position in the map\n  let tileYPositionInMap = pixelYPositionInMap >> 3;\n\n  // Loop through x to draw the line like a CRT\n  for (let i = iStart; i < 160; ++i) {\n    // Get our Current X position of our pixel on the on the 160x144 camera\n    // this is done by getting the current scroll X position,\n    // and adding it do what X Value the scanline is drawing on the camera.\n    let pixelXPositionInMap = i + xOffset;\n\n    // This is to compensate wrapping, same as pixelY\n    if (pixelXPositionInMap >= 0x100) {\n      pixelXPositionInMap -= 0x100;\n    }\n\n    // Divide our pixel position by 8 to get our tile.\n    // Since, there are 256x256 pixels, and 32x32 tiles.\n    // 256 / 8 = 32.\n    // Also, bitshifting by 3, do do a division by 8\n    // Need to use u16s, as they will be used to compute an address, which will cause weird errors and overflows\n    let tileXPositionInMap = pixelXPositionInMap >> 3;\n\n    // Get our tile address on the tileMap\n    // NOTE: (tileMap represents where each tile is displayed on the screen)\n    // NOTE: (tile map represents the entire map, now just what is within the \"camera\")\n    // For instance, if we have y pixel 144. 144 / 8 = 18. 18 * 32 = line address in map memory.\n    // And we have x pixel 160. 160 / 8 = 20.\n    // * 32, because remember, this is NOT only for the camera, the actual map is 32x32. Therefore, the next tile line of the map, is 32 byte offset.\n    // Think like indexing a 2d array, as a 1d array and it make sense :)\n    let tileMapAddress = tileMapMemoryLocation + (tileYPositionInMap << 5) + tileXPositionInMap;\n\n    // Get the tile Id on the Tile Map\n    let tileIdFromTileMap: i32 = loadFromVramBank(tileMapAddress, 0);\n\n    // Now that we have our Tile Id, let's check our Tile Cache\n    let usedTileCache = false;\n    if (Config.tileCaching) {\n      let pixelsDrawn: i32 = drawLineOfTileFromTileCache(\n        i,\n        scanlineRegister,\n        pixelXPositionInMap,\n        pixelYPositionInMap,\n        tileMapAddress,\n        tileDataMemoryLocation,\n        tileIdFromTileMap\n      );\n      // Increment i by 7, not 8 because i will be incremented at end of for loop\n      if (pixelsDrawn > 0) {\n        i += pixelsDrawn - 1;\n        usedTileCache = true;\n      }\n    }\n\n    if (Config.tileRendering && !usedTileCache) {\n      let pixelsDrawn: i32 = drawLineOfTileFromTileId(\n        i,\n        scanlineRegister,\n        pixelXPositionInMap,\n        pixelYPositionInMap,\n        tileMapAddress,\n        tileDataMemoryLocation,\n        tileIdFromTileMap\n      );\n      // A line of a tile is 8 pixels wide, therefore increase i by (pixelsDrawn - 1), and then the for loop will increment by 1\n      // For a net increment for 8\n      if (pixelsDrawn > 0) {\n        i += pixelsDrawn - 1;\n      }\n    } else if (!usedTileCache) {\n      if (Cpu.GBCEnabled) {\n        // Draw the individual pixel\n        drawColorPixelFromTileId(\n          i,\n          scanlineRegister,\n          pixelXPositionInMap,\n          pixelYPositionInMap,\n          tileMapAddress,\n          tileDataMemoryLocation,\n          tileIdFromTileMap\n        );\n      } else {\n        // Draw the individual pixel\n        drawMonochromePixelFromTileId(\n          i,\n          scanlineRegister,\n          pixelXPositionInMap,\n          pixelYPositionInMap,\n          tileDataMemoryLocation,\n          tileIdFromTileMap\n        );\n      }\n    }\n  }\n}\n\n// Function to draw a pixel for the standard GB\n// Inlined because closure compiler inlines\nfunction drawMonochromePixelFromTileId(\n  xPixel: i32,\n  yPixel: i32,\n  pixelXPositionInMap: i32,\n  pixelYPositionInMap: i32,\n  tileDataMemoryLocation: i32,\n  tileIdFromTileMap: i32\n): void {\n  // Now we can process the the individual bytes that represent the pixel on a tile\n\n  // Now get our tileDataAddress for the corresponding tileID we found in the map\n  // Read the comments in _getTileDataAddress() to see what's going on.\n  // tl;dr if we had the tile map of \"a b c d\", and wanted tileId 2.\n  // This funcitons returns the start of memory locaiton for the tile 'c'.\n  let tileDataAddress: i32 = getTileDataAddress(tileDataMemoryLocation, tileIdFromTileMap);\n\n  // Get the y pixel of the 8 by 8 tile.\n  // Simply modulo the scanline.\n  // For instance, let's say we are printing the first line of pixels on our camera,\n  // And the first line of pixels on our tile.\n  // yPixel = 1. 1 % 8 = 1.\n  // And for the last line\n  // yPixel = 144. 144 % 8 = 0.\n  // 0 Represents last line of pixels in a tile, 1 represents first. 1 2 3 4 5 6 7 0.\n  // Because remember, we are counting lines on the display NOT including zero\n  let pixelYInTile = i32Portable(pixelYPositionInMap & 7);\n\n  // Remember to represent a single line of 8 pixels on a tile, we need two bytes.\n  // Therefore, we need to times our modulo by 2, to get the correct line of pixels on the tile.\n  // Again, think like you had to map a 2d array as a 1d.\n  let byteOneForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2, 0);\n  let byteTwoForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2 + 1, 0);\n\n  // Same logic as pixelYInTile.\n  // However, We need to reverse our byte,\n  // As pixel 0 is on byte 7, and pixel 1 is on byte 6, etc...\n  // Therefore, is pixelX was 2, then really is need to be 5\n  // So 2 - 7 = -5, * 1 = 5\n  // Or to simplify, 7 - 2 = 5 haha!\n  let pixelXInTile = i32Portable(pixelXPositionInMap & 7);\n  pixelXInTile = 7 - pixelXInTile;\n\n  // Now we can get the color for that pixel\n  // Colors are represented by getting X position of ByteTwo, and X positon of Byte One\n  // To Get the color Id.\n  // For example, the result of the color id is 0000 00[xPixelByteTwo][xPixelByteOne]\n  // See: How to draw a tile/sprite from memory: http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n  let paletteColorId: u8 = 0;\n  if (checkBitOnByte(pixelXInTile, byteTwoForLineOfTilePixels)) {\n    // Byte one represents the second bit in our color id, so bit shift\n    paletteColorId += 1;\n    paletteColorId = paletteColorId << 1;\n  }\n  if (checkBitOnByte(pixelXInTile, byteOneForLineOfTilePixels)) {\n    paletteColorId += 1;\n  }\n  // Not checking u8 Portability overflow here, since it can't be greater than i32 over :p\n\n  // Now get the colorId from the pallete, to get our final color\n  // Developers could change colorIds to represents different colors\n  // in their palette, thus we need to grab the color from there\n  //let pixelColorInTileFromPalette: u8 = getColorFromPalette(paletteColorId, Graphics.memoryLocationBackgroundPalette);\n  // Moved below for perofrmance\n\n  // FINALLY, RENDER THAT PIXEL!\n  // Only rendering camera for now, so coordinates are for the camera.\n  // Get the rgb value for the color Id, will be repeated into R, G, B. if not colorized\n  let hexColor: i32 = getColorizedGbHexColorFromPalette(paletteColorId, Graphics.memoryLocationBackgroundPalette);\n  setPixelOnFrame(xPixel, yPixel, 0, getRedFromHexColor(hexColor));\n  setPixelOnFrame(xPixel, yPixel, 1, getGreenFromHexColor(hexColor));\n  setPixelOnFrame(xPixel, yPixel, 2, getBlueFromHexColor(hexColor));\n\n  // Lastly, add the pixel to our background priority map\n  // https://github.com/torch2424/wasmBoy/issues/51\n  // Bits 0 & 1 will represent the color Id drawn by the BG/Window\n  // Bit 2 will represent if the Bg/Window has GBC priority.\n  addPriorityforPixel(xPixel, yPixel, paletteColorId);\n}\n\n// Function to draw a pixel from a tile in C O L O R\n// See above for more context on some variables\n// Inlined because closure compiler inlines\nfunction drawColorPixelFromTileId(\n  xPixel: i32,\n  yPixel: i32,\n  pixelXPositionInMap: i32,\n  pixelYPositionInMap: i32,\n  tileMapAddress: i32,\n  tileDataMemoryLocation: i32,\n  tileIdFromTileMap: i32\n): void {\n  // Now get our tileDataAddress for the corresponding tileID we found in the map\n  // Read the comments in _getTileDataAddress() to see what's going on.\n  // tl;dr if we had the tile map of \"a b c d\", and wanted tileId 2.\n  // This funcitons returns the start of memory locaiton for the tile 'c'.\n  let tileDataAddress: i32 = getTileDataAddress(tileDataMemoryLocation, tileIdFromTileMap);\n\n  // Get the GB Map Attributes\n  // Bit 0-2  Background Palette number  (BGP0-7)\n  // Bit 3    Tile VRAM Bank number      (0=Bank 0, 1=Bank 1)\n  // Bit 4    Not used\n  // Bit 5    Horizontal Flip            (0=Normal, 1=Mirror horizontally)\n  // Bit 6    Vertical Flip              (0=Normal, 1=Mirror vertically)\n  // Bit 7    BG-to-OAM Priority         (0=Use OAM priority bit, 1=BG Priority)\n  let bgMapAttributes: i32 = loadFromVramBank(tileMapAddress, 1);\n\n  // See above for explanation\n  let pixelYInTile = i32Portable(pixelYPositionInMap & 7);\n  if (checkBitOnByte(6, bgMapAttributes)) {\n    // We are mirroring the tile, therefore, we need to opposite byte\n    // So if our pixel was 0 our of 8, it wild become 7 :)\n    pixelYInTile = 7 - pixelYInTile;\n  }\n\n  // Remember to represent a single line of 8 pixels on a tile, we need two bytes.\n  // Therefore, we need to times our modulo by 2, to get the correct line of pixels on the tile.\n  // But we need to load the time from a specific Vram bank\n  let vramBankId = i32Portable(<i32>checkBitOnByte(3, bgMapAttributes));\n  let byteOneForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2, vramBankId);\n  let byteTwoForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2 + 1, vramBankId);\n\n  // Get our X pixel. Need to NOT reverse it if it was flipped.\n  // See above, you have to reverse this normally\n  let pixelXInTile = i32Portable(pixelXPositionInMap & 7);\n  if (!checkBitOnByte(5, bgMapAttributes)) {\n    pixelXInTile = 7 - pixelXInTile;\n  }\n\n  // Now we can get the color for that pixel\n  // Colors are represented by getting X position of ByteTwo, and X positon of Byte One\n  // To Get the color Id.\n  // For example, the result of the color id is 0000 00[xPixelByteTwo][xPixelByteOne]\n  // See: How to draw a tile/sprite from memory: http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n  let paletteColorId = 0;\n  if (checkBitOnByte(pixelXInTile, byteTwoForLineOfTilePixels)) {\n    // Byte one represents the second bit in our color id, so bit shift\n    paletteColorId += 1;\n    paletteColorId = paletteColorId << 1;\n  }\n  if (checkBitOnByte(pixelXInTile, byteOneForLineOfTilePixels)) {\n    paletteColorId += 1;\n  }\n\n  // Finally lets add some, C O L O R\n  // Want the botom 3 bits\n  let bgPalette = bgMapAttributes & 0x07;\n\n  // Call the helper function to grab the correct color from the palette\n  let rgbColorPalette = getRgbColorFromPalette(bgPalette, paletteColorId, false);\n\n  // Split off into red green and blue\n  let red = getColorComponentFromRgb(0, rgbColorPalette);\n  let green = getColorComponentFromRgb(1, rgbColorPalette);\n  let blue = getColorComponentFromRgb(2, rgbColorPalette);\n\n  // Finally Place our colors on the things\n  setPixelOnFrame(xPixel, yPixel, 0, red);\n  setPixelOnFrame(xPixel, yPixel, 1, green);\n  setPixelOnFrame(xPixel, yPixel, 2, blue);\n\n  // Lastly, add the pixel to our background priority map\n  // https://github.com/torch2424/wasmBoy/issues/51\n  // Bits 0 & 1 will represent the color Id drawn by the BG/Window\n  // Bit 2 will represent if the Bg/Window has GBC priority.\n  addPriorityforPixel(xPixel, yPixel, paletteColorId, checkBitOnByte(7, bgMapAttributes));\n}\n\n// Function to attempt to draw the tile from the tile cache\n// Inlined because closure compiler inlines\nfunction drawLineOfTileFromTileCache(\n  xPixel: i32,\n  yPixel: i32,\n  pixelXPositionInMap: i32,\n  pixelYPositionInMap: i32,\n  tileMapAddress: i32,\n  tileDataMemoryLocation: i32,\n  tileIdFromTileMap: i32\n): i32 {\n  // First, initialize how many pixels we have drawn\n  let pixelsDrawn: i32 = 0;\n\n  // Check if the current tile matches our tileId\n  // TODO: Allow the first line to use the tile cache, for some odd reason it doesn't work when scanline is 0\n  let nextXIndexToPerformCacheCheck = TileCache.nextXIndexToPerformCacheCheck;\n  if (yPixel > 0 && xPixel > 8 && <i32>tileIdFromTileMap === TileCache.tileId && xPixel === nextXIndexToPerformCacheCheck) {\n    // Was last tile flipped\n    let wasLastTileHorizontallyFlipped = checkBitOnByte(5, eightBitLoadFromGBMemory(tileMapAddress - 1));\n    let isCurrentTileHorizontallyFlipped = checkBitOnByte(5, eightBitLoadFromGBMemory(tileMapAddress));\n\n    // Simply copy the last 8 pixels from memory to copy the line from the tile\n    for (let tileCacheIndex = 0; tileCacheIndex < 8; ++tileCacheIndex) {\n      // Check if we need to render backwards for flipping\n      if (wasLastTileHorizontallyFlipped !== isCurrentTileHorizontallyFlipped) {\n        tileCacheIndex = 7 - tileCacheIndex;\n      }\n\n      let xPos = xPixel + tileCacheIndex;\n      // First check for overflow\n      if (xPos <= 160) {\n        // Get the pixel location in memory of the tile\n        let previousXPixel = xPixel - (8 - tileCacheIndex);\n        let previousTilePixelLocation = FRAME_LOCATION + getRgbPixelStart(xPos, yPixel);\n\n        // Cycle through the RGB\n        // for (let tileCacheRgb = 0; tileCacheRgb < 3; ++tileCacheRgb) {\n        //  setPixelOnFrame(xPixel + tileCacheIndex, yPixel, tileCacheRgb, load<u8>(previousTilePixelLocation + tileCacheRgb));\n        // }\n        // unroll\n        setPixelOnFrame(xPos, yPixel, 0, load<u8>(previousTilePixelLocation, 0));\n        setPixelOnFrame(xPos, yPixel, 1, load<u8>(previousTilePixelLocation, 1));\n        setPixelOnFrame(xPos, yPixel, 2, load<u8>(previousTilePixelLocation, 2));\n\n        // Copy the priority for the pixel\n        let pixelPriority: i32 = getPriorityforPixel(previousXPixel, yPixel);\n        addPriorityforPixel(xPos, yPixel, resetBitOnByte(2, pixelPriority), checkBitOnByte(2, pixelPriority));\n\n        pixelsDrawn++;\n      }\n    }\n  } else {\n    // Save our current tile Id, and the next x value we should check the x index\n    TileCache.tileId = tileIdFromTileMap;\n  }\n\n  // Calculate when we should do the tileCache calculation again\n  if (xPixel >= nextXIndexToPerformCacheCheck) {\n    nextXIndexToPerformCacheCheck = xPixel + 8;\n    let xOffsetTileWidthRemainder = i32Portable(pixelXPositionInMap & 7);\n    if (xPixel < xOffsetTileWidthRemainder) {\n      nextXIndexToPerformCacheCheck += xOffsetTileWidthRemainder;\n    }\n  }\n  TileCache.nextXIndexToPerformCacheCheck = nextXIndexToPerformCacheCheck;\n\n  return pixelsDrawn;\n}\n\n// Function to draw a line of a tile in Color\n// This is for tile rendering shortcuts\n// Inlined because closure compiler inlines\nfunction drawLineOfTileFromTileId(\n  xPixel: i32,\n  yPixel: i32,\n  pixelXPositionInMap: i32,\n  pixelYPositionInMap: i32,\n  tileMapAddress: i32,\n  tileDataMemoryLocation: i32,\n  tileIdFromTileMap: i32\n): i32 {\n  // Get the which line of the tile we are rendering\n  let tileLineY: i32 = i32Portable(pixelYPositionInMap & 7);\n\n  // Now lets find our tileX start and end\n  // This is for the case where i = 0, but scroll X was 3.\n  // Or i is 157, and our camera is only 160 pixels wide\n  let tileXStart = 0;\n  if (xPixel == 0) {\n    tileXStart = pixelXPositionInMap - ((pixelXPositionInMap >> 3) << 3);\n  }\n  let tileXEnd = 7;\n  if (xPixel + 8 > 160) {\n    tileXEnd = 160 - xPixel;\n  }\n\n  // initialize some variables for GBC\n  let bgMapAttributes = -1;\n  let vramBankId = 0;\n  if (Cpu.GBCEnabled) {\n    // Get Our GBC properties\n    bgMapAttributes = loadFromVramBank(tileMapAddress, 1);\n    vramBankId = i32Portable(<i32>checkBitOnByte(3, <u8>bgMapAttributes));\n\n    if (checkBitOnByte(6, bgMapAttributes)) {\n      // We are mirroring the tile, therefore, we need to opposite byte\n      // So if our pixel was 0 our of 8, it wild become 7 :)\n      tileLineY = 7 - tileLineY;\n    }\n  }\n\n  // Return the number of pixels drawn\n  return drawPixelsFromLineOfTile(\n    tileIdFromTileMap,\n    tileDataMemoryLocation,\n    vramBankId,\n    tileXStart,\n    tileXEnd,\n    tileLineY,\n    xPixel,\n    yPixel,\n    160,\n    FRAME_LOCATION,\n    false,\n    0,\n    bgMapAttributes,\n    -1\n  );\n}\n","// https://github.com/torch2424/wasmBoy/issues/51\n// Bits 0 & 1 will represent the color Id drawn by the BG/Window\n// Bit 2 will represent if the Bg/Window has GBC priority.\n\nimport { BG_PRIORITY_MAP_LOCATION } from '../constants';\nimport { setBitOnByte } from '../helpers/index';\n\nexport function addPriorityforPixel(x: i32, y: i32, colorId: i32 = 0, hasGbcBgPriority: boolean = false): void {\n  let bgPriorityByte = colorId & 0x03;\n  if (hasGbcBgPriority) {\n    bgPriorityByte = setBitOnByte(2, bgPriorityByte);\n  }\n\n  store<u8>(BG_PRIORITY_MAP_LOCATION + getPixelStart(x, y), <u8>bgPriorityByte);\n}\n\n// Inlined because closure compiler inlines\nexport function getPriorityforPixel(x: i32, y: i32): u8 {\n  return load<u8>(BG_PRIORITY_MAP_LOCATION + getPixelStart(x, y));\n}\n\n// Inlined because closure compiler inlines\nexport function clearPriorityMap(): void {\n  for (let y = 0; y < 144; ++y) {\n    for (let x = 0; x < 160; ++x) {\n      store<u8>(BG_PRIORITY_MAP_LOCATION + getPixelStart(x, y), 0);\n    }\n  }\n}\n\n// Inlined because closure compiler inlines\nfunction getPixelStart(x: i32, y: i32): i32 {\n  // Get the pixel number\n  return y * 160 + x;\n}\n","// Functions for rendering the sprites\nimport { Graphics, loadFromVramBank, setPixelOnFrame } from './graphics';\nimport { Lcd } from './lcd';\nimport { Cpu } from '../cpu/index';\nimport { getTileDataAddress } from './tiles';\nimport { getColorizedGbHexColorFromPalette, getRgbColorFromPalette, getColorComponentFromRgb } from './palette';\nimport { getRedFromHexColor, getGreenFromHexColor, getBlueFromHexColor } from './colors';\nimport { getPriorityforPixel } from './priority';\n// Assembly script really not feeling the reexport\n// using Skip Traps, because LCD has unrestricted access\n// http://gbdev.gg8.se/wiki/articles/Video_Display#LCD_OAM_DMA_Transfers\nimport { eightBitLoadFromGBMemory } from '../memory/load';\nimport { checkBitOnByte } from '../helpers/index';\n\n// Inlined because closure compiler inlines\nexport function renderSprites(scanlineRegister: i32, useLargerSprites: boolean): void {\n  // Need to loop through all 40 sprites to check their status\n  // Going backwards since lower sprites draw over higher ones\n  // Will fix dragon warrior 3 intro\n  for (let i = 39; i >= 0; --i) {\n    // Sprites occupy 4 bytes in the sprite attribute table\n    let spriteTableIndex = i * 4;\n    // Y positon is offset by 16, X position is offset by 8\n\n    let index = Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex;\n\n    let spriteYPosition = eightBitLoadFromGBMemory(index + 0);\n    let spriteXPosition = eightBitLoadFromGBMemory(index + 1);\n    let spriteTileId = eightBitLoadFromGBMemory(index + 2);\n\n    // Pan docs of sprite attirbute table\n    // Bit7   OBJ-to-BG Priority (0=OBJ Above BG, 1=OBJ Behind BG color 1-3)\n    //      (Used for both BG and Window. BG color 0 is always behind OBJ)\n    // Bit6   Y flip          (0=Normal, 1=Vertically mirrored)\n    // Bit5   X flip          (0=Normal, 1=Horizontally mirrored)\n    // Bit4   Palette number  **Non CGB Mode Only** (0=OBP0, 1=OBP1)\n    // Bit3   Tile VRAM-Bank  **CGB Mode Only**     (0=Bank 0, 1=Bank 1)\n    // Bit2-0 Palette number  **CGB Mode Only**     (OBP0-7)\n\n    // Apply sprite X and Y offset\n    // TODO: Sprites are overflowing on x if less than 8\n    spriteYPosition -= 16;\n    spriteXPosition -= 8;\n\n    // Find our sprite height\n    let spriteHeight = 8;\n    if (useLargerSprites) {\n      spriteHeight = 16;\n      // @binji says in 8x16 mode, even tileId always drawn first\n      // This will fix shantae sprites which always uses odd numbered indexes\n\n      // TODO: Do the actual Pandocs thing:\n      // \"In 8x16 mode, the lower bit of the tile number is ignored. Ie. the upper 8x8 tile is \"NN AND FEh\", and the lower 8x8 tile is \"NN OR 01h\".\"\n      // So just knock off the last bit? :)\n      spriteTileId -= spriteTileId & 1;\n    }\n\n    // Find if our sprite is on the current scanline\n    if (scanlineRegister >= spriteYPosition && scanlineRegister < spriteYPosition + spriteHeight) {\n      // Then we need to draw the current sprite\n\n      // Get our sprite attributes since we know we shall be drawing the tile\n      let spriteAttributes = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 3);\n\n      // Check sprite Priority\n      let isSpritePriorityBehindWindowAndBackground = checkBitOnByte(7, spriteAttributes);\n\n      // Check if we should flip the sprite on the x or y axis\n      let flipSpriteY = checkBitOnByte(6, spriteAttributes);\n      let flipSpriteX = checkBitOnByte(5, spriteAttributes);\n\n      // TODO: Torch2424 continue here.\n\n      // Find which line on the sprite we are on\n      let currentSpriteLine = scanlineRegister - spriteYPosition;\n\n      // If we fliiped the Y axis on our sprite, need to read from memory backwards to acheive the same effect\n      if (flipSpriteY) {\n        currentSpriteLine = spriteHeight - currentSpriteLine;\n\n        // Bug fix for the flipped flies in link's awakening\n        currentSpriteLine -= 1;\n      }\n\n      // Each line of a tile takes two bytes of memory\n      currentSpriteLine <<= 1;\n\n      // Get our sprite tile address, need to also add the current sprite line to get the correct bytes\n      let spriteTileAddressStart = getTileDataAddress(Graphics.memoryLocationTileDataSelectOneStart, spriteTileId);\n      spriteTileAddressStart += currentSpriteLine;\n      let spriteTileAddress = spriteTileAddressStart;\n\n      // Find which VRAM Bank to load from\n      let vramBankId = <i32>(Cpu.GBCEnabled && checkBitOnByte(3, spriteAttributes));\n      let spriteDataByteOneForLineOfTilePixels = loadFromVramBank(spriteTileAddress + 0, vramBankId);\n      let spriteDataByteTwoForLineOfTilePixels = loadFromVramBank(spriteTileAddress + 1, vramBankId);\n\n      // Iterate over the width of our sprite to find our individual pixels\n      for (let tilePixel = 7; tilePixel >= 0; --tilePixel) {\n        // Get our spritePixel, and check for flipping\n        let spritePixelXInTile = tilePixel;\n        if (flipSpriteX) {\n          spritePixelXInTile -= 7;\n          spritePixelXInTile = -spritePixelXInTile;\n        }\n\n        // Get the color Id of our sprite, similar to renderBackground()\n        // With the first byte, and second byte lined up method thing\n        // Yes, the second byte comes before the first, see ./background.ts\n        let spriteColorId = 0;\n        if (checkBitOnByte(spritePixelXInTile, spriteDataByteTwoForLineOfTilePixels)) {\n          // Byte one represents the second bit in our color id, so bit shift\n          spriteColorId = (spriteColorId + 1) << 1;\n        }\n        if (checkBitOnByte(spritePixelXInTile, spriteDataByteOneForLineOfTilePixels)) {\n          spriteColorId += 1;\n        }\n\n        // ColorId zero (last two bits of pallette) are transparent\n        // http://gbdev.gg8.se/wiki/articles/Video_Display\n        if (spriteColorId !== 0) {\n          // Find our actual X pixel location on the gameboy \"camera\" view\n          // This cannot be less than zero, i32 will overflow\n          let spriteXPixelLocationInCameraView = spriteXPosition + (7 - tilePixel);\n          if (spriteXPixelLocationInCameraView >= 0 && spriteXPixelLocationInCameraView <= 160) {\n            // There are two cases where wouldnt draw the pixel on top of the Bg/window\n            // 1. if isSpritePriorityBehindWindowAndBackground, sprite can only draw over color 0\n            // 2. if bit 2 of our priority is set, then BG-to-OAM Priority from pandoc\n            //  is active, meaning BG tile will have priority above all OBJs\n            //  (regardless of the priority bits in OAM memory)\n            // But if GBC and Bit 0 of LCDC is set, we always draw the object\n            let shouldShowFromLcdcPriority = Cpu.GBCEnabled && !Lcd.bgDisplayEnabled; // LCDC Priority\n            let shouldHideFromOamPriority = false;\n            let shouldHideFromBgPriority = false;\n\n            if (!shouldShowFromLcdcPriority) {\n              // Now that we have our coordinates, check for sprite priority\n              // Lets get the priority byte we put in memory\n              let bgPriorityByte = getPriorityforPixel(spriteXPixelLocationInCameraView, scanlineRegister);\n\n              let bgColorFromPriorityByte = bgPriorityByte & 0x03;\n\n              // Doing an else if, since either will automatically stop drawing the pixel\n              if (isSpritePriorityBehindWindowAndBackground && bgColorFromPriorityByte > 0) {\n                // OAM Priority\n                shouldHideFromOamPriority = true;\n              } else if (Cpu.GBCEnabled && checkBitOnByte(2, bgPriorityByte) && bgColorFromPriorityByte > 0) {\n                // Bg priority\n                shouldHideFromBgPriority = true;\n              }\n            }\n\n            if (shouldShowFromLcdcPriority || (!shouldHideFromOamPriority && !shouldHideFromBgPriority)) {\n              if (!Cpu.GBCEnabled) {\n                // Get our monochrome color RGB from the current sprite pallete\n                // Get our sprite pallete\n                let spritePaletteLocation = Graphics.memoryLocationSpritePaletteOne;\n                if (checkBitOnByte(4, spriteAttributes)) {\n                  spritePaletteLocation = Graphics.memoryLocationSpritePaletteTwo;\n                }\n\n                let hexColor = getColorizedGbHexColorFromPalette(spriteColorId, spritePaletteLocation);\n\n                // Finally set the pixel!\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 0, getRedFromHexColor(hexColor));\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 1, getGreenFromHexColor(hexColor));\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 2, getBlueFromHexColor(hexColor));\n              } else {\n                // Get our RGB Color\n\n                // Finally lets add some, C O L O R\n                // Want the botom 3 bits\n                let bgPalette = spriteAttributes & 0x07;\n\n                // Call the helper function to grab the correct color from the palette\n                let rgbColorPalette = getRgbColorFromPalette(bgPalette, spriteColorId, true);\n\n                // Split off into red green and blue\n                let red = getColorComponentFromRgb(0, rgbColorPalette);\n                let green = getColorComponentFromRgb(1, rgbColorPalette);\n                let blue = getColorComponentFromRgb(2, rgbColorPalette);\n\n                // Finally Place our colors on the things\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 0, red);\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 1, green);\n                setPixelOnFrame(spriteXPixelLocationInCameraView, scanlineRegister, 2, blue);\n              }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n","import { Memory } from './memory';\nimport { Cpu } from '../cpu/index';\nimport { Graphics } from '../graphics/graphics';\nimport { Lcd } from '../graphics/index';\nimport { batchProcessAudio, SoundRegisterReadTraps, Channel3 } from '../sound/index';\nimport { eightBitStoreIntoGBMemory } from './store';\nimport { eightBitLoadFromGBMemory } from './load';\nimport { Joypad, getJoypadState } from '../joypad/index';\nimport { Timers } from '../timers/index';\nimport { Interrupts } from '../interrupts/index';\nimport { checkBitOnByte, resetBitOnByte, splitHighByte } from '../helpers/index';\n\n// Returns -1 if no trap found, otherwise returns a value that should be fed for the address\nexport function checkReadTraps(offset: i32): i32 {\n  // Cache globals used multiple times for performance\n  let videoRamLocation = Memory.videoRamLocation;\n\n  // Try to break early for most common scenario\n  if (offset < videoRamLocation) {\n    return -1;\n  }\n\n  // Check the graphics mode to see if we can read VRAM\n  // http://gbdev.gg8.se/wiki/articles/Video_Display#Accessing_VRAM_and_OAM\n  if (offset >= videoRamLocation && offset < Memory.cartridgeRamLocation) {\n    // Can only read/write from VRAM During Modes 0 - 2\n    // See graphics/lcd.ts\n    // TODO: This can do more harm than good in a beta emulator,\n    // requres precise timing, disabling for now\n    // if (Graphics.currentLcdMode > 2) {\n    //   return 0xFF;\n    // }\n\n    return -1;\n  }\n\n  // ECHO Ram, E000\tFDFF\tMirror of C000~DDFF (ECHO RAM)\n  // http://gbdev.gg8.se/wiki/articles/Memory_Map\n  if (offset >= Memory.echoRamLocation && offset < Memory.spriteInformationTableLocation) {\n    // Simply return the mirror'd value\n    return eightBitLoadFromGBMemory(offset - 0x2000);\n  }\n\n  // Check for individal writes\n  // Can only read/write from OAM During Modes 0 - 1\n  // See graphics/lcd.ts\n  if (offset >= Memory.spriteInformationTableLocation && offset <= Memory.spriteInformationTableLocationEnd) {\n    // Can only read/write from OAM During Mode 2\n    // See graphics/lcd.ts\n    // if (Lcd.currentLcdMode < 2) {\n    // return 0xff;\n    // }\n\n    // Not batch processing here for performance\n    // batchProcessGraphics();\n\n    // return -1;\n    return Lcd.currentLcdMode < 2 ? 0xff : -1;\n  }\n\n  // CPU\n  if (offset === Cpu.memoryLocationSpeedSwitch) {\n    // TCAGBD, only Bit 7 and 0 are readable, all others are 1\n    let response = 0xff;\n\n    let currentSpeedSwitchRegister = eightBitLoadFromGBMemory(Cpu.memoryLocationSpeedSwitch);\n    if (!checkBitOnByte(0, currentSpeedSwitchRegister)) {\n      response = resetBitOnByte(0, response);\n    }\n\n    if (!Cpu.GBCDoubleSpeed) {\n      response = resetBitOnByte(7, response);\n    }\n\n    return response;\n  }\n\n  // Graphics\n  // Not batch processing here for performance\n  // batchProcessGraphics();\n  if (offset === Graphics.memoryLocationScanlineRegister) {\n    eightBitStoreIntoGBMemory(offset, Graphics.scanlineRegister);\n    return Graphics.scanlineRegister;\n  }\n\n  // Sound\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n  // TODO: Put these bounds on the Sound Class\n  if (offset >= 0xff10 && offset <= 0xff26) {\n    batchProcessAudio();\n    return SoundRegisterReadTraps(offset);\n  }\n\n  // FF27 - FF2F not used\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Register_Reading\n  // Always read as 0xFF\n  if (offset >= 0xff27 && offset <= 0xff2f) {\n    return 0xff;\n  }\n\n  // Final Wave Table for Channel 3\n  if (offset >= 0xff30 && offset <= 0xff3f) {\n    batchProcessAudio();\n\n    if (Channel3.isEnabled) {\n      return Channel3.handleWaveRamRead();\n    }\n    return -1;\n  }\n\n  // Timers\n  if (offset === Timers.memoryLocationDividerRegister) {\n    // Divider register in memory is just the upper 8 bits\n    // http://gbdev.gg8.se/wiki/articles/Timer_Obscure_Behaviour\n    let upperDividerRegisterBits = splitHighByte(Timers.dividerRegister);\n    eightBitStoreIntoGBMemory(offset, upperDividerRegisterBits);\n    return upperDividerRegisterBits;\n  }\n\n  if (offset === Timers.memoryLocationTimerCounter) {\n    eightBitStoreIntoGBMemory(offset, Timers.timerCounter);\n    return Timers.timerCounter;\n  }\n\n  // Interrupts\n  if (offset === Interrupts.memoryLocationInterruptRequest) {\n    // TCAGB and BGB say the top 5 bits are always 1.\n    return 0xe0 | Interrupts.interruptsRequestedValue;\n  }\n\n  // Joypad\n  if (offset === Joypad.memoryLocationJoypadRegister) {\n    return getJoypadState();\n  }\n\n  return -1;\n}\n","// Functions to help with Handling Duty on Square Channels\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n\nimport { checkBitOnByte } from '../helpers/index';\n\n// Since there are no 2d arrays, we will use a byte to represent duty cycles (wave form from percentages)\nexport function isDutyCycleClockPositiveOrNegativeForWaveform(channelDuty: i32, waveFormPositionOnDuty: i32): boolean {\n  // Get our Wave Form According to the Duty\n  // Default to a duty of 1\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Square_Wave\n  switch (channelDuty) {\n    case 0x01:\n      // 1000 0001\n      return checkBitOnByte(waveFormPositionOnDuty, 0x81);\n    case 0x02:\n      // 1000 0111\n      return checkBitOnByte(waveFormPositionOnDuty, 0x87);\n    case 0x03:\n      // 0111 1110\n      return checkBitOnByte(waveFormPositionOnDuty, 0x7e);\n    default:\n      // 0000 0001\n      return checkBitOnByte(waveFormPositionOnDuty, 0x01);\n  }\n}\n","// Functions involved in R/W of sound registers\n// Information of bits on every register can be found at: https://gist.github.com/drhelius/3652407\n// Passing channel number to make things simpler than passing around memory addresses, to avoid bugs in choosing the wrong address\n\nimport { Sound } from './sound';\nimport { SoundAccumulator } from './accumulator';\nimport { Channel1 } from './channel1';\nimport { Channel2 } from './channel2';\nimport { Channel3 } from './channel3';\nimport { Channel4 } from './channel4';\nimport { eightBitLoadFromGBMemory, eightBitStoreIntoGBMemory, eightBitStoreIntoGBMemoryWithTraps } from '../memory/index';\nimport { checkBitOnByte, setBitOnByte, resetBitOnByte, log } from '../helpers/index';\n\n// Function to check and handle writes to sound registers\n// Inlined because closure compiler inlines\n// NOTE: For write traps, return false = don't write to memory,\n// return true = allow the write to memory\nexport function SoundRegisterWriteTraps(offset: i32, value: i32): boolean {\n  if (offset !== Sound.memoryLocationNR52 && !Sound.NR52IsSoundEnabled) {\n    // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Power_Control\n    // When sound is turned off / enabled\n    // Block all writes to any sound register EXCEPT NR52!\n    // This is under the assumption that the check for\n    // offset >= 0xFF10 && offset <= 0xFF26\n    // is done in writeTraps.ts (which it is)\n    // NOTE: Except on DMG, length can still be written (whatever that means)\n    return false;\n  }\n\n  switch (offset) {\n    // Handle NRx0 on Channels\n    case Channel1.memoryLocationNRx0:\n      Channel1.updateNRx0(value);\n      return true;\n    case Channel3.memoryLocationNRx0:\n      Channel3.updateNRx0(value);\n      return true;\n    // Handle NRx1 (Length Counter) on Channels\n    case Channel1.memoryLocationNRx1:\n      Channel1.updateNRx1(value);\n      return true;\n    case Channel2.memoryLocationNRx1:\n      Channel2.updateNRx1(value);\n      return true;\n    case Channel3.memoryLocationNRx1:\n      Channel3.updateNRx1(value);\n      return true;\n    case Channel4.memoryLocationNRx1:\n      Channel4.updateNRx1(value);\n      return true;\n    // Handle NRx2 (Envelope / Volume) on Channels\n    case Channel1.memoryLocationNRx2:\n      Channel1.updateNRx2(value);\n      return true;\n    case Channel2.memoryLocationNRx2:\n      Channel2.updateNRx2(value);\n      return true;\n    case Channel3.memoryLocationNRx2:\n      // Check if channel 3's volume code was written too\n      // This is handcy to know for accumulation of samples\n      Channel3.volumeCodeChanged = true;\n      Channel3.updateNRx2(value);\n      return true;\n    case Channel4.memoryLocationNRx2:\n      Channel4.updateNRx2(value);\n      return true;\n    // Handle NRx3 (Frequency / Noise Properties) on Channels\n    case Channel1.memoryLocationNRx3:\n      Channel1.updateNRx3(value);\n      return true;\n    case Channel2.memoryLocationNRx3:\n      Channel2.updateNRx3(value);\n      return true;\n    case Channel3.memoryLocationNRx3:\n      Channel3.updateNRx3(value);\n      return true;\n    case Channel4.memoryLocationNRx3:\n      Channel4.updateNRx3(value);\n      return true;\n    // Check our NRx4 registers to trap our trigger bits\n    case Channel1.memoryLocationNRx4:\n      Channel1.updateNRx4(value);\n      return true;\n    case Channel2.memoryLocationNRx4:\n      Channel2.updateNRx4(value);\n      return true;\n    case Channel3.memoryLocationNRx4:\n      Channel3.updateNRx4(value);\n      return true;\n    case Channel4.memoryLocationNRx4:\n      Channel4.updateNRx4(value);\n      return true;\n    // Tell the sound accumulator if volumes changes\n    case Sound.memoryLocationNR50:\n      Sound.updateNR50(value);\n      SoundAccumulator.mixerVolumeChanged = true;\n      return true;\n    // Tell the sound accumulator if volumes changes\n    case Sound.memoryLocationNR51:\n      Sound.updateNR51(value);\n      SoundAccumulator.mixerEnabledChanged = true;\n      return true;\n    case Sound.memoryLocationNR52:\n      // Reset all registers except NR52\n\n      // See if we were enabled, then update the register.\n      let wasNR52Enabled = Sound.NR52IsSoundEnabled;\n\n      // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Power_Control\n      // When powered on, the frame sequencer is reset so that the next step will be 0,\n      // the square duty units are reset to the first step of the waveform,\n      // and the wave channel's sample buffer is reset to 0.\n      if (!wasNR52Enabled && checkBitOnByte(7, value)) {\n        Sound.frameSequencer = 0x07;\n        Channel1.waveFormPositionOnDuty = 0x00;\n        Channel2.waveFormPositionOnDuty = 0x00;\n\n        // TODO: Wave Channel Sample Buffer?\n        // I don't think we clear wave RAM here...\n      }\n\n      // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Power_Control\n      // When powered off, all registers (NR10-NR51) are instantly written with zero\n      // and any writes to those registers are ignored while power remains off\n      if (wasNR52Enabled && !checkBitOnByte(7, value)) {\n        for (let i = 0xff10; i < 0xff26; ++i) {\n          eightBitStoreIntoGBMemoryWithTraps(i, 0x00);\n        }\n      }\n\n      // Need to update our new value here, that way writes go through :p\n      Sound.updateNR52(value);\n      return true;\n  }\n\n  // We did not handle the write, Allow the write\n  return true;\n}\n\n// http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n// Inlined because closure compiler inlines\nexport function SoundRegisterReadTraps(offset: i32): i32 {\n  // Registers must be OR'd with values when being read\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n\n  switch (offset) {\n    // Handle NRx0 on Channels\n    case Channel1.memoryLocationNRx0: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx0);\n      return register | 0x80;\n    }\n    case Channel2.memoryLocationNRx0: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx0);\n      return register | 0xff;\n    }\n    case Channel3.memoryLocationNRx0: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx0);\n      return register | 0x7f;\n    }\n    case Channel4.memoryLocationNRx0: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx0);\n      return register | 0xff;\n    }\n    case Sound.memoryLocationNR50: {\n      let register = eightBitLoadFromGBMemory(Sound.memoryLocationNR50);\n      return register | 0x00;\n    }\n\n    // Handle NRx1 on Channels\n    case Channel1.memoryLocationNRx1: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx1);\n      return register | 0x3f;\n    }\n    case Channel2.memoryLocationNRx1: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx1);\n      return register | 0x3f;\n    }\n    case Channel3.memoryLocationNRx1: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx1);\n      return register | 0xff;\n    }\n    case Channel4.memoryLocationNRx1: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx1);\n      return register | 0xff;\n    }\n    case Sound.memoryLocationNR51: {\n      let register = eightBitLoadFromGBMemory(Sound.memoryLocationNR51);\n      return register | 0x00;\n    }\n\n    // Handle NRx2 on Channels\n    case Channel1.memoryLocationNRx2: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx2);\n      return register | 0x00;\n    }\n    case Channel2.memoryLocationNRx2: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx2);\n      return register | 0x00;\n    }\n    case Channel3.memoryLocationNRx2: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx2);\n      return register | 0x9f;\n    }\n    case Channel4.memoryLocationNRx2: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx2);\n      return register | 0x00;\n    }\n    case Sound.memoryLocationNR52: {\n      // This will fix bugs in orcale of ages :)\n\n      // Start our registerNR52\n      let registerNR52 = 0x00;\n\n      // Set the first bit to the sound paower status\n      if (Sound.NR52IsSoundEnabled) {\n        registerNR52 = setBitOnByte(7, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(7, registerNR52);\n      }\n\n      // Set our lower 4 bits to our channel length statuses\n      if (Channel1.isEnabled) {\n        registerNR52 = setBitOnByte(0, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(0, registerNR52);\n      }\n\n      if (Channel2.isEnabled) {\n        registerNR52 = setBitOnByte(1, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(1, registerNR52);\n      }\n\n      if (Channel3.isEnabled) {\n        registerNR52 = setBitOnByte(2, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(2, registerNR52);\n      }\n\n      if (Channel4.isEnabled) {\n        registerNR52 = setBitOnByte(3, registerNR52);\n      } else {\n        registerNR52 = resetBitOnByte(3, registerNR52);\n      }\n\n      // Or from the table\n      registerNR52 |= 0x70;\n      return registerNR52;\n    }\n\n    // Handle NRx3 on Channels\n    case Channel1.memoryLocationNRx3: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx3);\n      return register | 0xff;\n    }\n    case Channel2.memoryLocationNRx3: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx3);\n      return register | 0xff;\n    }\n    case Channel3.memoryLocationNRx3: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx3);\n      return register | 0xff;\n    }\n    case Channel4.memoryLocationNRx3: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx3);\n      return register | 0x00;\n    }\n\n    // Handle NRx4 on Channels\n    case Channel1.memoryLocationNRx4: {\n      let register = eightBitLoadFromGBMemory(Channel1.memoryLocationNRx4);\n      return register | 0xbf;\n    }\n    case Channel2.memoryLocationNRx4: {\n      let register = eightBitLoadFromGBMemory(Channel2.memoryLocationNRx4);\n      return register | 0xbf;\n    }\n    case Channel3.memoryLocationNRx4: {\n      let register = eightBitLoadFromGBMemory(Channel3.memoryLocationNRx4);\n      return register | 0xbf;\n    }\n    case Channel4.memoryLocationNRx4: {\n      let register = eightBitLoadFromGBMemory(Channel4.memoryLocationNRx4);\n      return register | 0xbf;\n    }\n  }\n\n  return -1;\n}\n","import { Memory } from './memory';\nimport { Cpu } from '../cpu/index';\nimport { Graphics } from '../graphics/graphics';\nimport { Palette, writeColorPaletteToMemory, Lcd } from '../graphics/index';\nimport { batchProcessAudio, SoundRegisterWriteTraps, Channel3 } from '../sound/index';\nimport { Timers, batchProcessTimers } from '../timers/index';\nimport { Serial } from '../serial/serial';\nimport { Interrupts } from '../interrupts/index';\nimport { Joypad } from '../joypad/index';\nimport { handleBanking } from './banking';\nimport { eightBitStoreIntoGBMemory } from './store';\nimport { startDmaTransfer, startHdmaTransfer } from './dma';\n\n// Internal function to trap any modify data trying to be written to Gameboy memory\n// Follows the Gameboy memory map\n// Return true if you want to continue the write, return false to end it here\nexport function checkWriteTraps(offset: i32, value: i32): boolean {\n  // Cpu\n  if (offset === Cpu.memoryLocationSpeedSwitch) {\n    // TCAGBD, only Bit 0 is writable\n    eightBitStoreIntoGBMemory(Cpu.memoryLocationSpeedSwitch, value & 0x01);\n    // We did the write, dont need to\n    return false;\n  }\n\n  // Handle Boot ROM Switch\n  if (Cpu.BootROMEnabled && offset === Cpu.memoryLocationBootROMSwitch) {\n    // Disable the boot rom\n    Cpu.BootROMEnabled = false;\n\n    // Set the program counter to be incremented after this command\n    Cpu.programCounter = 0x00ff;\n\n    // Allow the write\n    return true;\n  }\n\n  // Graphics\n  // Cache globals used multiple times for performance\n  let videoRamLocation = Memory.videoRamLocation;\n  let spriteInformationTableLocation = Memory.spriteInformationTableLocation;\n\n  // Handle banking\n  if (offset < videoRamLocation) {\n    handleBanking(offset, value);\n    return false;\n  }\n\n  // Check the graphics mode to see if we can write to VRAM\n  // http://gbdev.gg8.se/wiki/articles/Video_Display#Accessing_VRAM_and_OAM\n  if (offset >= videoRamLocation && offset < Memory.cartridgeRamLocation) {\n    // Can only read/write from VRAM During Modes 0 - 2\n    // See graphics/lcd.ts\n    // TODO: This can do more harm than good in a beta emulator,\n    // requires precise timing disabling for now\n    // if (Graphics.currentLcdMode > 2) {\n    //   return false;\n    // }\n\n    // Not batch processing here for performance\n    // batchProcessGraphics();\n\n    // Allow the original write, and return since we dont need to look anymore\n    return true;\n  }\n\n  // Be sure to copy everything in EchoRam to Work Ram\n  // Codeslinger: The ECHO memory region (0xE000-0xFDFF) is quite different because any data written here is also written in the equivelent ram memory region 0xC000-0xDDFF.\n  // Hence why it is called echo\n  if (offset >= Memory.echoRamLocation && offset < spriteInformationTableLocation) {\n    let wramOffset = offset - 0x2000;\n    eightBitStoreIntoGBMemory(wramOffset, value);\n\n    // Allow the original write, and return since we dont need to look anymore\n    return true;\n  }\n\n  // Also check for individal writes\n  // Can only read/write from OAM During Modes 0 - 1\n  // See graphics/lcd.ts\n  if (offset >= spriteInformationTableLocation && offset <= Memory.spriteInformationTableLocationEnd) {\n    // Can only read/write from OAM During Mode 2\n    // See graphics/lcd.ts\n    // if (Lcd.currentLcdMode < 2) {\n    // return false;\n    // }\n    // Not batch processing here for performance\n    // batchProcessGraphics();\n\n    // Allow the original write, and return since we dont need to look anymore\n    // return true;\n    return Lcd.currentLcdMode >= 2;\n  }\n\n  if (offset >= Memory.unusableMemoryLocation && offset <= Memory.unusableMemoryEndLocation) {\n    return false;\n  }\n\n  // Serial\n  if (offset === Serial.memoryLocationSerialTransferControl) {\n    // SC\n    return Serial.updateTransferControl(value);\n  }\n\n  // Sound\n  // http://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Registers\n  if (offset >= 0xff10 && offset <= 0xff26) {\n    batchProcessAudio();\n    return SoundRegisterWriteTraps(offset, value);\n  }\n\n  // FF27 - FF2F not used\n\n  // Final Wave Table for Channel 3\n  if (offset >= 0xff30 && offset <= 0xff3f) {\n    batchProcessAudio();\n\n    // Need to handle the write if channel 3 is enabled\n    if (Channel3.isEnabled) {\n      Channel3.handleWaveRamWrite(value);\n      return false;\n    }\n    return true;\n  }\n\n  // Other Memory effects fomr read/write to Lcd/Graphics\n  if (offset >= Lcd.memoryLocationLcdControl && offset <= Graphics.memoryLocationWindowX) {\n    // Not batch processing here for performance\n    // batchProcessGraphics();\n\n    if (offset === Lcd.memoryLocationLcdControl) {\n      // Shorcut for isLCD Enabled since it gets \"hot\"\n      Lcd.updateLcdControl(value);\n      return true;\n    }\n\n    if (offset === Lcd.memoryLocationLcdStatus) {\n      // We are handling the write here\n      Lcd.updateLcdStatus(value);\n      return false;\n    }\n\n    // reset the current scanline if the game tries to write to it\n    if (offset === Graphics.memoryLocationScanlineRegister) {\n      Graphics.scanlineRegister = 0;\n      eightBitStoreIntoGBMemory(offset, 0);\n      return false;\n    }\n\n    // Cache our coincidence compare\n    if (offset === Lcd.memoryLocationCoincidenceCompare) {\n      Lcd.coincidenceCompare = value;\n      return true;\n    }\n\n    // Do the direct memory access transfer for spriteInformationTable\n    // Check the graphics mode to see if we can write to VRAM\n    // http://gbdev.gg8.se/wiki/articles/Video_Display#Accessing_VRAM_and_OAM\n    if (offset === Graphics.memoryLocationDmaTransfer) {\n      // otherwise, perform a DMA transfer\n      // And allow the original write\n      startDmaTransfer(value);\n      return true;\n    }\n\n    // Scroll and Window XY\n    switch (offset) {\n      case Graphics.memoryLocationScrollX:\n        Graphics.scrollX = value;\n        return true;\n      case Graphics.memoryLocationScrollY:\n        Graphics.scrollY = value;\n        return true;\n      case Graphics.memoryLocationWindowX:\n        Graphics.windowX = value;\n        return true;\n      case Graphics.memoryLocationWindowY:\n        Graphics.windowY = value;\n        return true;\n    }\n\n    // Allow the original write, and return since we dont need to look anymore\n    return true;\n  }\n\n  // Do an HDMA\n  if (offset === Memory.memoryLocationHdmaTrigger) {\n    startHdmaTransfer(value);\n    return false;\n  }\n\n  // Don't allow banking if we are doing an Hblank HDM transfer\n  // https://gist.github.com/drhelius/3394856\n  if (offset === Memory.memoryLocationGBCWRAMBank || offset === Memory.memoryLocationGBCVRAMBank) {\n    if (Memory.isHblankHdmaActive) {\n      let hblankHdmaSource = Memory.hblankHdmaSource;\n      if ((hblankHdmaSource >= 0x4000 && hblankHdmaSource <= 0x7fff) || (hblankHdmaSource >= 0xd000 && hblankHdmaSource <= 0xdfff)) {\n        return false;\n      }\n    }\n  }\n\n  // Handle GBC Pallete Write\n  if (offset >= Palette.memoryLocationBackgroundPaletteIndex && offset <= Palette.memoryLocationSpritePaletteData) {\n    // Incremeenting the palette handled by the write\n    writeColorPaletteToMemory(offset, value);\n    return true;\n  }\n\n  // Handle timer writes\n  if (offset >= Timers.memoryLocationDividerRegister && offset <= Timers.memoryLocationTimerControl) {\n    // Batch Process\n    batchProcessTimers();\n\n    switch (offset) {\n      case Timers.memoryLocationDividerRegister:\n        Timers.updateDividerRegister();\n        return false;\n      case Timers.memoryLocationTimerCounter:\n        Timers.updateTimerCounter(value);\n        return true;\n      case Timers.memoryLocationTimerModulo:\n        Timers.updateTimerModulo(value);\n        return true;\n      case Timers.memoryLocationTimerControl:\n        Timers.updateTimerControl(value);\n        return true;\n    }\n\n    return true;\n  }\n\n  // Handle Joypad writes for HW reg caching\n  if (offset === Joypad.memoryLocationJoypadRegister) {\n    Joypad.updateJoypad(value);\n  }\n\n  // Handle Interrupt writes\n  if (offset === Interrupts.memoryLocationInterruptRequest) {\n    Interrupts.updateInterruptRequested(value);\n    return true;\n  }\n  if (offset === Interrupts.memoryLocationInterruptEnabled) {\n    Interrupts.updateInterruptEnabled(value);\n    return true;\n  }\n\n  // Allow the original write\n  return true;\n}\n","import { Cpu } from './index';\nimport { u8Portable, u16Portable } from '../portable/portable';\n\n// Set flag bit on on register F. For instance set zero flag to zero -> (7, 0)\nfunction setFlagBit(flagBit: u8, flagValue: i32): u8 {\n  let bitwiseOperand = u8Portable(1 << flagBit);\n  if (flagValue > 0) {\n    Cpu.registerF = Cpu.registerF | bitwiseOperand;\n  } else {\n    // XOR out the two ones\n    bitwiseOperand = 0xff ^ bitwiseOperand;\n    Cpu.registerF = Cpu.registerF & bitwiseOperand;\n  }\n\n  return Cpu.registerF;\n}\n\n// Overload the set flag bit for ease of use\nexport function setZeroFlag(value: i32): void {\n  setFlagBit(7, value);\n}\n\nexport function setSubtractFlag(value: i32): void {\n  setFlagBit(6, value);\n}\n\nexport function setHalfCarryFlag(value: i32): void {\n  setFlagBit(5, value);\n}\n\nexport function setCarryFlag(value: i32): void {\n  setFlagBit(4, value);\n}\n\n// Getters for flags\nexport function getZeroFlag(): u8 {\n  return (Cpu.registerF >> 7) & 0x01;\n}\n\nexport function getSubtractFlag(): u8 {\n  return (Cpu.registerF >> 6) & 0x01;\n}\n\nexport function getHalfCarryFlag(): u8 {\n  return (Cpu.registerF >> 5) & 0x01;\n}\n\nexport function getCarryFlag(): u8 {\n  return (Cpu.registerF >> 4) & 0x01;\n}\n\n// Must be run before the register actually performs the add\n// amountToAdd i16, since max number can be an u8\nexport function checkAndSetEightBitHalfCarryFlag(value: u8, amountToAdd: i32): void {\n  if (amountToAdd >= 0) {\n    // https://robdor.com/2016/08/10/gameboy-emulator-half-carry-flag/\n    let result = u8Portable(((<u8>value) & 0x0f) + ((<u8>amountToAdd) & 0x0f)) & 0x10;\n    setHalfCarryFlag(<i32>(result !== 0x00));\n  } else {\n    // From: https://github.com/djhworld/gomeboycolor/blob/master/src/cpu/index.go\n    // CTRL+F \"subBytes(a, b byte)\"\n    setHalfCarryFlag(<i32>(<u8>(abs(amountToAdd) & 0x0f) > (value & 0x0f)));\n  }\n}\n\nexport function checkAndSetEightBitCarryFlag(value: u8, amountToAdd: i32): void {\n  if (amountToAdd >= 0) {\n    let result = u8Portable(value + <u8>amountToAdd);\n    setCarryFlag(<i32>(value > result));\n  } else {\n    setCarryFlag(<i32>(abs(amountToAdd) > <i32>value));\n  }\n}\n\n// Function to handle 16 bit addition overflow, and set the carry flags accordingly\n// i32 on valueTwo to support passing signed immedaite values\nexport function checkAndSetSixteenBitFlagsAddOverflow(valueOne: u16, valueTwo: i32, useStackPointerBits: boolean): void {\n  // need to differentiate between HL and SP\n  // HL carries are at 11 and 15, SP carries are at 3 and 7 :p\n  if (useStackPointerBits) {\n    // Logic from : https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n    // CTRL+F add_sp_n\n    // using the stack pointer bits means we can safely assume the value is signed\n    let signedValueOne = <i32>valueOne;\n    let result = signedValueOne + valueTwo;\n    let flagXor = signedValueOne ^ valueTwo ^ result;\n\n    setHalfCarryFlag(<i32>((flagXor & 0x10) !== 0));\n    setCarryFlag(<i32>((flagXor & 0x100) !== 0));\n  } else {\n    // Logic from: https://github.com/djhworld/gomeboycolor/blob/master/src/cpu/index.go\n    // CTRL+F addWords\n    // Value two is not signed\n    let result = u16Portable(valueOne + <u16>valueTwo);\n\n    // Check the carry flag by allowing the overflow\n    setCarryFlag(<i32>(result < valueOne));\n\n    // To check for half carry flag (bit 15), by XOR'ing valyes, and and'ing the bit in question\n    let halfCarryXor: u16 = valueOne ^ (<u16>valueTwo) ^ (<u16>result);\n    let halfCarryAnd = u16Portable(halfCarryXor & 0x1000);\n    setHalfCarryFlag(<i32>(halfCarryAnd !== 0x00));\n  }\n}\n","// Imports\nimport { Cpu } from './index';\nimport {\n  setZeroFlag,\n  setSubtractFlag,\n  setHalfCarryFlag,\n  setCarryFlag,\n  getCarryFlag,\n  checkAndSetEightBitCarryFlag,\n  checkAndSetEightBitHalfCarryFlag\n} from './flags';\nimport { rotateByteLeft, rotateByteLeftThroughCarry, rotateByteRight, rotateByteRightThroughCarry } from '../helpers/index';\nimport { u8Portable, u16Portable, i8Portable } from '../portable/portable';\n\n// General Logic Instructions\n// Such as the ones found on the CB table and 0x40 - 0xBF\n// NOTE: Only CB table uses these for now, was mostly me realizing that I messed up, trying to be all cute and verbose :p\n// NOTE: TODO: Refactor honestly shouldn't take that long, and may happen once assembly script is improved\nexport function addARegister(register: u8): void {\n  let registerA = Cpu.registerA;\n  checkAndSetEightBitHalfCarryFlag(registerA, register);\n  checkAndSetEightBitCarryFlag(registerA, register);\n  registerA = u8Portable(registerA + register);\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(0);\n}\n\nexport function addAThroughCarryRegister(register: u8): void {\n  // Handling flags manually as they require some special overflow\n  // From: https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // CTRL+F adc\n  let registerA = Cpu.registerA;\n  let result = u8Portable(registerA + register + getCarryFlag());\n  setHalfCarryFlag(<i32>((u8Portable(registerA ^ register ^ result) & 0x10) != 0));\n\n  let overflowedResult = u16Portable(<u16>registerA + <u16>register + <u16>getCarryFlag());\n  setCarryFlag(<i32>((overflowedResult & 0x100) > 0));\n\n  Cpu.registerA = result;\n  setZeroFlag(<i32>(result === 0));\n  setSubtractFlag(0);\n}\n\nexport function subARegister(register: u8): void {\n  // Need to convert the register on one line, and flip the sign on another\n  let negativeRegister: i32 = register;\n  negativeRegister = negativeRegister * -1;\n\n  let registerA = Cpu.registerA;\n  checkAndSetEightBitHalfCarryFlag(registerA, negativeRegister);\n  checkAndSetEightBitCarryFlag(registerA, negativeRegister);\n  registerA = u8Portable(registerA - register);\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(1);\n}\n\nexport function subAThroughCarryRegister(register: u8): void {\n  // Handling flags manually as they require some special overflow\n  // From: https://github.com/nakardo/node-gameboy/blob/master/lib/cpu/opcodes.js\n  // CTRL+F adc\n  let registerA = Cpu.registerA;\n  let result = u8Portable(registerA - register - getCarryFlag());\n\n  let carryRegisterCheck = u8Portable((registerA ^ register ^ result) & 0x10);\n  setHalfCarryFlag(<i32>(carryRegisterCheck != 0));\n\n  let overflowedResult = u16Portable(<u16>registerA - <u16>register - <u16>getCarryFlag());\n  setCarryFlag(<i32>((overflowedResult & 0x100) > 0));\n\n  Cpu.registerA = result;\n  setZeroFlag(<i32>(result === 0));\n  setSubtractFlag(1);\n}\n\nexport function andARegister(register: u8): void {\n  let registerA = Cpu.registerA & register;\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(1);\n  setCarryFlag(0);\n}\n\nexport function xorARegister(register: u8): void {\n  let registerA = u8Portable(Cpu.registerA ^ register);\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(0);\n}\n\nexport function orARegister(register: u8): void {\n  let registerA = Cpu.registerA | register;\n  Cpu.registerA = registerA;\n  setZeroFlag(<i32>(registerA === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(0);\n}\n\nexport function cpARegister(register: u8): void {\n  // 0xB8 - 0xBF\n  // CP B\n  // 1  4\n  // Z 1 H C\n  let registerA = Cpu.registerA;\n  let negativeRegister: i32 = register;\n  negativeRegister = negativeRegister * -1;\n  checkAndSetEightBitHalfCarryFlag(registerA, negativeRegister);\n  checkAndSetEightBitCarryFlag(registerA, negativeRegister);\n  let tempResult = <i32>registerA + negativeRegister;\n  setZeroFlag(<i32>(tempResult === 0));\n  setSubtractFlag(1);\n}\n\n// Inlined because closure compiler inlines\nexport function rotateRegisterLeft(register: u8): u8 {\n  // RLC register 8-bit\n  // Z 0 0 C\n  setCarryFlag(<i32>((register & 0x80) === 0x80));\n\n  register = rotateByteLeft(register);\n  setZeroFlag(<i32>(register === 0));\n\n  // Set all other flags to zero\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  // Return the register\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function rotateRegisterRight(register: u8): u8 {\n  // RLC register 8-bit\n  // Z 0 0 C\n  // Check for the last bit, to see if it will be carried\n  setCarryFlag(<i32>((register & 0x01) > 0));\n  register = rotateByteRight(register);\n\n  setZeroFlag(<i32>(register === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  // Return the register\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function rotateRegisterLeftThroughCarry(register: u8): u8 {\n  // RL register 8-bit\n  // Z 0 0 C\n  // setting has first bit since we need to use carry\n  let hasHighbit = (register & 0x80) === 0x80;\n  register = rotateByteLeftThroughCarry(register);\n\n  setCarryFlag(<i32>hasHighbit);\n  setZeroFlag(<i32>(register === 0));\n\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function rotateRegisterRightThroughCarry(register: u8): u8 {\n  // RR register 8-bit\n  // Z 0 0 C\n  let hasLowBit = (register & 0x01) === 0x01;\n  register = rotateByteRightThroughCarry(register);\n\n  setCarryFlag(<i32>hasLowBit);\n  setZeroFlag(<i32>(register === 0));\n\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function shiftLeftRegister(register: u8): u8 {\n  // SLA register 8-bit\n  // Z 0 0 C\n  let hasHighbit = (register & 0x80) === 0x80;\n  register = u8Portable(register << 1);\n\n  setCarryFlag(<i32>hasHighbit);\n  setZeroFlag(<i32>(register === 0));\n\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function shiftRightArithmeticRegister(register: u8): u8 {\n  // SRA register 8-bit\n  // Z 0 0 C\n  // NOTE: This C flag may need to be set to 0;\n  // This preserves the MSB (Most significant bit)\n  let hasHighbit = (register & 0x80) === 0x80;\n  let hasLowbit = (register & 0x01) === 0x01;\n\n  register = u8Portable(register >> 1);\n\n  if (hasHighbit) {\n    register = register | 0x80;\n  }\n\n  setZeroFlag(<i32>(register === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(<i32>hasLowbit);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function swapNibblesOnRegister(register: u8): u8 {\n  // SWAP register 8-bit\n  // Z 0 0 0\n  let highNibble = register & 0xf0;\n  let lowNibble = register & 0x0f;\n  register = u8Portable((lowNibble << 4) | (highNibble >> 4));\n\n  setZeroFlag(<i32>(register === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(0);\n\n  return register;\n}\n\n// Inlined because closure compiler inlines\nexport function shiftRightLogicalRegister(register: u8): u8 {\n  // SRA register 8-bit\n  // Z 0 0 C\n  // NOTE: This C flag may need to be set to 0;\n  // This does NOT preserve MSB (most significant bit)\n\n  let hasLowbit = (register & 0x01) === 0x01;\n  register = u8Portable(register >> 1);\n\n  setZeroFlag(<i32>(register === 0));\n  setSubtractFlag(0);\n  setHalfCarryFlag(0);\n  setCarryFlag(<i32>hasLowbit);\n\n  return register;\n}\n\nexport function testBitOnRegister(bitPosition: u8, register: u8): u8 {\n  // BIT bitPosition ,register 8-bit\n  // Z 0 1 -\n\n  let testByte: u8 = 0x01 << bitPosition;\n  let result = register & testByte;\n\n  setZeroFlag(<i32>(result === 0x00));\n  setSubtractFlag(0);\n  setHalfCarryFlag(1);\n\n  return register;\n}\n\nexport function setBitOnRegister(bitPosition: u8, bitValue: i32, register: u8): u8 {\n  // RES 0,B or SET 0,B depending on bit value\n\n  if (bitValue > 0) {\n    let setByte: u8 = 0x01 << bitPosition;\n    register = register | setByte;\n  } else {\n    // NOT (byte we want)\n    // 0000 0100 becomes 1111 1011\n    let setByte: u8 = ~(0x01 << bitPosition);\n    register = register & setByte;\n  }\n\n  return register;\n}\n\n// Private function for our relative jumps\nexport function relativeJump(value: u8): void {\n  // Need to convert the value to i8, since in this case, u8 can be negative\n  let relativeJumpOffset = i8Portable(<i8>value);\n  let programCounter = Cpu.programCounter;\n  programCounter = u16Portable(programCounter + relativeJumpOffset);\n  // Realtive jump, using bgb debugger\n  // and my debugger shows,\n  // on JR you need to jump to the relative jump offset,\n  // However, if the jump fails (such as conditional), only jump +2 in total\n\n  programCounter = u16Portable(programCounter + 1);\n  Cpu.programCounter = programCounter;\n}\n","// Imports\nimport { Cpu } from './index';\nimport {\n  rotateRegisterLeft,\n  rotateRegisterRight,\n  rotateRegisterLeftThroughCarry,\n  rotateRegisterRightThroughCarry,\n  shiftLeftRegister,\n  shiftRightArithmeticRegister,\n  swapNibblesOnRegister,\n  shiftRightLogicalRegister,\n  testBitOnRegister,\n  setBitOnRegister\n} from './instructions';\nimport { eightBitLoadSyncCycles, eightBitStoreSyncCycles } from './opcodes';\nimport { concatenateBytes } from '../helpers/index';\n\n// Handle CB Opcodes\n// NOTE: Program stpes and cycles are standardized depending on the register type\n// NOTE: Doing some funny stuff to get around not having arrays or objects\n// Inlined because closure compiler inlines.\nexport function handleCbOpcode(cbOpcode: i32): i32 {\n  let numberOfCycles = -1;\n  let handledOpcode = false;\n\n  // The result of our cb logic instruction\n  let instructionRegisterValue: u8 = 0;\n  let instructionRegisterResult: u8 = 0;\n\n  // Get our register number by modulo 0x08 (number of registers)\n  // cbOpcode % 0x08\n  let registerNumber = cbOpcode & 0x07;\n\n  // NOTE: registerNumber = register on CB table. Cpu.registerB = 0, Cpu.registerC = 1....Cpu.registerA = 7\n  switch (registerNumber) {\n    case 0:\n      instructionRegisterValue = Cpu.registerB;\n      break;\n    case 1:\n      instructionRegisterValue = Cpu.registerC;\n      break;\n    case 2:\n      instructionRegisterValue = Cpu.registerD;\n      break;\n    case 3:\n      instructionRegisterValue = Cpu.registerE;\n      break;\n    case 4:\n      instructionRegisterValue = Cpu.registerH;\n      break;\n    case 5:\n      instructionRegisterValue = Cpu.registerL;\n      break;\n    case 6:\n      // Value at register HL\n      // 4 cycles\n      instructionRegisterValue = <u8>eightBitLoadSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL));\n      break;\n    case 7:\n      instructionRegisterValue = Cpu.registerA;\n      break;\n  }\n\n  // Grab the high nibble to perform skips to speed up performance\n  let opcodeHighNibble = cbOpcode & 0xf0;\n  opcodeHighNibble = opcodeHighNibble >> 4;\n\n  // Send to the correct function\n  switch (opcodeHighNibble) {\n    case 0x00:\n      if (cbOpcode <= 0x07) {\n        // RLC register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = rotateRegisterLeft(instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x0f) {\n        // RRC register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = rotateRegisterRight(instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x01:\n      if (cbOpcode <= 0x17) {\n        // RL register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = rotateRegisterLeftThroughCarry(instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x1f) {\n        // RR register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = rotateRegisterRightThroughCarry(instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x02:\n      if (cbOpcode <= 0x27) {\n        // SLA register 8-bit\n        // Z 0 0 C\n        instructionRegisterResult = shiftLeftRegister(instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x2f) {\n        // SRA register 8-bit\n        // Z 0 0 0\n        instructionRegisterResult = shiftRightArithmeticRegister(instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x03:\n      if (cbOpcode <= 0x37) {\n        // SWAP register 8-bit\n        // Z 0 0 0\n        instructionRegisterResult = swapNibblesOnRegister(instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x3f) {\n        // SRL B\n        // Z 0 0 C\n        instructionRegisterResult = shiftRightLogicalRegister(instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x04:\n      if (cbOpcode <= 0x47) {\n        // BIT 0,register 8-bit\n        // Z 0 1 -\n        //TODO: Optimize this not to do logic of setting register back\n        instructionRegisterResult = testBitOnRegister(0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x4f) {\n        // BIT 1,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x05:\n      if (cbOpcode <= 0x57) {\n        // BIT 2,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(2, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x5f) {\n        // BIT 3,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(3, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x06:\n      if (cbOpcode <= 0x67) {\n        // BIT 4,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(4, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x6f) {\n        // BIT 5,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(5, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x07:\n      if (cbOpcode <= 0x77) {\n        // BIT 6,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(6, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x7f) {\n        // BIT 7,register 8-bit\n        // Z 0 1 -\n        instructionRegisterResult = testBitOnRegister(7, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x08:\n      if (cbOpcode <= 0x87) {\n        // Res 0,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(0, 0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x8f) {\n        // Res 1,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(1, 0, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x09:\n      if (cbOpcode <= 0x97) {\n        // Res 2,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(2, 0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0x9f) {\n        // Res 3,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(3, 0, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0a:\n      if (cbOpcode <= 0xa7) {\n        // Res 4,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(4, 0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xaf) {\n        // Res 5,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(5, 0, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0b:\n      if (cbOpcode <= 0xb7) {\n        // Res 6,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(6, 0, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xbf) {\n        // Res 7,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(7, 0, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0c:\n      if (cbOpcode <= 0xc7) {\n        // SET 0,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(0, 1, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xcf) {\n        // SET 1,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(1, 1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0d:\n      if (cbOpcode <= 0xd7) {\n        // SET 2,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(2, 1, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xdf) {\n        // SET 3,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(3, 1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0e:\n      if (cbOpcode <= 0xe7) {\n        // SET 4,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(4, 1, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xef) {\n        // SET 5,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(5, 1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n    case 0x0f:\n      if (cbOpcode <= 0xf7) {\n        // SET 6,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(6, 1, instructionRegisterValue);\n        handledOpcode = true;\n      } else if (cbOpcode <= 0xff) {\n        // SET 7,register 8-bit\n        // - - - -\n        instructionRegisterResult = setBitOnRegister(7, 1, instructionRegisterValue);\n        handledOpcode = true;\n      }\n      break;\n  }\n\n  // Finally Pass back into the correct register\n  switch (registerNumber) {\n    case 0:\n      Cpu.registerB = instructionRegisterResult;\n      break;\n    case 1:\n      Cpu.registerC = instructionRegisterResult;\n      break;\n    case 2:\n      Cpu.registerD = instructionRegisterResult;\n      break;\n    case 3:\n      Cpu.registerE = instructionRegisterResult;\n      break;\n    case 4:\n      Cpu.registerH = instructionRegisterResult;\n      break;\n    case 5:\n      Cpu.registerL = instructionRegisterResult;\n      break;\n    case 6:\n      // Value at register HL\n\n      // Opcodes 0x40 -> 0x7F only do simple\n      // Bit test, and don't need to be stored back in memory\n      // Thus they take 4 less cycles to run\n      if (opcodeHighNibble < 0x04 || opcodeHighNibble > 0x07) {\n        // Store the result back\n        // 4 cycles\n        eightBitStoreSyncCycles(concatenateBytes(Cpu.registerH, Cpu.registerL), instructionRegisterResult);\n      }\n      break;\n    case 7:\n      Cpu.registerA = instructionRegisterResult;\n      break;\n  }\n\n  // Finally our number of cycles\n  // Set if we handled the opcode\n  if (handledOpcode) {\n    numberOfCycles = 4;\n  }\n\n  // Return our number of cycles\n  return numberOfCycles;\n}\n","// Functions to get information about the emulator for debugging purposes\nimport { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory } from '../memory/index';\n\nexport function getRegisterA(): u8 {\n  return Cpu.registerA;\n}\n\nexport function getRegisterB(): u8 {\n  return Cpu.registerB;\n}\n\nexport function getRegisterC(): u8 {\n  return Cpu.registerC;\n}\n\nexport function getRegisterD(): u8 {\n  return Cpu.registerD;\n}\n\nexport function getRegisterE(): u8 {\n  return Cpu.registerE;\n}\n\nexport function getRegisterH(): u8 {\n  return Cpu.registerH;\n}\n\nexport function getRegisterL(): u8 {\n  return Cpu.registerL;\n}\n\nexport function getRegisterF(): u8 {\n  return Cpu.registerF;\n}\n\nexport function getProgramCounter(): u16 {\n  return Cpu.programCounter;\n}\n\nexport function getStackPointer(): u16 {\n  return Cpu.stackPointer;\n}\n\nexport function getOpcodeAtProgramCounter(): u8 {\n  return <u8>eightBitLoadFromGBMemory(Cpu.programCounter);\n}\n","// Functions to debug graphical output\nimport { BACKGROUND_MAP_LOCATION, TILE_DATA_LOCATION, OAM_TILES_LOCATION } from '../constants';\nimport {\n  Graphics,\n  Lcd,\n  getTileDataAddress,\n  drawPixelsFromLineOfTile,\n  getMonochromeColorFromPalette,\n  getColorizedGbHexColorFromPalette,\n  getRedFromHexColor,\n  getGreenFromHexColor,\n  getBlueFromHexColor,\n  getRgbColorFromPalette,\n  getColorComponentFromRgb,\n  loadFromVramBank\n} from '../graphics/index';\nimport { Cpu } from '../cpu/index';\nimport { eightBitLoadFromGBMemory, Memory } from '../memory/index';\nimport { checkBitOnByte } from '../helpers/index';\n\n// Some Simple internal getters\nexport function getLY(): i32 {\n  return Graphics.scanlineRegister;\n}\n\nexport function getScrollX(): i32 {\n  return Graphics.scrollX;\n}\n\nexport function getScrollY(): i32 {\n  return Graphics.scrollY;\n}\n\nexport function getWindowX(): i32 {\n  return Graphics.windowX;\n}\n\nexport function getWindowY(): i32 {\n  return Graphics.windowY;\n}\n\n// TODO: Render by tile, rather than by pixel\nexport function drawBackgroundMapToWasmMemory(showColor: i32): void {\n  // http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n  // Bit 7 - LCD Display Enable (0=Off, 1=On)\n  // Bit 6 - Window Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)\n  // Bit 5 - Window Display Enable (0=Off, 1=On)\n  // Bit 4 - BG & Window Tile Data Select (0=8800-97FF, 1=8000-8FFF)\n  // Bit 3 - BG Tile Map Display Select (0=9800-9BFF, 1=9C00-9FFF)\n  // Bit 2 - OBJ (Sprite) Size (0=8x8, 1=8x16)\n  // Bit 1 - OBJ (Sprite) Display Enable (0=Off, 1=On)\n  // Bit 0 - BG Display (for CGB see below) (0=Off, 1=On)\n\n  // Get our seleted tile data memory location\n  let tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectZeroStart;\n  if (Lcd.bgWindowTileDataSelect) {\n    tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectOneStart;\n  }\n\n  let tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectZeroStart;\n  if (Lcd.bgTileMapDisplaySelect) {\n    tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectOneStart;\n  }\n\n  for (let y: i32 = 0; y < 256; y++) {\n    for (let x: i32 = 0; x < 256; x++) {\n      // Get our current Y\n      let pixelYPositionInMap: i32 = y;\n\n      // Get our Current X position of our pixel on the on the 160x144 camera\n      // this is done by getting the current scroll X position,\n      // and adding it do what X Value the scanline is drawing on the camera.\n      let pixelXPositionInMap: i32 = x;\n\n      // Divide our pixel position by 8 to get our tile.\n      // Since, there are 256x256 pixels, and 32x32 tiles.\n      // 256 / 8 = 32.\n      // Also, bitshifting by 3, do do a division by 8\n      // Need to use u16s, as they will be used to compute an address, which will cause weird errors and overflows\n      let tileXPositionInMap: i32 = pixelXPositionInMap >> 3;\n      let tileYPositionInMap: i32 = pixelYPositionInMap >> 3;\n\n      // Get our tile address on the tileMap\n      // NOTE: (tileMap represents where each tile is displayed on the screen)\n      // NOTE: (tile map represents the entire map, now just what is within the \"camera\")\n      // For instance, if we have y pixel 144. 144 / 8 = 18. 18 * 32 = line address in map memory.\n      // And we have x pixel 160. 160 / 8 = 20.\n      // * 32, because remember, this is NOT only for the camera, the actual map is 32x32. Therefore, the next tile line of the map, is 32 byte offset.\n      // Think like indexing a 2d array, as a 1d array and it make sense :)\n      let tileMapAddress: i32 = tileMapMemoryLocation + tileYPositionInMap * 32 + tileXPositionInMap;\n\n      // Get the tile Id on the Tile Map\n      let tileIdFromTileMap: i32 = loadFromVramBank(tileMapAddress, 0);\n\n      // Now get our tileDataAddress for the corresponding tileID we found in the map\n      // Read the comments in _getTileDataAddress() to see what's going on.\n      // tl;dr if we had the tile map of \"a b c d\", and wanted tileId 2.\n      // This funcitons returns the start of memory locaiton for the tile 'c'.\n      let tileDataAddress: i32 = getTileDataAddress(tileDataMemoryLocation, tileIdFromTileMap);\n\n      // Now we can process the the individual bytes that represent the pixel on a tile\n\n      // Get the y pixel of the 8 by 8 tile.\n      // Simply modulo the scanline.\n      // For instance, let's say we are printing the first line of pixels on our camera,\n      // And the first line of pixels on our tile.\n      // yPixel = 1. 1 % 8 = 1.\n      // And for the last line\n      // yPixel = 144. 144 % 8 = 0.\n      // 0 Represents last line of pixels in a tile, 1 represents first. 1 2 3 4 5 6 7 0.\n      // Because remember, we are counting lines on the display NOT including zero\n      let pixelYInTile: i32 = pixelYPositionInMap % 8;\n\n      // Same logic as pixelYInTile.\n      // However, We need to reverse our byte,\n      // As pixel 0 is on byte 7, and pixel 1 is on byte 6, etc...\n      // Therefore, is pixelX was 2, then really is need to be 5\n      // So 2 - 7 = -5, * 1 = 5\n      // Or to simplify, 7 - 2 = 5 haha!\n      let pixelXInTile: i32 = pixelXPositionInMap % 8;\n      pixelXInTile = 7 - pixelXInTile;\n\n      // Get the GB Map Attributes\n      // Bit 0-2  Background Palette number  (BGP0-7)\n      // Bit 3    Tile VRAM Bank number      (0=Bank 0, 1=Bank 1)\n      // Bit 4    Not used\n      // Bit 5    Horizontal Flip            (0=Normal, 1=Mirror horizontally)\n      // Bit 6    Vertical Flip              (0=Normal, 1=Mirror vertically)\n      // Bit 7    BG-to-OAM Priority         (0=Use OAM priority bit, 1=BG Priority)\n      let bgMapAttributes: i32 = 0;\n      if (Cpu.GBCEnabled && showColor > 0) {\n        bgMapAttributes = loadFromVramBank(tileMapAddress, 1);\n      }\n\n      if (checkBitOnByte(6, bgMapAttributes)) {\n        // We are mirroring the tile, therefore, we need to opposite byte\n        // So if our pizel was 0 our of 8, it wild become 7 :)\n        // TODO: This may be wrong :p\n        pixelYInTile = 7 - pixelYInTile;\n      }\n\n      // Remember to represent a single line of 8 pixels on a tile, we need two bytes.\n      // Therefore, we need to times our modulo by 2, to get the correct line of pixels on the tile.\n      // But we need to load the time from a specific Vram bank\n      let vramBankId: i32 = 0;\n      if (checkBitOnByte(3, bgMapAttributes)) {\n        vramBankId = 1;\n      }\n\n      // Remember to represent a single line of 8 pixels on a tile, we need two bytes.\n      // Therefore, we need to times our modulo by 2, to get the correct line of pixels on the tile.\n      // Again, think like you had to map a 2d array as a 1d.\n      let byteOneForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2, vramBankId);\n      let byteTwoForLineOfTilePixels: i32 = loadFromVramBank(tileDataAddress + pixelYInTile * 2 + 1, vramBankId);\n\n      // Now we can get the color for that pixel\n      // Colors are represented by getting X position of ByteTwo, and X positon of Byte One\n      // To Get the color Id.\n      // For example, the result of the color id is 0000 00[xPixelByteTwo][xPixelByteOne]\n      // See: How to draw a tile/sprite from memory: http://www.codeslinger.co.uk/pages/projects/gameboy/graphics.html\n      let paletteColorId: i32 = 0;\n      if (checkBitOnByte(pixelXInTile, byteTwoForLineOfTilePixels)) {\n        // Byte one represents the second bit in our color id, so bit shift\n        paletteColorId += 1;\n        paletteColorId = paletteColorId << 1;\n      }\n      if (checkBitOnByte(pixelXInTile, byteOneForLineOfTilePixels)) {\n        paletteColorId += 1;\n      }\n\n      // FINALLY, RENDER THAT PIXEL!\n      let pixelStart: i32 = (y * 256 + x) * 3;\n\n      if (Cpu.GBCEnabled && showColor > 0) {\n        // Finally lets add some, C O L O R\n        // Want the botom 3 bits\n        let bgPalette: i32 = bgMapAttributes & 0x07;\n\n        // Call the helper function to grab the correct color from the palette\n        let rgbColorPalette: i32 = getRgbColorFromPalette(bgPalette, paletteColorId, false);\n\n        // Split off into red green and blue\n        let red: i32 = getColorComponentFromRgb(0, rgbColorPalette);\n        let green: i32 = getColorComponentFromRgb(1, rgbColorPalette);\n        let blue: i32 = getColorComponentFromRgb(2, rgbColorPalette);\n\n        let offset: i32 = BACKGROUND_MAP_LOCATION + pixelStart;\n        store<u8>(offset, <u8>red);\n        store<u8>(offset + 1, <u8>green);\n        store<u8>(offset + 2, <u8>blue);\n      } else {\n        // Only rendering camera for now, so coordinates are for the camera.\n        // Get the rgb value for the color Id, will be repeated into R, G, B (if not colorized)\n        let hexColor: i32 = getColorizedGbHexColorFromPalette(paletteColorId, Graphics.memoryLocationBackgroundPalette);\n\n        let offset: i32 = BACKGROUND_MAP_LOCATION + pixelStart;\n\n        // Red\n        store<u8>(offset + 0, <u8>getRedFromHexColor(hexColor));\n        // Green\n        store<u8>(offset + 1, <u8>getGreenFromHexColor(hexColor));\n        // Blue\n        store<u8>(offset + 2, <u8>getBlueFromHexColor(hexColor));\n      }\n    }\n  }\n}\n\nexport function drawTileDataToWasmMemory(): void {\n  for (let tileDataMapGridY: i32 = 0; tileDataMapGridY < 0x17; tileDataMapGridY++) {\n    for (let tileDataMapGridX: i32 = 0; tileDataMapGridX < 0x1f; tileDataMapGridX++) {\n      // Get Our VramBankID\n      let vramBankId: i32 = 0;\n      if (tileDataMapGridX > 0x0f) {\n        vramBankId = 1;\n      }\n\n      // Get our tile ID\n      let tileId: i32 = tileDataMapGridY;\n      if (tileDataMapGridY > 0x0f) {\n        tileId -= 0x0f;\n      }\n      tileId = tileId << 4;\n      if (tileDataMapGridX > 0x0f) {\n        tileId = tileId + (tileDataMapGridX - 0x0f);\n      } else {\n        tileId = tileId + tileDataMapGridX;\n      }\n\n      // Finally get our tile Data location\n      let tileDataMemoryLocation: i32 = Graphics.memoryLocationTileDataSelectOneStart;\n      if (tileDataMapGridY > 0x0f) {\n        tileDataMemoryLocation = Graphics.memoryLocationTileDataSelectZeroStart;\n      }\n\n      // Let's see if we have C O L O R\n      // Set the map and sprite attributes to -1\n      // Meaning, we will draw monochrome\n      let paletteLocation: i32 = Graphics.memoryLocationBackgroundPalette;\n      let bgMapAttributes: i32 = -1;\n      let spriteAttributes: i32 = -1;\n\n      // Let's see if the tile is being used by a sprite\n      for (let spriteRow: i32 = 0; spriteRow < 8; spriteRow++) {\n        for (let spriteColumn: i32 = 0; spriteColumn < 5; spriteColumn++) {\n          let spriteIndex = spriteColumn * 8 + spriteRow;\n\n          // Sprites occupy 4 bytes in the sprite attribute table\n          let spriteTableIndex: i32 = spriteIndex * 4;\n          let spriteTileId: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 2);\n\n          if (tileId === spriteTileId) {\n            let currentSpriteAttributes: i32 = eightBitLoadFromGBMemory(\n              Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 3\n            );\n\n            let spriteVramBankId: i32 = 0;\n            if (Cpu.GBCEnabled && checkBitOnByte(3, currentSpriteAttributes)) {\n              spriteVramBankId = 1;\n            }\n\n            if (spriteVramBankId === vramBankId) {\n              spriteAttributes = currentSpriteAttributes;\n              spriteRow = 8;\n              spriteColumn = 5;\n\n              // Set our paletteLocation\n              paletteLocation = Graphics.memoryLocationSpritePaletteOne;\n              if (checkBitOnByte(4, spriteAttributes)) {\n                paletteLocation = Graphics.memoryLocationSpritePaletteTwo;\n              }\n            }\n          }\n        }\n      }\n\n      // If we didn't find a sprite,\n      // Let's see if the tile is on the bg tile map\n      // If so, use that bg map for attributes\n      if (Cpu.GBCEnabled && spriteAttributes < 0) {\n        let tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectZeroStart;\n        if (Lcd.bgTileMapDisplaySelect) {\n          tileMapMemoryLocation = Graphics.memoryLocationTileMapSelectOneStart;\n        }\n        // Loop through the tileMap, and find if we have our current ID\n        let foundTileMapAddress: i32 = -1;\n        for (let x: i32 = 0; x < 32; x++) {\n          for (let y: i32 = 0; y < 32; y++) {\n            let tileMapAddress: i32 = tileMapMemoryLocation + y * 32 + x;\n            let tileIdFromTileMap: i32 = loadFromVramBank(tileMapAddress, 0);\n\n            // Check if we found our tileId\n            if (tileId === tileIdFromTileMap) {\n              foundTileMapAddress = tileMapAddress;\n              x = 32;\n              y = 32;\n            }\n          }\n        }\n\n        if (foundTileMapAddress >= 0) {\n          bgMapAttributes = loadFromVramBank(foundTileMapAddress, 1);\n        }\n      }\n\n      // Draw each Y line of the tile\n      for (let tileLineY: i32 = 0; tileLineY < 8; tileLineY++) {\n        drawPixelsFromLineOfTile(\n          tileId, // tileId\n          tileDataMemoryLocation, // Graphics.memoryLocationTileDataSelect\n          vramBankId, // Vram Bank\n          0, // Tile Line X Start\n          7, // Tile Line X End\n          tileLineY, // Tile Line Y\n          tileDataMapGridX * 8, // Output line X\n          tileDataMapGridY * 8 + tileLineY, // Output line Y\n          0x1f * 8, // Output Width\n          TILE_DATA_LOCATION, // Wasm Memory Start\n          false, // shouldRepresentMonochromeColorByColorId\n          paletteLocation, // paletteLocation\n          bgMapAttributes, // bgMapAttributes\n          spriteAttributes // spriteAttributes\n        );\n      }\n    }\n  }\n}\n\nexport function drawOamToWasmMemory(): void {\n  // Draw all 40 sprites\n  // Going to be like BGB and do 8 x 5 sprites\n  for (let spriteRow: i32 = 0; spriteRow < 8; spriteRow++) {\n    for (let spriteColumn: i32 = 0; spriteColumn < 5; spriteColumn++) {\n      let spriteIndex = spriteColumn * 8 + spriteRow;\n\n      // Sprites occupy 4 bytes in the sprite attribute table\n      let spriteTableIndex: i32 = spriteIndex * 4;\n\n      // Y positon is offset by 16, X position is offset by 8\n\n      let spriteYPosition: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex);\n      let spriteXPosition: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 1);\n      let spriteTileId: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 2);\n\n      let tilesToDraw: i32 = 1;\n      if (Lcd.tallSpriteSize) {\n        // @binji says in 8x16 mode, even tileId always drawn first\n        // This will fix shantae sprites which always uses odd numbered indexes\n\n        // TODO: Do the actual Pandocs thing:\n        // \"In 8x16 mode, the lower bit of the tile number is ignored. Ie. the upper 8x8 tile is \"NN AND FEh\", and the lower 8x8 tile is \"NN OR 01h\".\"\n        // So just knock off the last bit? :)\n        if (spriteTileId % 2 === 1) {\n          spriteTileId -= 1;\n        }\n\n        tilesToDraw += 1;\n      }\n\n      // Get our sprite attributes since we know we shall be drawing the tile\n      let spriteAttributes: i32 = eightBitLoadFromGBMemory(Graphics.memoryLocationSpriteAttributesTable + spriteTableIndex + 3);\n\n      // Check if we should flip the sprite on the x or y axis\n      let flipSpriteY: boolean = checkBitOnByte(6, spriteAttributes);\n      let flipSpriteX: boolean = checkBitOnByte(5, spriteAttributes);\n\n      // Find which VRAM Bank to load from\n      let vramBankId: i32 = 0;\n      if (Cpu.GBCEnabled && checkBitOnByte(3, spriteAttributes)) {\n        vramBankId = 1;\n      }\n\n      // Find which monochrome palette we should use\n      let paletteLocation: i32 = Graphics.memoryLocationSpritePaletteOne;\n      if (checkBitOnByte(4, spriteAttributes)) {\n        paletteLocation = Graphics.memoryLocationSpritePaletteTwo;\n      }\n\n      // Start Drawing our tiles\n      for (let i: i32 = 0; i < tilesToDraw; i++) {\n        // Draw each Y line of the tile\n        for (let tileLineY: i32 = 0; tileLineY < 8; tileLineY++) {\n          drawPixelsFromLineOfTile(\n            spriteTileId + i, // tileId\n            Graphics.memoryLocationTileDataSelectOneStart, // Graphics.memoryLocationTileDataSelect\n            vramBankId, // VRAM Bank\n            0, // Tile Line X Start\n            7, // Tile Line X End\n            tileLineY, // Tile Line Y\n            spriteRow * 8, // Output line X\n            spriteColumn * 16 + tileLineY + i * 8, // Output line Y\n            8 * 8, // Output Width\n            OAM_TILES_LOCATION, // Wasm Memory Start\n            false, // shouldRepresentMonochromeColorByColorId\n            paletteLocation, // paletteLocation\n            -1, // bgMapAttributes\n            spriteAttributes // spriteAttributes\n          );\n        }\n      }\n    }\n  }\n}\n","import { Timers } from '../timers/timers';\nimport { setBitOnByte } from '../helpers/index';\n\nexport function getDIV(): i32 {\n  return Timers.dividerRegister;\n}\n\nexport function getTIMA(): i32 {\n  return Timers.timerCounter;\n}\n\nexport function getTMA(): i32 {\n  return Timers.timerModulo;\n}\n\nexport function getTAC(): i32 {\n  let response: i32 = Timers.timerInputClock;\n\n  if (Timers.timerEnabled) {\n    response = setBitOnByte(2, response);\n  }\n\n  return response;\n}\n","// Functions to debug internal gameboy memory\n// Great for disassembelr\nimport { DEBUG_GAMEBOY_MEMORY_LOCATION, DEBUG_GAMEBOY_MEMORY_SIZE } from '../constants';\nimport { eightBitLoadFromGBMemoryWithTraps } from '../memory/index';\nimport { Breakpoints } from './breakpoints';\n\nexport function updateDebugGBMemory(): void {\n  for (let i: i32 = 0; i < DEBUG_GAMEBOY_MEMORY_SIZE; i++) {\n    store<u8>(DEBUG_GAMEBOY_MEMORY_LOCATION + i, eightBitLoadFromGBMemoryWithTraps(i));\n  }\n\n  // Since we are debugging, we don't want to be responsible for tripping the breakpoints\n  Breakpoints.reachedBreakpoint = false;\n}\n"]}