Home | History | Annotate | Download | only in octane
      1 // Portions copyright 2012 Google, Inc
      2 
      3 // Copyright (C) 2010 - 2012 Grant Galitz
      4 // This program is free software; you can redistribute it and/or modify
      5 // it under the terms of the GNU General Public License version 2 as
      6 // published by the Free Software Foundation.
      7 // The full license is available at http://www.gnu.org/licenses/gpl.html
      8 // This program is distributed in the hope that it will be useful, but
      9 // WITHOUT ANY WARRANTY; without even the implied warranty of
     10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     11 // See the GNU General Public License for more details.
     12 
     13 // The code has been adapted for use as a benchmark by Google.
     14 
     15 var GameboyBenchmark = new BenchmarkSuite('Gameboy', 18000000,
     16                                           [new Benchmark('Gameboy',
     17                                                          runGameboy,
     18                                                          setupGameboy,
     19                                                          tearDownGameboy,
     20                                                          4)]);
     21 
     22 var decoded_gameboy_rom = null;
     23 
     24 function setupGameboy() {
     25 
     26   // Check if all the types required by the code are supported.
     27   // If not, throw exception and quit.
     28   if (!(typeof Uint8Array != "undefined" &&
     29       typeof Int8Array != "undefined" &&
     30       typeof Float32Array != "undefined" &&
     31       typeof Int32Array != "undefined") ) {
     32     throw "TypedArrayUnsupported";
     33   }
     34   decoded_gameboy_rom = base64_decode(gameboy_rom);
     35   rom = null;
     36 }
     37 
     38 function runGameboy() {
     39   start(new GameBoyCanvas(), decoded_gameboy_rom);
     40 
     41   gameboy.instructions = 0;
     42   gameboy.totalInstructions = 250000;
     43 
     44   while (gameboy.instructions <= gameboy.totalInstructions) {
     45     gameboy.run();
     46     GameBoyAudioNode.run();
     47   }
     48 
     49   resetGlobalVariables();
     50 }
     51 
     52 function tearDownGameboy() {
     53   decoded_gameboy_rom = null;
     54   expectedGameboyStateStr = null;
     55 }
     56 
     57 var expectedGameboyStateStr =
     58   '{"registerA":160,"registerB":255,"registerC":255,"registerE":11,' +
     59   '"registersHL":51600,"programCounter":24309,"stackPointer":49706,' +
     60   '"sumROM":10171578,"sumMemory":3435856,"sumMBCRam":234598,"sumVRam":0}';
     61 
     62 // Start of browser emulation.
     63 
     64 GameBoyWindow = { };
     65 
     66 function GameBoyContext() {
     67   this.createBuffer = function() {
     68     return new Buffer();
     69   }
     70   this.createImageData = function (w, h) {
     71     var result = {};
     72     result.data = new Uint8Array(w * h);
     73     return result;
     74   }
     75   this.putImageData = function (buffer, x, y) {
     76     var sum = 0;
     77     for (var i = 0; i < buffer.data.length; i++) {
     78       sum += i * buffer.data[i];
     79       sum = sum % 1000;
     80     }
     81   }
     82   this.drawImage = function () { }
     83 };
     84 
     85 function GameBoyCanvas() {
     86   this.getContext = function() {
     87     return new GameBoyContext();
     88   }
     89   this.width = 160;
     90   this.height = 144;
     91   this.style = { visibility: "visibile" };
     92 }
     93 
     94 function cout(message, colorIndex) {
     95 }
     96 
     97 function clear_terminal() {
     98 }
     99 
    100 var GameBoyAudioNode = {
    101   bufferSize : 0,
    102   onaudioprocess : null ,
    103   connect : function () {},
    104   run: function() {
    105     var event = {outputBuffer : this.outputBuffer};
    106     this.onaudioprocess(event);
    107   }
    108 };
    109 
    110 function GameBoyAudioContext () {
    111   this.createBufferSource = function() {
    112     return { noteOn : function () {}, connect : function() {}};
    113   }
    114   this.sampleRate = 48000;
    115   this.destination = {}
    116   this.createBuffer = function (channels, len, sampleRate) {
    117     return { gain : 1,
    118              numberOfChannels : 1,
    119              length : 1,
    120              duration : 0.000020833333110203966,
    121              sampleRate : 48000}
    122   }
    123   this.createJavaScriptNode = function (bufferSize, inputChannels, outputChannels) {
    124     GameBoyAudioNode.bufferSize = bufferSize;
    125     GameBoyAudioNode.outputBuffer = {
    126         getChannelData : function (i) {return this.channelData[i];},
    127         channelData    : []
    128     };
    129     for (var i = 0; i < outputChannels; i++) {
    130       GameBoyAudioNode.outputBuffer.channelData[i] = new Float32Array(bufferSize);
    131     }
    132     return GameBoyAudioNode;
    133   }
    134 }
    135 
    136 var mock_date_time_counter = 0;
    137 
    138 function new_Date() {
    139   return {
    140     getTime: function() {
    141       mock_date_time_counter += 16;
    142       return mock_date_time_counter;
    143     }
    144   };
    145 }
    146 
    147 // End of browser emulation.
    148 
    149 // Start of helper functions.
    150 
    151 function checkFinalState() {
    152   function sum(a) {
    153     var result = 0;
    154     for (var i = 0; i < a.length; i++) {
    155       result += a[i];
    156     }
    157     return result;
    158   }
    159   var state = {
    160     registerA: gameboy.registerA,
    161     registerB: gameboy.registerB,
    162     registerC: gameboy.registerC,
    163     registerE: gameboy.registerE,
    164     registerF: gameboy.registerF,
    165     registersHL: gameboy.registersHL,
    166     programCounter: gameboy.programCounter,
    167     stackPointer: gameboy.stackPointer,
    168     sumROM : sum(gameboy.fromTypedArray(gameboy.ROM)),
    169     sumMemory: sum(gameboy.fromTypedArray(gameboy.memory)),
    170     sumMBCRam: sum(gameboy.fromTypedArray(gameboy.MBCRam)),
    171     sumVRam: sum(gameboy.fromTypedArray(gameboy.VRam))
    172   }
    173   var stateStr = JSON.stringify(state);
    174   if (typeof expectedGameboyStateStr != "undefined") {
    175     if (stateStr != expectedGameboyStateStr) {
    176       alert("Incorrect final state of processor:\n" +
    177             " actual   " + stateStr + "\n" +
    178             " expected " + expectedGameboyStateStr);
    179     }
    180   } else {
    181     alert(stateStr);
    182   }
    183 }
    184 
    185 
    186 function resetGlobalVariables () {
    187   //Audio API Event Handler:
    188   audioContextHandle = null;
    189   audioNode = null;
    190   audioSource = null;
    191   launchedContext = false;
    192   audioContextSampleBuffer = [];
    193   resampled = [];
    194   webAudioMinBufferSize = 15000;
    195   webAudioMaxBufferSize = 25000;
    196   webAudioActualSampleRate = 44100;
    197   XAudioJSSampleRate = 0;
    198   webAudioMono = false;
    199   XAudioJSVolume = 1;
    200   resampleControl = null;
    201   audioBufferSize = 0;
    202   resampleBufferStart = 0;
    203   resampleBufferEnd = 0;
    204   resampleBufferSize = 2;
    205 
    206   gameboy = null;           //GameBoyCore object.
    207   gbRunInterval = null;       //GameBoyCore Timer
    208 }
    209 
    210 
    211 // End of helper functions.
    212 
    213 // Original code from Grant Galitz follows.
    214 // Modifications by Google are marked in comments.
    215 
    216 // Start of js/other/base64.js file.
    217 
    218 var toBase64 = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
    219   "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
    220   "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+" , "/", "="];
    221 var fromBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    222 function base64(data) {
    223   try {
    224     // The following line was modified for benchmarking:
    225     var base64 = GameBoyWindow.btoa(data);  //Use this native function when it's available, as it's a magnitude faster than the non-native code below.
    226   }
    227   catch (error) {
    228     //Defaulting to non-native base64 encoding...
    229     var base64 = "";
    230     var dataLength = data.length;
    231     if (dataLength > 0) {
    232       var bytes = [0, 0, 0];
    233       var index = 0;
    234       var remainder = dataLength % 3;
    235       while (data.length % 3 > 0) {
    236         //Make sure we don't do fuzzy math in the next loop...
    237         data[data.length] = " ";
    238       }
    239       while (index < dataLength) {
    240         //Keep this loop small for speed.
    241         bytes = [data.charCodeAt(index++) & 0xFF, data.charCodeAt(index++) & 0xFF, data.charCodeAt(index++) & 0xFF];
    242         base64 += toBase64[bytes[0] >> 2] + toBase64[((bytes[0] & 0x3) << 4) | (bytes[1] >> 4)] + toBase64[((bytes[1] & 0xF) << 2) | (bytes[2] >> 6)] + toBase64[bytes[2] & 0x3F];
    243       }
    244       if (remainder > 0) {
    245         //Fill in the padding and recalulate the trailing six-bit group...
    246         base64[base64.length - 1] = "=";
    247         if (remainder == 2) {
    248           base64[base64.length - 2] = "=";
    249           base64[base64.length - 3] = toBase64[(bytes[0] & 0x3) << 4];
    250         }
    251         else {
    252           base64[base64.length - 2] = toBase64[(bytes[1] & 0xF) << 2];
    253         }
    254       }
    255     }
    256   }
    257   return base64;
    258 }
    259 function base64_decode(data) {
    260   try {
    261     // The following line was modified for benchmarking:
    262     var decode64 = GameBoyWindow.atob(data);  //Use this native function when it's available, as it's a magnitude faster than the non-native code below.
    263   }
    264   catch (error) {
    265     //Defaulting to non-native base64 decoding...
    266     var decode64 = "";
    267     var dataLength = data.length;
    268     if (dataLength > 3 && dataLength % 4 == 0) {
    269       var sixbits = [0, 0, 0, 0];  //Declare this out of the loop, to speed up the ops.
    270       var index = 0;
    271       while (index < dataLength) {
    272         //Keep this loop small for speed.
    273         sixbits = [fromBase64.indexOf(data.charAt(index++)), fromBase64.indexOf(data.charAt(index++)), fromBase64.indexOf(data.charAt(index++)), fromBase64.indexOf(data.charAt(index++))];
    274         decode64 += String.fromCharCode((sixbits[0] << 2) | (sixbits[1] >> 4)) + String.fromCharCode(((sixbits[1] & 0x0F) << 4) | (sixbits[2] >> 2)) + String.fromCharCode(((sixbits[2] & 0x03) << 6) | sixbits[3]);
    275       }
    276       //Check for the '=' character after the loop, so we don't hose it up.
    277       if (sixbits[3] >= 0x40) {
    278         decode64.length -= 1;
    279         if (sixbits[2] >= 0x40) {
    280           decode64.length -= 1;
    281         }
    282       }
    283     }
    284   }
    285   return decode64;
    286 }
    287 function to_little_endian_dword(str) {
    288   return to_little_endian_word(str) + String.fromCharCode((str >> 16) & 0xFF, (str >> 24) & 0xFF);
    289 }
    290 function to_little_endian_word(str) {
    291   return to_byte(str) + String.fromCharCode((str >> 8) & 0xFF);
    292 }
    293 function to_byte(str) {
    294   return String.fromCharCode(str & 0xFF);
    295 }
    296 function arrayToBase64(arrayIn) {
    297   var binString = "";
    298   var length = arrayIn.length;
    299   for (var index = 0; index < length; ++index) {
    300     if (typeof arrayIn[index] == "number") {
    301       binString += String.fromCharCode(arrayIn[index]);
    302     }
    303   }
    304   return base64(binString);
    305 }
    306 function base64ToArray(b64String) {
    307   var binString = base64_decode(b64String);
    308   var outArray = [];
    309   var length = binString.length;
    310   for (var index = 0; index < length;) {
    311     outArray.push(binString.charCodeAt(index++) & 0xFF);
    312   }
    313   return outArray;
    314 }
    315 
    316 // End of js/other/base64.js file.
    317 
    318 // Start of js/other/resampler.js file.
    319 
    320 //JavaScript Audio Resampler (c) 2011 - Grant Galitz
    321 function Resampler(fromSampleRate, toSampleRate, channels, outputBufferSize, noReturn) {
    322   this.fromSampleRate = fromSampleRate;
    323   this.toSampleRate = toSampleRate;
    324   this.channels = channels | 0;
    325   this.outputBufferSize = outputBufferSize;
    326   this.noReturn = !!noReturn;
    327   this.initialize();
    328 }
    329 Resampler.prototype.initialize = function () {
    330   //Perform some checks:
    331   if (this.fromSampleRate > 0 && this.toSampleRate > 0 && this.channels > 0) {
    332     if (this.fromSampleRate == this.toSampleRate) {
    333       //Setup a resampler bypass:
    334       this.resampler = this.bypassResampler;    //Resampler just returns what was passed through.
    335       this.ratioWeight = 1;
    336     }
    337     else {
    338       //Setup the interpolation resampler:
    339       this.compileInterpolationFunction();
    340       this.resampler = this.interpolate;      //Resampler is a custom quality interpolation algorithm.
    341       this.ratioWeight = this.fromSampleRate / this.toSampleRate;
    342       this.tailExists = false;
    343       this.lastWeight = 0;
    344       this.initializeBuffers();
    345     }
    346   }
    347   else {
    348     throw(new Error("Invalid settings specified for the resampler."));
    349   }
    350 }
    351 Resampler.prototype.compileInterpolationFunction = function () {
    352   var toCompile = "var bufferLength = Math.min(buffer.length, this.outputBufferSize);\
    353   if ((bufferLength % " + this.channels + ") == 0) {\
    354     if (bufferLength > 0) {\
    355       var ratioWeight = this.ratioWeight;\
    356       var weight = 0;";
    357   for (var channel = 0; channel < this.channels; ++channel) {
    358     toCompile += "var output" + channel + " = 0;"
    359   }
    360   toCompile += "var actualPosition = 0;\
    361       var amountToNext = 0;\
    362       var alreadyProcessedTail = !this.tailExists;\
    363       this.tailExists = false;\
    364       var outputBuffer = this.outputBuffer;\
    365       var outputOffset = 0;\
    366       var currentPosition = 0;\
    367       do {\
    368         if (alreadyProcessedTail) {\
    369           weight = ratioWeight;";
    370   for (channel = 0; channel < this.channels; ++channel) {
    371     toCompile += "output" + channel + " = 0;"
    372   }
    373   toCompile += "}\
    374         else {\
    375           weight = this.lastWeight;";
    376   for (channel = 0; channel < this.channels; ++channel) {
    377     toCompile += "output" + channel + " = this.lastOutput[" + channel + "];"
    378   }
    379   toCompile += "alreadyProcessedTail = true;\
    380         }\
    381         while (weight > 0 && actualPosition < bufferLength) {\
    382           amountToNext = 1 + actualPosition - currentPosition;\
    383           if (weight >= amountToNext) {";
    384   for (channel = 0; channel < this.channels; ++channel) {
    385     toCompile += "output" + channel + " += buffer[actualPosition++] * amountToNext;"
    386   }
    387   toCompile += "currentPosition = actualPosition;\
    388             weight -= amountToNext;\
    389           }\
    390           else {";
    391   for (channel = 0; channel < this.channels; ++channel) {
    392     toCompile += "output" + channel + " += buffer[actualPosition" + ((channel > 0) ? (" + " + channel) : "") + "] * weight;"
    393   }
    394   toCompile += "currentPosition += weight;\
    395             weight = 0;\
    396             break;\
    397           }\
    398         }\
    399         if (weight == 0) {";
    400   for (channel = 0; channel < this.channels; ++channel) {
    401     toCompile += "outputBuffer[outputOffset++] = output" + channel + " / ratioWeight;"
    402   }
    403   toCompile += "}\
    404         else {\
    405           this.lastWeight = weight;";
    406   for (channel = 0; channel < this.channels; ++channel) {
    407     toCompile += "this.lastOutput[" + channel + "] = output" + channel + ";"
    408   }
    409   toCompile += "this.tailExists = true;\
    410           break;\
    411         }\
    412       } while (actualPosition < bufferLength);\
    413       return this.bufferSlice(outputOffset);\
    414     }\
    415     else {\
    416       return (this.noReturn) ? 0 : [];\
    417     }\
    418   }\
    419   else {\
    420     throw(new Error(\"Buffer was of incorrect sample length.\"));\
    421   }";
    422   this.interpolate = Function("buffer", toCompile);
    423 }
    424 Resampler.prototype.bypassResampler = function (buffer) {
    425   if (this.noReturn) {
    426     //Set the buffer passed as our own, as we don't need to resample it:
    427     this.outputBuffer = buffer;
    428     return buffer.length;
    429   }
    430   else {
    431     //Just return the buffer passsed:
    432     return buffer;
    433   }
    434 }
    435 Resampler.prototype.bufferSlice = function (sliceAmount) {
    436   if (this.noReturn) {
    437     //If we're going to access the properties directly from this object:
    438     return sliceAmount;
    439   }
    440   else {
    441     //Typed array and normal array buffer section referencing:
    442     try {
    443       return this.outputBuffer.subarray(0, sliceAmount);
    444     }
    445     catch (error) {
    446       try {
    447         //Regular array pass:
    448         this.outputBuffer.length = sliceAmount;
    449         return this.outputBuffer;
    450       }
    451       catch (error) {
    452         //Nightly Firefox 4 used to have the subarray function named as slice:
    453         return this.outputBuffer.slice(0, sliceAmount);
    454       }
    455     }
    456   }
    457 }
    458 Resampler.prototype.initializeBuffers = function () {
    459   //Initialize the internal buffer:
    460   try {
    461     this.outputBuffer = new Float32Array(this.outputBufferSize);
    462     this.lastOutput = new Float32Array(this.channels);
    463   }
    464   catch (error) {
    465     this.outputBuffer = [];
    466     this.lastOutput = [];
    467   }
    468 }
    469 
    470 // End of js/other/resampler.js file.
    471 
    472 // Start of js/other/XAudioServer.js file.
    473 
    474 /*Initialize here first:
    475   Example:
    476     Stereo audio with a sample rate of 70 khz, a minimum buffer of 15000 samples total, a maximum buffer of 25000 samples total and a starting volume level of 1.
    477       var parentObj = this;
    478       this.audioHandle = new XAudioServer(2, 70000, 15000, 25000, function (sampleCount) {
    479         return parentObj.audioUnderRun(sampleCount);
    480       }, 1);
    481 
    482   The callback is passed the number of samples requested, while it can return any number of samples it wants back.
    483 */
    484 function XAudioServer(channels, sampleRate, minBufferSize, maxBufferSize, underRunCallback, volume) {
    485   this.audioChannels = (channels == 2) ? 2 : 1;
    486   webAudioMono = (this.audioChannels == 1);
    487   XAudioJSSampleRate = (sampleRate > 0 && sampleRate <= 0xFFFFFF) ? sampleRate : 44100;
    488   webAudioMinBufferSize = (minBufferSize >= (samplesPerCallback << 1) && minBufferSize < maxBufferSize) ? (minBufferSize & ((webAudioMono) ? 0xFFFFFFFF : 0xFFFFFFFE)) : (samplesPerCallback << 1);
    489   webAudioMaxBufferSize = (Math.floor(maxBufferSize) > webAudioMinBufferSize + this.audioChannels) ? (maxBufferSize & ((webAudioMono) ? 0xFFFFFFFF : 0xFFFFFFFE)) : (minBufferSize << 1);
    490   this.underRunCallback = (typeof underRunCallback == "function") ? underRunCallback : function () {};
    491   XAudioJSVolume = (volume >= 0 && volume <= 1) ? volume : 1;
    492   this.audioType = -1;
    493   this.mozAudioTail = [];
    494   this.audioHandleMoz = null;
    495   this.audioHandleFlash = null;
    496   this.flashInitialized = false;
    497   this.mozAudioFound = false;
    498   this.initializeAudio();
    499 }
    500 XAudioServer.prototype.MOZWriteAudio = function (buffer) {
    501   //mozAudio:
    502   this.MOZWriteAudioNoCallback(buffer);
    503   this.MOZExecuteCallback();
    504 }
    505 XAudioServer.prototype.MOZWriteAudioNoCallback = function (buffer) {
    506   //mozAudio:
    507   this.writeMozAudio(buffer);
    508 }
    509 XAudioServer.prototype.callbackBasedWriteAudio = function (buffer) {
    510   //Callback-centered audio APIs:
    511   this.callbackBasedWriteAudioNoCallback(buffer);
    512   this.callbackBasedExecuteCallback();
    513 }
    514 XAudioServer.prototype.callbackBasedWriteAudioNoCallback = function (buffer) {
    515   //Callback-centered audio APIs:
    516   var length = buffer.length;
    517   for (var bufferCounter = 0; bufferCounter < length && audioBufferSize < webAudioMaxBufferSize;) {
    518     audioContextSampleBuffer[audioBufferSize++] = buffer[bufferCounter++];
    519   }
    520 }
    521 /*Pass your samples into here!
    522 Pack your samples as a one-dimenional array
    523 With the channel samplea packed uniformly.
    524 examples:
    525     mono - [left, left, left, left]
    526     stereo - [left, right, left, right, left, right, left, right]
    527 */
    528 XAudioServer.prototype.writeAudio = function (buffer) {
    529   if (this.audioType == 0) {
    530     this.MOZWriteAudio(buffer);
    531   }
    532   else if (this.audioType == 1) {
    533     this.callbackBasedWriteAudio(buffer);
    534   }
    535   else if (this.audioType == 2) {
    536     if (this.checkFlashInit() || launchedContext) {
    537       this.callbackBasedWriteAudio(buffer);
    538     }
    539     else if (this.mozAudioFound) {
    540       this.MOZWriteAudio(buffer);
    541     }
    542   }
    543 }
    544 /*Pass your samples into here if you don't want automatic callback calling:
    545 Pack your samples as a one-dimenional array
    546 With the channel samplea packed uniformly.
    547 examples:
    548     mono - [left, left, left, left]
    549     stereo - [left, right, left, right, left, right, left, right]
    550 Useful in preventing infinite recursion issues with calling writeAudio inside your callback.
    551 */
    552 XAudioServer.prototype.writeAudioNoCallback = function (buffer) {
    553   if (this.audioType == 0) {
    554     this.MOZWriteAudioNoCallback(buffer);
    555   }
    556   else if (this.audioType == 1) {
    557     this.callbackBasedWriteAudioNoCallback(buffer);
    558   }
    559   else if (this.audioType == 2) {
    560     if (this.checkFlashInit() || launchedContext) {
    561       this.callbackBasedWriteAudioNoCallback(buffer);
    562     }
    563     else if (this.mozAudioFound) {
    564       this.MOZWriteAudioNoCallback(buffer);
    565     }
    566   }
    567 }
    568 //Developer can use this to see how many samples to write (example: minimum buffer allotment minus remaining samples left returned from this function to make sure maximum buffering is done...)
    569 //If -1 is returned, then that means metric could not be done.
    570 XAudioServer.prototype.remainingBuffer = function () {
    571   if (this.audioType == 0) {
    572     //mozAudio:
    573     return this.samplesAlreadyWritten - this.audioHandleMoz.mozCurrentSampleOffset();
    574   }
    575   else if (this.audioType == 1) {
    576     //WebKit Audio:
    577     return (((resampledSamplesLeft() * resampleControl.ratioWeight) >> (this.audioChannels - 1)) << (this.audioChannels - 1)) + audioBufferSize;
    578   }
    579   else if (this.audioType == 2) {
    580     if (this.checkFlashInit() || launchedContext) {
    581       //Webkit Audio / Flash Plugin Audio:
    582       return (((resampledSamplesLeft() * resampleControl.ratioWeight) >> (this.audioChannels - 1)) << (this.audioChannels - 1)) + audioBufferSize;
    583     }
    584     else if (this.mozAudioFound) {
    585       //mozAudio:
    586       return this.samplesAlreadyWritten - this.audioHandleMoz.mozCurrentSampleOffset();
    587     }
    588   }
    589   //Default return:
    590   return 0;
    591 }
    592 XAudioServer.prototype.MOZExecuteCallback = function () {
    593   //mozAudio:
    594   var samplesRequested = webAudioMinBufferSize - this.remainingBuffer();
    595   if (samplesRequested > 0) {
    596     this.writeMozAudio(this.underRunCallback(samplesRequested));
    597   }
    598 }
    599 XAudioServer.prototype.callbackBasedExecuteCallback = function () {
    600   //WebKit /Flash Audio:
    601   var samplesRequested = webAudioMinBufferSize - this.remainingBuffer();
    602   if (samplesRequested > 0) {
    603     this.callbackBasedWriteAudioNoCallback(this.underRunCallback(samplesRequested));
    604   }
    605 }
    606 //If you just want your callback called for any possible refill (Execution of callback is still conditional):
    607 XAudioServer.prototype.executeCallback = function () {
    608   if (this.audioType == 0) {
    609     this.MOZExecuteCallback();
    610   }
    611   else if (this.audioType == 1) {
    612     this.callbackBasedExecuteCallback();
    613   }
    614   else if (this.audioType == 2) {
    615     if (this.checkFlashInit() || launchedContext) {
    616       this.callbackBasedExecuteCallback();
    617     }
    618     else if (this.mozAudioFound) {
    619       this.MOZExecuteCallback();
    620     }
    621   }
    622 }
    623 //DO NOT CALL THIS, the lib calls this internally!
    624 XAudioServer.prototype.initializeAudio = function () {
    625   try {
    626     throw (new Error("Select initializeWebAudio case"));  // Line added for benchmarking.
    627     this.preInitializeMozAudio();
    628     if (navigator.platform == "Linux i686") {
    629       //Block out mozaudio usage for Linux Firefox due to moz bugs:
    630       throw(new Error(""));
    631     }
    632     this.initializeMozAudio();
    633   }
    634   catch (error) {
    635     try {
    636       this.initializeWebAudio();
    637     }
    638     catch (error) {
    639       try {
    640         this.initializeFlashAudio();
    641       }
    642       catch (error) {
    643         throw(new Error("Browser does not support real time audio output."));
    644       }
    645     }
    646   }
    647 }
    648 XAudioServer.prototype.preInitializeMozAudio = function () {
    649   //mozAudio - Synchronous Audio API
    650   this.audioHandleMoz = new Audio();
    651   this.audioHandleMoz.mozSetup(this.audioChannels, XAudioJSSampleRate);
    652   this.samplesAlreadyWritten = 0;
    653   var emptySampleFrame = (this.audioChannels == 2) ? [0, 0] : [0];
    654   var prebufferAmount = 0;
    655   if (navigator.platform != "MacIntel" && navigator.platform != "MacPPC") {  //Mac OS X doesn't experience this moz-bug!
    656     while (this.audioHandleMoz.mozCurrentSampleOffset() == 0) {
    657       //Mozilla Audio Bugginess Workaround (Firefox freaks out if we don't give it a prebuffer under certain OSes):
    658       prebufferAmount += this.audioHandleMoz.mozWriteAudio(emptySampleFrame);
    659     }
    660     var samplesToDoubleBuffer = prebufferAmount / this.audioChannels;
    661     //Double the prebuffering for windows:
    662     for (var index = 0; index < samplesToDoubleBuffer; index++) {
    663       this.samplesAlreadyWritten += this.audioHandleMoz.mozWriteAudio(emptySampleFrame);
    664     }
    665   }
    666   this.samplesAlreadyWritten += prebufferAmount;
    667   webAudioMinBufferSize += this.samplesAlreadyWritten;
    668   this.mozAudioFound = true;
    669 }
    670 XAudioServer.prototype.initializeMozAudio = function () {
    671   //Fill in our own buffering up to the minimum specified:
    672   this.writeMozAudio(getFloat32(webAudioMinBufferSize));
    673   this.audioType = 0;
    674 }
    675 XAudioServer.prototype.initializeWebAudio = function () {
    676   if (launchedContext) {
    677     resetCallbackAPIAudioBuffer(webAudioActualSampleRate, samplesPerCallback);
    678     this.audioType = 1;
    679   }
    680   else {
    681     throw(new Error(""));
    682   }
    683 }
    684 XAudioServer.prototype.initializeFlashAudio = function () {
    685   var existingFlashload = document.getElementById("XAudioJS");
    686   if (existingFlashload == null) {
    687     var thisObj = this;
    688     var mainContainerNode = document.createElement("div");
    689     mainContainerNode.setAttribute("style", "position: fixed; bottom: 0px; right: 0px; margin: 0px; padding: 0px; border: none; width: 8px; height: 8px; overflow: hidden; z-index: -1000; ");
    690     var containerNode = document.createElement("div");
    691     containerNode.setAttribute("style", "position: static; border: none; width: 0px; height: 0px; visibility: hidden; margin: 8px; padding: 0px;");
    692     containerNode.setAttribute("id", "XAudioJS");
    693     mainContainerNode.appendChild(containerNode);
    694     document.getElementsByTagName("body")[0].appendChild(mainContainerNode);
    695     swfobject.embedSWF(
    696       "XAudioJS.swf",
    697       "XAudioJS",
    698       "8",
    699       "8",
    700       "9.0.0",
    701       "",
    702       {},
    703       {"allowscriptaccess":"always"},
    704       {"style":"position: static; visibility: hidden; margin: 8px; padding: 0px; border: none"},
    705       function (event) {
    706         if (event.success) {
    707           thisObj.audioHandleFlash = event.ref;
    708         }
    709         else {
    710           thisObj.audioType = 1;
    711         }
    712       }
    713     );
    714   }
    715   else {
    716     this.audioHandleFlash = existingFlashload;
    717   }
    718   this.audioType = 2;
    719 }
    720 XAudioServer.prototype.changeVolume = function (newVolume) {
    721   if (newVolume >= 0 && newVolume <= 1) {
    722     XAudioJSVolume = newVolume;
    723     if (this.checkFlashInit()) {
    724       this.audioHandleFlash.changeVolume(XAudioJSVolume);
    725     }
    726     if (this.mozAudioFound) {
    727       this.audioHandleMoz.volume = XAudioJSVolume;
    728     }
    729   }
    730 }
    731 //Moz Audio Buffer Writing Handler:
    732 XAudioServer.prototype.writeMozAudio = function (buffer) {
    733   var length = this.mozAudioTail.length;
    734   if (length > 0) {
    735     var samplesAccepted = this.audioHandleMoz.mozWriteAudio(this.mozAudioTail);
    736     this.samplesAlreadyWritten += samplesAccepted;
    737     this.mozAudioTail.splice(0, samplesAccepted);
    738   }
    739   length = Math.min(buffer.length, webAudioMaxBufferSize - this.samplesAlreadyWritten + this.audioHandleMoz.mozCurrentSampleOffset());
    740   var samplesAccepted = this.audioHandleMoz.mozWriteAudio(buffer);
    741   this.samplesAlreadyWritten += samplesAccepted;
    742   for (var index = 0; length > samplesAccepted; --length) {
    743     //Moz Audio wants us saving the tail:
    744     this.mozAudioTail.push(buffer[index++]);
    745   }
    746 }
    747 //Checks to see if the NPAPI Adobe Flash bridge is ready yet:
    748 XAudioServer.prototype.checkFlashInit = function () {
    749   if (!this.flashInitialized && this.audioHandleFlash && this.audioHandleFlash.initialize) {
    750     this.flashInitialized = true;
    751     this.audioHandleFlash.initialize(this.audioChannels, XAudioJSVolume);
    752     resetCallbackAPIAudioBuffer(44100, samplesPerCallback);
    753   }
    754   return this.flashInitialized;
    755 }
    756 /////////END LIB
    757 function getFloat32(size) {
    758   try {
    759     return new Float32Array(size);
    760   }
    761   catch (error) {
    762     return new Array(size);
    763   }
    764 }
    765 function getFloat32Flat(size) {
    766   try {
    767     var newBuffer = new Float32Array(size);
    768   }
    769   catch (error) {
    770     var newBuffer = new Array(size);
    771     var audioSampleIndice = 0;
    772     do {
    773       newBuffer[audioSampleIndice] = 0;
    774     } while (++audioSampleIndice < size);
    775   }
    776   return newBuffer;
    777 }
    778 //Flash NPAPI Event Handler:
    779 var samplesPerCallback = 2048;      //Has to be between 2048 and 4096 (If over, then samples are ignored, if under then silence is added).
    780 var outputConvert = null;
    781 function audioOutputFlashEvent() {    //The callback that flash calls...
    782   resampleRefill();
    783   return outputConvert();
    784 }
    785 function generateFlashStereoString() {  //Convert the arrays to one long string for speed.
    786   var copyBinaryStringLeft = "";
    787   var copyBinaryStringRight = "";
    788   for (var index = 0; index < samplesPerCallback && resampleBufferStart != resampleBufferEnd; ++index) {
    789     //Sanitize the buffer:
    790     copyBinaryStringLeft += String.fromCharCode(((Math.min(Math.max(resampled[resampleBufferStart++] + 1, 0), 2) * 0x3FFF) | 0) + 0x3000);
    791     copyBinaryStringRight += String.fromCharCode(((Math.min(Math.max(resampled[resampleBufferStart++] + 1, 0), 2) * 0x3FFF) | 0) + 0x3000);
    792     if (resampleBufferStart == resampleBufferSize) {
    793       resampleBufferStart = 0;
    794     }
    795   }
    796   return copyBinaryStringLeft + copyBinaryStringRight;
    797 }
    798 function generateFlashMonoString() {  //Convert the array to one long string for speed.
    799   var copyBinaryString = "";
    800   for (var index = 0; index < samplesPerCallback && resampleBufferStart != resampleBufferEnd; ++index) {
    801     //Sanitize the buffer:
    802     copyBinaryString += String.fromCharCode(((Math.min(Math.max(resampled[resampleBufferStart++] + 1, 0), 2) * 0x3FFF) | 0) + 0x3000);
    803     if (resampleBufferStart == resampleBufferSize) {
    804       resampleBufferStart = 0;
    805     }
    806   }
    807   return copyBinaryString;
    808 }
    809 //Audio API Event Handler:
    810 var audioContextHandle = null;
    811 var audioNode = null;
    812 var audioSource = null;
    813 var launchedContext = false;
    814 var audioContextSampleBuffer = [];
    815 var resampled = [];
    816 var webAudioMinBufferSize = 15000;
    817 var webAudioMaxBufferSize = 25000;
    818 var webAudioActualSampleRate = 44100;
    819 var XAudioJSSampleRate = 0;
    820 var webAudioMono = false;
    821 var XAudioJSVolume = 1;
    822 var resampleControl = null;
    823 var audioBufferSize = 0;
    824 var resampleBufferStart = 0;
    825 var resampleBufferEnd = 0;
    826 var resampleBufferSize = 2;
    827 function audioOutputEvent(event) {    //Web Audio API callback...
    828   var index = 0;
    829   var buffer1 = event.outputBuffer.getChannelData(0);
    830   var buffer2 = event.outputBuffer.getChannelData(1);
    831   resampleRefill();
    832   if (!webAudioMono) {
    833     //STEREO:
    834     while (index < samplesPerCallback && resampleBufferStart != resampleBufferEnd) {
    835       buffer1[index] = resampled[resampleBufferStart++] * XAudioJSVolume;
    836       buffer2[index++] = resampled[resampleBufferStart++] * XAudioJSVolume;
    837       if (resampleBufferStart == resampleBufferSize) {
    838         resampleBufferStart = 0;
    839       }
    840     }
    841   }
    842   else {
    843     //MONO:
    844     while (index < samplesPerCallback && resampleBufferStart != resampleBufferEnd) {
    845       buffer2[index] = buffer1[index] = resampled[resampleBufferStart++] * XAudioJSVolume;
    846       ++index;
    847       if (resampleBufferStart == resampleBufferSize) {
    848         resampleBufferStart = 0;
    849       }
    850     }
    851   }
    852   //Pad with silence if we're underrunning:
    853   while (index < samplesPerCallback) {
    854     buffer2[index] = buffer1[index] = 0;
    855     ++index;
    856   }
    857 }
    858 function resampleRefill() {
    859   if (audioBufferSize > 0) {
    860     //Resample a chunk of audio:
    861     var resampleLength = resampleControl.resampler(getBufferSamples());
    862     var resampledResult = resampleControl.outputBuffer;
    863     for (var index2 = 0; index2 < resampleLength; ++index2) {
    864       resampled[resampleBufferEnd++] = resampledResult[index2];
    865       if (resampleBufferEnd == resampleBufferSize) {
    866         resampleBufferEnd = 0;
    867       }
    868       if (resampleBufferStart == resampleBufferEnd) {
    869         ++resampleBufferStart;
    870         if (resampleBufferStart == resampleBufferSize) {
    871           resampleBufferStart = 0;
    872         }
    873       }
    874     }
    875     audioBufferSize = 0;
    876   }
    877 }
    878 function resampledSamplesLeft() {
    879   return ((resampleBufferStart <= resampleBufferEnd) ? 0 : resampleBufferSize) + resampleBufferEnd - resampleBufferStart;
    880 }
    881 function getBufferSamples() {
    882   //Typed array and normal array buffer section referencing:
    883   try {
    884     return audioContextSampleBuffer.subarray(0, audioBufferSize);
    885   }
    886   catch (error) {
    887     try {
    888       //Regular array pass:
    889       audioContextSampleBuffer.length = audioBufferSize;
    890       return audioContextSampleBuffer;
    891     }
    892     catch (error) {
    893       //Nightly Firefox 4 used to have the subarray function named as slice:
    894       return audioContextSampleBuffer.slice(0, audioBufferSize);
    895     }
    896   }
    897 }
    898 //Initialize WebKit Audio /Flash Audio Buffer:
    899 function resetCallbackAPIAudioBuffer(APISampleRate, bufferAlloc) {
    900   audioContextSampleBuffer = getFloat32(webAudioMaxBufferSize);
    901   audioBufferSize = webAudioMaxBufferSize;
    902   resampleBufferStart = 0;
    903   resampleBufferEnd = 0;
    904   resampleBufferSize = Math.max(webAudioMaxBufferSize * Math.ceil(XAudioJSSampleRate / APISampleRate), samplesPerCallback) << 1;
    905   if (webAudioMono) {
    906     //MONO Handling:
    907     resampled = getFloat32Flat(resampleBufferSize);
    908     resampleControl = new Resampler(XAudioJSSampleRate, APISampleRate, 1, resampleBufferSize, true);
    909     outputConvert = generateFlashMonoString;
    910   }
    911   else {
    912     //STEREO Handling:
    913     resampleBufferSize  <<= 1;
    914     resampled = getFloat32Flat(resampleBufferSize);
    915     resampleControl = new Resampler(XAudioJSSampleRate, APISampleRate, 2, resampleBufferSize, true);
    916     outputConvert = generateFlashStereoString;
    917   }
    918 }
    919 //Initialize WebKit Audio:
    920 (function () {
    921   if (!launchedContext) {
    922     try {
    923       // The following line was modified for benchmarking:
    924       audioContextHandle = new GameBoyAudioContext();              //Create a system audio context.
    925     }
    926     catch (error) {
    927       try {
    928         audioContextHandle = new AudioContext();                //Create a system audio context.
    929       }
    930       catch (error) {
    931         return;
    932       }
    933     }
    934     try {
    935       audioSource = audioContextHandle.createBufferSource();            //We need to create a false input to get the chain started.
    936       audioSource.loop = false;  //Keep this alive forever (Event handler will know when to ouput.)
    937       XAudioJSSampleRate = webAudioActualSampleRate = audioContextHandle.sampleRate;
    938       audioSource.buffer = audioContextHandle.createBuffer(1, 1, webAudioActualSampleRate);  //Create a zero'd input buffer for the input to be valid.
    939       audioNode = audioContextHandle.createJavaScriptNode(samplesPerCallback, 1, 2);      //Create 2 outputs and ignore the input buffer (Just copy buffer 1 over if mono)
    940       audioNode.onaudioprocess = audioOutputEvent;                //Connect the audio processing event to a handling function so we can manipulate output
    941       audioSource.connect(audioNode);                        //Send and chain the input to the audio manipulation.
    942       audioNode.connect(audioContextHandle.destination);              //Send and chain the output of the audio manipulation to the system audio output.
    943       audioSource.noteOn(0);                            //Start the loop!
    944     }
    945     catch (error) {
    946       return;
    947     }
    948     launchedContext = true;
    949   }
    950 })();
    951 
    952 // End of js/other/XAudioServer.js file.
    953 
    954 // Start of js/other/resize.js file.
    955 
    956 //JavaScript Image Resizer (c) 2012 - Grant Galitz
    957 function Resize(widthOriginal, heightOriginal, targetWidth, targetHeight, blendAlpha, interpolationPass) {
    958   this.widthOriginal = Math.abs(parseInt(widthOriginal) || 0);
    959   this.heightOriginal = Math.abs(parseInt(heightOriginal) || 0);
    960   this.targetWidth = Math.abs(parseInt(targetWidth) || 0);
    961   this.targetHeight = Math.abs(parseInt(targetHeight) || 0);
    962   this.colorChannels = (!!blendAlpha) ? 4 : 3;
    963   this.interpolationPass = !!interpolationPass;
    964   this.targetWidthMultipliedByChannels = this.targetWidth * this.colorChannels;
    965   this.originalWidthMultipliedByChannels = this.widthOriginal * this.colorChannels;
    966   this.originalHeightMultipliedByChannels = this.heightOriginal * this.colorChannels;
    967   this.widthPassResultSize = this.targetWidthMultipliedByChannels * this.heightOriginal;
    968   this.finalResultSize = this.targetWidthMultipliedByChannels * this.targetHeight;
    969   this.initialize();
    970 }
    971 Resize.prototype.initialize = function () {
    972   //Perform some checks:
    973   if (this.widthOriginal > 0 && this.heightOriginal > 0 && this.targetWidth > 0 && this.targetHeight > 0) {
    974     if (this.widthOriginal == this.targetWidth) {
    975       //Bypass the width resizer pass:
    976       this.resizeWidth = this.bypassResizer;
    977     }
    978     else {
    979       //Setup the width resizer pass:
    980       this.ratioWeightWidthPass = this.widthOriginal / this.targetWidth;
    981       if (this.ratioWeightWidthPass < 1 && this.interpolationPass) {
    982         this.initializeFirstPassBuffers(true);
    983         this.resizeWidth = (this.colorChannels == 4) ? this.resizeWidthInterpolatedRGBA : this.resizeWidthInterpolatedRGB;
    984       }
    985       else {
    986         this.initializeFirstPassBuffers(false);
    987         this.resizeWidth = (this.colorChannels == 4) ? this.resizeWidthRGBA : this.resizeWidthRGB;
    988       }
    989     }
    990     if (this.heightOriginal == this.targetHeight) {
    991       //Bypass the height resizer pass:
    992       this.resizeHeight = this.bypassResizer;
    993     }
    994     else {
    995       //Setup the height resizer pass:
    996       this.ratioWeightHeightPass = this.heightOriginal / this.targetHeight;
    997       if (this.ratioWeightHeightPass < 1 && this.interpolationPass) {
    998         this.initializeSecondPassBuffers(true);
    999         this.resizeHeight = this.resizeHeightInterpolated;
   1000       }
   1001       else {
   1002         this.initializeSecondPassBuffers(false);
   1003         this.resizeHeight = (this.colorChannels == 4) ? this.resizeHeightRGBA : this.resizeHeightRGB;
   1004       }
   1005     }
   1006   }
   1007   else {
   1008     throw(new Error("Invalid settings specified for the resizer."));
   1009   }
   1010 }
   1011 Resize.prototype.resizeWidthRGB = function (buffer) {
   1012   var ratioWeight = this.ratioWeightWidthPass;
   1013   var weight = 0;
   1014   var amountToNext = 0;
   1015   var actualPosition = 0;
   1016   var currentPosition = 0;
   1017   var line = 0;
   1018   var pixelOffset = 0;
   1019   var outputOffset = 0;
   1020   var nextLineOffsetOriginalWidth = this.originalWidthMultipliedByChannels - 2;
   1021   var nextLineOffsetTargetWidth = this.targetWidthMultipliedByChannels - 2;
   1022   var output = this.outputWidthWorkBench;
   1023   var outputBuffer = this.widthBuffer;
   1024   do {
   1025     for (line = 0; line < this.originalHeightMultipliedByChannels;) {
   1026       output[line++] = 0;
   1027       output[line++] = 0;
   1028       output[line++] = 0;
   1029     }
   1030     weight = ratioWeight;
   1031     do {
   1032       amountToNext = 1 + actualPosition - currentPosition;
   1033       if (weight >= amountToNext) {
   1034         for (line = 0, pixelOffset = actualPosition; line < this.originalHeightMultipliedByChannels; pixelOffset += nextLineOffsetOriginalWidth) {
   1035           output[line++] += buffer[pixelOffset++] * amountToNext;
   1036           output[line++] += buffer[pixelOffset++] * amountToNext;
   1037           output[line++] += buffer[pixelOffset] * amountToNext;
   1038         }
   1039         currentPosition = actualPosition = actualPosition + 3;
   1040         weight -= amountToNext;
   1041       }
   1042       else {
   1043         for (line = 0, pixelOffset = actualPosition; line < this.originalHeightMultipliedByChannels; pixelOffset += nextLineOffsetOriginalWidth) {
   1044           output[line++] += buffer[pixelOffset++] * weight;
   1045           output[line++] += buffer[pixelOffset++] * weight;
   1046           output[line++] += buffer[pixelOffset] * weight;
   1047         }
   1048         currentPosition += weight;
   1049         break;
   1050       }
   1051     } while (weight > 0 && actualPosition < this.originalWidthMultipliedByChannels);
   1052     for (line = 0, pixelOffset = outputOffset; line < this.originalHeightMultipliedByChannels; pixelOffset += nextLineOffsetTargetWidth) {
   1053       outputBuffer[pixelOffset++] = output[line++] / ratioWeight;
   1054       outputBuffer[pixelOffset++] = output[line++] / ratioWeight;
   1055       outputBuffer[pixelOffset] = output[line++] / ratioWeight;
   1056     }
   1057     outputOffset += 3;
   1058   } while (outputOffset < this.targetWidthMultipliedByChannels);
   1059   return outputBuffer;
   1060 }
   1061 Resize.prototype.resizeWidthInterpolatedRGB = function (buffer) {
   1062   var ratioWeight = (this.widthOriginal - 1) / this.targetWidth;
   1063   var weight = 0;
   1064   var finalOffset = 0;
   1065   var pixelOffset = 0;
   1066   var outputBuffer = this.widthBuffer;
   1067   for (var targetPosition = 0; targetPosition < this.targetWidthMultipliedByChannels; targetPosition += 3, weight += ratioWeight) {
   1068     //Calculate weightings:
   1069     secondWeight = weight % 1;
   1070     firstWeight = 1 - secondWeight;
   1071     //Interpolate:
   1072     for (finalOffset = targetPosition, pixelOffset = Math.floor(weight) * 3; finalOffset < this.widthPassResultSize; pixelOffset += this.originalWidthMultipliedByChannels, finalOffset += this.targetWidthMultipliedByChannels) {
   1073       outputBuffer[finalOffset] = (buffer[pixelOffset] * firstWeight) + (buffer[pixelOffset + 3] * secondWeight);
   1074       outputBuffer[finalOffset + 1] = (buffer[pixelOffset + 1] * firstWeight) + (buffer[pixelOffset + 4] * secondWeight);
   1075       outputBuffer[finalOffset + 2] = (buffer[pixelOffset + 2] * firstWeight) + (buffer[pixelOffset + 5] * secondWeight);
   1076     }
   1077   }
   1078   return outputBuffer;
   1079 }
   1080 Resize.prototype.resizeWidthRGBA = function (buffer) {
   1081   var ratioWeight = this.ratioWeightWidthPass;
   1082   var weight = 0;
   1083   var amountToNext = 0;
   1084   var actualPosition = 0;
   1085   var currentPosition = 0;
   1086   var line = 0;
   1087   var pixelOffset = 0;
   1088   var outputOffset = 0;
   1089   var nextLineOffsetOriginalWidth = this.originalWidthMultipliedByChannels - 3;
   1090   var nextLineOffsetTargetWidth = this.targetWidthMultipliedByChannels - 3;
   1091   var output = this.outputWidthWorkBench;
   1092   var outputBuffer = this.widthBuffer;
   1093   do {
   1094     for (line = 0; line < this.originalHeightMultipliedByChannels;) {
   1095       output[line++] = 0;
   1096       output[line++] = 0;
   1097       output[line++] = 0;
   1098       output[line++] = 0;
   1099     }
   1100     weight = ratioWeight;
   1101     do {
   1102       amountToNext = 1 + actualPosition - currentPosition;
   1103       if (weight >= amountToNext) {
   1104         for (line = 0, pixelOffset = actualPosition; line < this.originalHeightMultipliedByChannels; pixelOffset += nextLineOffsetOriginalWidth) {
   1105           output[line++] += buffer[pixelOffset++] * amountToNext;
   1106           output[line++] += buffer[pixelOffset++] * amountToNext;
   1107           output[line++] += buffer[pixelOffset++] * amountToNext;
   1108           output[line++] += buffer[pixelOffset] * amountToNext;
   1109         }
   1110         currentPosition = actualPosition = actualPosition + 4;
   1111         weight -= amountToNext;
   1112       }
   1113       else {
   1114         for (line = 0, pixelOffset = actualPosition; line < this.originalHeightMultipliedByChannels; pixelOffset += nextLineOffsetOriginalWidth) {
   1115           output[line++] += buffer[pixelOffset++] * weight;
   1116           output[line++] += buffer[pixelOffset++] * weight;
   1117           output[line++] += buffer[pixelOffset++] * weight;
   1118           output[line++] += buffer[pixelOffset] * weight;
   1119         }
   1120         currentPosition += weight;
   1121         break;
   1122       }
   1123     } while (weight > 0 && actualPosition < this.originalWidthMultipliedByChannels);
   1124     for (line = 0, pixelOffset = outputOffset; line < this.originalHeightMultipliedByChannels; pixelOffset += nextLineOffsetTargetWidth) {
   1125       outputBuffer[pixelOffset++] = output[line++] / ratioWeight;
   1126       outputBuffer[pixelOffset++] = output[line++] / ratioWeight;
   1127       outputBuffer[pixelOffset++] = output[line++] / ratioWeight;
   1128       outputBuffer[pixelOffset] = output[line++] / ratioWeight;
   1129     }
   1130     outputOffset += 4;
   1131   } while (outputOffset < this.targetWidthMultipliedByChannels);
   1132   return outputBuffer;
   1133 }
   1134 Resize.prototype.resizeWidthInterpolatedRGBA = function (buffer) {
   1135   var ratioWeight = (this.widthOriginal - 1) / this.targetWidth;
   1136   var weight = 0;
   1137   var finalOffset = 0;
   1138   var pixelOffset = 0;
   1139   var outputBuffer = this.widthBuffer;
   1140   for (var targetPosition = 0; targetPosition < this.targetWidthMultipliedByChannels; targetPosition += 4, weight += ratioWeight) {
   1141     //Calculate weightings:
   1142     secondWeight = weight % 1;
   1143     firstWeight = 1 - secondWeight;
   1144     //Interpolate:
   1145     for (finalOffset = targetPosition, pixelOffset = Math.floor(weight) * 4; finalOffset < this.widthPassResultSize; pixelOffset += this.originalWidthMultipliedByChannels, finalOffset += this.targetWidthMultipliedByChannels) {
   1146       outputBuffer[finalOffset] = (buffer[pixelOffset] * firstWeight) + (buffer[pixelOffset + 4] * secondWeight);
   1147       outputBuffer[finalOffset + 1] = (buffer[pixelOffset + 1] * firstWeight) + (buffer[pixelOffset + 5] * secondWeight);
   1148       outputBuffer[finalOffset + 2] = (buffer[pixelOffset + 2] * firstWeight) + (buffer[pixelOffset + 6] * secondWeight);
   1149       outputBuffer[finalOffset + 3] = (buffer[pixelOffset + 3] * firstWeight) + (buffer[pixelOffset + 7] * secondWeight);
   1150     }
   1151   }
   1152   return outputBuffer;
   1153 }
   1154 Resize.prototype.resizeHeightRGB = function (buffer) {
   1155   var ratioWeight = this.ratioWeightHeightPass;
   1156   var weight = 0;
   1157   var amountToNext = 0;
   1158   var actualPosition = 0;
   1159   var currentPosition = 0;
   1160   var pixelOffset = 0;
   1161   var outputOffset = 0;
   1162   var output = this.outputHeightWorkBench;
   1163   var outputBuffer = this.heightBuffer;
   1164   do {
   1165     for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
   1166       output[pixelOffset++] = 0;
   1167       output[pixelOffset++] = 0;
   1168       output[pixelOffset++] = 0;
   1169     }
   1170     weight = ratioWeight;
   1171     do {
   1172       amountToNext = 1 + actualPosition - currentPosition;
   1173       if (weight >= amountToNext) {
   1174         for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
   1175           output[pixelOffset++] += buffer[actualPosition++] * amountToNext;
   1176           output[pixelOffset++] += buffer[actualPosition++] * amountToNext;
   1177           output[pixelOffset++] += buffer[actualPosition++] * amountToNext;
   1178         }
   1179         currentPosition = actualPosition;
   1180         weight -= amountToNext;
   1181       }
   1182       else {
   1183         for (pixelOffset = 0, amountToNext = actualPosition; pixelOffset < this.targetWidthMultipliedByChannels;) {
   1184           output[pixelOffset++] += buffer[amountToNext++] * weight;
   1185           output[pixelOffset++] += buffer[amountToNext++] * weight;
   1186           output[pixelOffset++] += buffer[amountToNext++] * weight;
   1187         }
   1188         currentPosition += weight;
   1189         break;
   1190       }
   1191     } while (weight > 0 && actualPosition < this.widthPassResultSize);
   1192     for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
   1193       outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] / ratioWeight);
   1194       outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] / ratioWeight);
   1195       outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] / ratioWeight);
   1196     }
   1197   } while (outputOffset < this.finalResultSize);
   1198   return outputBuffer;
   1199 }
   1200 Resize.prototype.resizeHeightInterpolated = function (buffer) {
   1201   var ratioWeight = (this.heightOriginal - 1) / this.targetHeight;
   1202   var weight = 0;
   1203   var finalOffset = 0;
   1204   var pixelOffset = 0;
   1205   var pixelOffsetAccumulated = 0;
   1206   var pixelOffsetAccumulated2 = 0;
   1207   var outputBuffer = this.heightBuffer;
   1208   do {
   1209     //Calculate weightings:
   1210     secondWeight = weight % 1;
   1211     firstWeight = 1 - secondWeight;
   1212     //Interpolate:
   1213     pixelOffsetAccumulated = Math.floor(weight) * this.targetWidthMultipliedByChannels;
   1214     pixelOffsetAccumulated2 = pixelOffsetAccumulated + this.targetWidthMultipliedByChannels;
   1215     for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels; ++pixelOffset) {
   1216       outputBuffer[finalOffset++] = (buffer[pixelOffsetAccumulated + pixelOffset] * firstWeight) + (buffer[pixelOffsetAccumulated2 + pixelOffset] * secondWeight);
   1217     }
   1218     weight += ratioWeight;
   1219   } while (finalOffset < this.finalResultSize);
   1220   return outputBuffer;
   1221 }
   1222 Resize.prototype.resizeHeightRGBA = function (buffer) {
   1223   var ratioWeight = this.ratioWeightHeightPass;
   1224   var weight = 0;
   1225   var amountToNext = 0;
   1226   var actualPosition = 0;
   1227   var currentPosition = 0;
   1228   var pixelOffset = 0;
   1229   var outputOffset = 0;
   1230   var output = this.outputHeightWorkBench;
   1231   var outputBuffer = this.heightBuffer;
   1232   do {
   1233     for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
   1234       output[pixelOffset++] = 0;
   1235       output[pixelOffset++] = 0;
   1236       output[pixelOffset++] = 0;
   1237       output[pixelOffset++] = 0;
   1238     }
   1239     weight = ratioWeight;
   1240     do {
   1241       amountToNext = 1 + actualPosition - currentPosition;
   1242       if (weight >= amountToNext) {
   1243         for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
   1244           output[pixelOffset++] += buffer[actualPosition++] * amountToNext;
   1245           output[pixelOffset++] += buffer[actualPosition++] * amountToNext;
   1246           output[pixelOffset++] += buffer[actualPosition++] * amountToNext;
   1247           output[pixelOffset++] += buffer[actualPosition++] * amountToNext;
   1248         }
   1249         currentPosition = actualPosition;
   1250         weight -= amountToNext;
   1251       }
   1252       else {
   1253         for (pixelOffset = 0, amountToNext = actualPosition; pixelOffset < this.targetWidthMultipliedByChannels;) {
   1254           output[pixelOffset++] += buffer[amountToNext++] * weight;
   1255           output[pixelOffset++] += buffer[amountToNext++] * weight;
   1256           output[pixelOffset++] += buffer[amountToNext++] * weight;
   1257           output[pixelOffset++] += buffer[amountToNext++] * weight;
   1258         }
   1259         currentPosition += weight;
   1260         break;
   1261       }
   1262     } while (weight > 0 && actualPosition < this.widthPassResultSize);
   1263     for (pixelOffset = 0; pixelOffset < this.targetWidthMultipliedByChannels;) {
   1264       outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] / ratioWeight);
   1265       outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] / ratioWeight);
   1266       outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] / ratioWeight);
   1267       outputBuffer[outputOffset++] = Math.round(output[pixelOffset++] / ratioWeight);
   1268     }
   1269   } while (outputOffset < this.finalResultSize);
   1270   return outputBuffer;
   1271 }
   1272 Resize.prototype.resizeHeightInterpolatedRGBA = function (buffer) {
   1273   var ratioWeight = (this.heightOriginal - 1) / this.targetHeight;
   1274   var weight = 0;
   1275   var finalOffset = 0;
   1276   var pixelOffset = 0;
   1277   var outputBuffer = this.heightBuffer;
   1278   while (pixelOffset < this.finalResultSize) {
   1279     //Calculate weightings:
   1280     secondWeight = weight % 1;
   1281     firstWeight = 1 - secondWeight;
   1282     //Interpolate:
   1283     for (pixelOffset = Math.floor(weight) * 4; pixelOffset < this.targetWidthMultipliedByChannels; pixelOffset += 4) {
   1284       outputBuffer[finalOffset++] = (buffer[pixelOffset] * firstWeight) + (buffer[pixelOffset + 4] * secondWeight);
   1285       outputBuffer[finalOffset++] = (buffer[pixelOffset + 1] * firstWeight) + (buffer[pixelOffset + 5] * secondWeight);
   1286       outputBuffer[finalOffset++] = (buffer[pixelOffset + 2] * firstWeight) + (buffer[pixelOffset + 6] * secondWeight);
   1287       outputBuffer[finalOffset++] = (buffer[pixelOffset + 3] * firstWeight) + (buffer[pixelOffset + 7] * secondWeight);
   1288     }
   1289     weight += ratioWeight;
   1290   }
   1291   return outputBuffer;
   1292 }
   1293 Resize.prototype.resize = function (buffer) {
   1294   return this.resizeHeight(this.resizeWidth(buffer));
   1295 }
   1296 Resize.prototype.bypassResizer = function (buffer) {
   1297   //Just return the buffer passsed:
   1298   return buffer;
   1299 }
   1300 Resize.prototype.initializeFirstPassBuffers = function (BILINEARAlgo) {
   1301   //Initialize the internal width pass buffers:
   1302   this.widthBuffer = this.generateFloatBuffer(this.widthPassResultSize);
   1303   if (!BILINEARAlgo) {
   1304     this.outputWidthWorkBench = this.generateFloatBuffer(this.originalHeightMultipliedByChannels);
   1305   }
   1306 }
   1307 Resize.prototype.initializeSecondPassBuffers = function (BILINEARAlgo) {
   1308   //Initialize the internal height pass buffers:
   1309   this.heightBuffer = this.generateUint8Buffer(this.finalResultSize);
   1310   if (!BILINEARAlgo) {
   1311     this.outputHeightWorkBench = this.generateFloatBuffer(this.targetWidthMultipliedByChannels);
   1312   }
   1313 }
   1314 Resize.prototype.generateFloatBuffer = function (bufferLength) {
   1315   //Generate a float32 typed array buffer:
   1316   try {
   1317     return new Float32Array(bufferLength);
   1318   }
   1319   catch (error) {
   1320     return [];
   1321   }
   1322 }
   1323 Resize.prototype.generateUint8Buffer = function (bufferLength) {
   1324   //Generate a uint8 typed array buffer:
   1325   try {
   1326     return this.checkForOperaMathBug(new Uint8Array(bufferLength));
   1327   }
   1328   catch (error) {
   1329     return [];
   1330   }
   1331 }
   1332 Resize.prototype.checkForOperaMathBug = function (typedArray) {
   1333   typedArray[0] = -1;
   1334   typedArray[0] >>= 0;
   1335   if (typedArray[0] != 0xFF) {
   1336     return [];
   1337   }
   1338   else {
   1339     return typedArray;
   1340   }
   1341 }
   1342 
   1343 // End of js/other/resize.js file.
   1344 
   1345 // Start of js/GameBoyCore.js file.
   1346 
   1347 "use strict";
   1348 /*
   1349  * JavaScript GameBoy Color Emulator
   1350  * Copyright (C) 2010 - 2012 Grant Galitz
   1351  *
   1352  * This program is free software; you can redistribute it and/or
   1353  * modify it under the terms of the GNU General Public License
   1354  * version 2 as published by the Free Software Foundation.
   1355  * The full license is available at http://www.gnu.org/licenses/gpl.html
   1356  *
   1357  * This program is distributed in the hope that it will be useful,
   1358  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   1359  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   1360  * GNU General Public License for more details.
   1361  *
   1362  */
   1363 function GameBoyCore(canvas, ROMImage) {
   1364   //Params, etc...
   1365   this.canvas = canvas;            //Canvas DOM object for drawing out the graphics to.
   1366   this.drawContext = null;          // LCD Context
   1367   this.ROMImage = ROMImage;          //The game's ROM.
   1368   //CPU Registers and Flags:
   1369   this.registerA = 0x01;             //Register A (Accumulator)
   1370   this.FZero = true;               //Register F  - Result was zero
   1371   this.FSubtract = false;            //Register F  - Subtraction was executed
   1372   this.FHalfCarry = true;            //Register F  - Half carry or half borrow
   1373   this.FCarry = true;              //Register F  - Carry or borrow
   1374   this.registerB = 0x00;            //Register B
   1375   this.registerC = 0x13;            //Register C
   1376   this.registerD = 0x00;            //Register D
   1377   this.registerE = 0xD8;            //Register E
   1378   this.registersHL = 0x014D;          //Registers H and L combined
   1379   this.stackPointer = 0xFFFE;          //Stack Pointer
   1380   this.programCounter = 0x0100;        //Program Counter
   1381   //Some CPU Emulation State Variables:
   1382   this.CPUCyclesTotal = 0;          //Relative CPU clocking to speed set, rounded appropriately.
   1383   this.CPUCyclesTotalBase = 0;        //Relative CPU clocking to speed set base.
   1384   this.CPUCyclesTotalCurrent = 0;        //Relative CPU clocking to speed set, the directly used value.
   1385   this.CPUCyclesTotalRoundoff = 0;      //Clocking per iteration rounding catch.
   1386   this.baseCPUCyclesPerIteration = 0;    //CPU clocks per iteration at 1x speed.
   1387   this.remainingClocks = 0;          //HALT clocking overrun carry over.
   1388   this.inBootstrap = true;          //Whether we're in the GBC boot ROM.
   1389   this.usedBootROM = false;          //Updated upon ROM loading...
   1390   this.usedGBCBootROM = false;        //Did we boot to the GBC boot ROM?
   1391   this.halt = false;              //Has the CPU been suspended until the next interrupt?
   1392   this.skipPCIncrement = false;        //Did we trip the DMG Halt bug?
   1393   this.stopEmulator = 3;            //Has the emulation been paused or a frame has ended?
   1394   this.IME = true;              //Are interrupts enabled?
   1395   this.IRQLineMatched = 0;          //CPU IRQ assertion.
   1396   this.interruptsRequested = 0;        //IF Register
   1397   this.interruptsEnabled = 0;          //IE Register
   1398   this.hdmaRunning = false;          //HDMA Transfer Flag - GBC only
   1399   this.CPUTicks = 0;              //The number of clock cycles emulated.
   1400   this.doubleSpeedShifter = 0;        //GBC double speed clocking shifter.
   1401   this.JoyPad = 0xFF;              //Joypad State (two four-bit states actually)
   1402   this.CPUStopped = false;          //CPU STOP status.
   1403   //Main RAM, MBC RAM, GBC Main RAM, VRAM, etc.
   1404   this.memoryReader = [];            //Array of functions mapped to read back memory
   1405   this.memoryWriter = [];            //Array of functions mapped to write to memory
   1406   this.memoryHighReader = [];          //Array of functions mapped to read back 0xFFXX memory
   1407   this.memoryHighWriter = [];          //Array of functions mapped to write to 0xFFXX memory
   1408   this.ROM = [];                //The full ROM file dumped to an array.
   1409   this.memory = [];              //Main Core Memory
   1410   this.MBCRam = [];              //Switchable RAM (Used by games for more RAM) for the main memory range 0xA000 - 0xC000.
   1411   this.VRAM = [];                //Extra VRAM bank for GBC.
   1412   this.GBCMemory = [];            //GBC main RAM Banks
   1413   this.MBC1Mode = false;            //MBC1 Type (4/32, 16/8)
   1414   this.MBCRAMBanksEnabled = false;      //MBC RAM Access Control.
   1415   this.currMBCRAMBank = 0;          //MBC Currently Indexed RAM Bank
   1416   this.currMBCRAMBankPosition = -0xA000;    //MBC Position Adder;
   1417   this.cGBC = false;              //GameBoy Color detection.
   1418   this.gbcRamBank = 1;            //Currently Switched GameBoy Color ram bank
   1419   this.gbcRamBankPosition = -0xD000;      //GBC RAM offset from address start.
   1420   this.gbcRamBankPositionECHO = -0xF000;    //GBC RAM (ECHO mirroring) offset from address start.
   1421   this.RAMBanks = [0, 1, 2, 4, 16];      //Used to map the RAM banks to maximum size the MBC used can do.
   1422   this.ROMBank1offs = 0;            //Offset of the ROM bank switching.
   1423   this.currentROMBank = 0;          //The parsed current ROM bank selection.
   1424   this.cartridgeType = 0;            //Cartridge Type
   1425   this.name = "";                //Name of the game
   1426   this.gameCode = "";              //Game code (Suffix for older games)
   1427   this.fromSaveState = false;          //A boolean to see if this was loaded in as a save state.
   1428   this.savedStateFileName = "";        //When loaded in as a save state, this will not be empty.
   1429   this.STATTracker = 0;            //Tracker for STAT triggering.
   1430   this.modeSTAT = 0;              //The scan line mode (for lines 1-144 it's 2-3-0, for 145-154 it's 1)
   1431   this.spriteCount = 252;            //Mode 3 extra clocking counter (Depends on how many sprites are on the current line.).
   1432   this.LYCMatchTriggerSTAT = false;      //Should we trigger an interrupt if LY==LYC?
   1433   this.mode2TriggerSTAT = false;        //Should we trigger an interrupt if in mode 2?
   1434   this.mode1TriggerSTAT = false;        //Should we trigger an interrupt if in mode 1?
   1435   this.mode0TriggerSTAT = false;        //Should we trigger an interrupt if in mode 0?
   1436   this.LCDisOn = false;            //Is the emulated LCD controller on?
   1437   this.LINECONTROL = [];            //Array of functions to handle each scan line we do (onscreen + offscreen)
   1438   this.DISPLAYOFFCONTROL = [function (parentObj) {
   1439     //Array of line 0 function to handle the LCD controller when it's off (Do nothing!).
   1440   }];
   1441   this.LCDCONTROL = null;            //Pointer to either LINECONTROL or DISPLAYOFFCONTROL.
   1442   this.initializeLCDController();        //Compile the LCD controller functions.
   1443   //RTC (Real Time Clock for MBC3):
   1444   this.RTCisLatched = false;
   1445   this.latchedSeconds = 0;          //RTC latched seconds.
   1446   this.latchedMinutes = 0;          //RTC latched minutes.
   1447   this.latchedHours = 0;            //RTC latched hours.
   1448   this.latchedLDays = 0;            //RTC latched lower 8-bits of the day counter.
   1449   this.latchedHDays = 0;            //RTC latched high-bit of the day counter.
   1450   this.RTCSeconds = 0;            //RTC seconds counter.
   1451   this.RTCMinutes = 0;            //RTC minutes counter.
   1452   this.RTCHours = 0;              //RTC hours counter.
   1453   this.RTCDays = 0;              //RTC days counter.
   1454   this.RTCDayOverFlow = false;        //Did the RTC overflow and wrap the day counter?
   1455   this.RTCHALT = false;            //Is the RTC allowed to clock up?
   1456   //Gyro:
   1457   this.highX = 127;
   1458   this.lowX = 127;
   1459   this.highY = 127;
   1460   this.lowY = 127;
   1461   //Sound variables:
   1462   this.audioHandle = null;            //XAudioJS handle
   1463   this.numSamplesTotal = 0;            //Length of the sound buffers.
   1464   this.sampleSize = 0;              //Length of the sound buffer for one channel.
   1465   this.dutyLookup = [                //Map the duty values given to ones we can work with.
   1466     [false, false, false, false, false, false, false, true],
   1467     [true, false, false, false, false, false, false, true],
   1468     [true, false, false, false, false, true, true, true],
   1469     [false, true, true, true, true, true, true, false]
   1470   ];
   1471   this.currentBuffer = [];            //The audio buffer we're working on.
   1472   this.bufferContainAmount = 0;          //Buffer maintenance metric.
   1473   this.LSFR15Table = null;
   1474   this.LSFR7Table = null;
   1475   this.noiseSampleTable = null;
   1476   this.initializeAudioStartState();
   1477   this.soundMasterEnabled = false;      //As its name implies
   1478   this.channel3PCM = null;          //Channel 3 adjusted sample buffer.
   1479   //Vin Shit:
   1480   this.VinLeftChannelMasterVolume = 8;    //Computed post-mixing volume.
   1481   this.VinRightChannelMasterVolume = 8;    //Computed post-mixing volume.
   1482   //Channel paths enabled:
   1483   this.leftChannel1 = false;
   1484   this.leftChannel2 = false;
   1485   this.leftChannel3 = false;
   1486   this.leftChannel4 = false;
   1487   this.rightChannel1 = false;
   1488   this.rightChannel2 = false;
   1489   this.rightChannel3 = false;
   1490   this.rightChannel4 = false;
   1491   //Channel output level caches:
   1492   this.channel1currentSampleLeft = 0;
   1493   this.channel1currentSampleRight = 0;
   1494   this.channel2currentSampleLeft = 0;
   1495   this.channel2currentSampleRight = 0;
   1496   this.channel3currentSampleLeft = 0;
   1497   this.channel3currentSampleRight = 0;
   1498   this.channel4currentSampleLeft = 0;
   1499   this.channel4currentSampleRight = 0;
   1500   this.channel1currentSampleLeftSecondary = 0;
   1501   this.channel1currentSampleRightSecondary = 0;
   1502   this.channel2currentSampleLeftSecondary = 0;
   1503   this.channel2currentSampleRightSecondary = 0;
   1504   this.channel3currentSampleLeftSecondary = 0;
   1505   this.channel3currentSampleRightSecondary = 0;
   1506   this.channel4currentSampleLeftSecondary = 0;
   1507   this.channel4currentSampleRightSecondary = 0;
   1508   this.channel1currentSampleLeftTrimary = 0;
   1509   this.channel1currentSampleRightTrimary = 0;
   1510   this.channel2currentSampleLeftTrimary = 0;
   1511   this.channel2currentSampleRightTrimary = 0;
   1512   this.mixerOutputCache = 0;
   1513   //Pre-multipliers to cache some calculations:
   1514   this.initializeTiming();
   1515   this.machineOut = 0;        //Premultiplier for audio samples per instruction.
   1516   //Audio generation counters:
   1517   this.audioTicks = 0;        //Used to sample the audio system every x CPU instructions.
   1518   this.audioIndex = 0;        //Used to keep alignment on audio generation.
   1519   this.rollover = 0;          //Used to keep alignment on the number of samples to output (Realign from counter alias).
   1520   //Timing Variables
   1521   this.emulatorTicks = 0;        //Times for how many instructions to execute before ending the loop.
   1522   this.DIVTicks = 56;          //DIV Ticks Counter (Invisible lower 8-bit)
   1523   this.LCDTicks = 60;          //Counter for how many instructions have been executed on a scanline so far.
   1524   this.timerTicks = 0;        //Counter for the TIMA timer.
   1525   this.TIMAEnabled = false;      //Is TIMA enabled?
   1526   this.TACClocker = 1024;        //Timer Max Ticks
   1527   this.serialTimer = 0;        //Serial IRQ Timer
   1528   this.serialShiftTimer = 0;      //Serial Transfer Shift Timer
   1529   this.serialShiftTimerAllocated = 0;  //Serial Transfer Shift Timer Refill
   1530   this.IRQEnableDelay = 0;      //Are the interrupts on queue to be enabled?
   1531   var dateVar = new_Date();     // The line is changed for benchmarking.
   1532   this.lastIteration = dateVar.getTime();//The last time we iterated the main loop.
   1533   dateVar = new_Date();         // The line is changed for benchmarking.
   1534   this.firstIteration = dateVar.getTime();
   1535   this.iterations = 0;
   1536   this.actualScanLine = 0;      //Actual scan line...
   1537   this.lastUnrenderedLine = 0;    //Last rendered scan line...
   1538   this.queuedScanLines = 0;
   1539   this.totalLinesPassed = 0;
   1540   this.haltPostClocks = 0;      //Post-Halt clocking.
   1541   //ROM Cartridge Components:
   1542   this.cMBC1 = false;          //Does the cartridge use MBC1?
   1543   this.cMBC2 = false;          //Does the cartridge use MBC2?
   1544   this.cMBC3 = false;          //Does the cartridge use MBC3?
   1545   this.cMBC5 = false;          //Does the cartridge use MBC5?
   1546   this.cMBC7 = false;          //Does the cartridge use MBC7?
   1547   this.cSRAM = false;          //Does the cartridge use save RAM?
   1548   this.cMMMO1 = false;        //...
   1549   this.cRUMBLE = false;        //Does the cartridge use the RUMBLE addressing (modified MBC5)?
   1550   this.cCamera = false;        //Is the cartridge actually a GameBoy Camera?
   1551   this.cTAMA5 = false;        //Does the cartridge use TAMA5? (Tamagotchi Cartridge)
   1552   this.cHuC3 = false;          //Does the cartridge use HuC3 (Hudson Soft / modified MBC3)?
   1553   this.cHuC1 = false;          //Does the cartridge use HuC1 (Hudson Soft / modified MBC1)?
   1554   this.cTIMER = false;        //Does the cartridge have an RTC?
   1555   this.ROMBanks = [          // 1 Bank = 16 KBytes = 256 Kbits
   1556     2, 4, 8, 16, 32, 64, 128, 256, 512
   1557   ];
   1558   this.ROMBanks[0x52] = 72;
   1559   this.ROMBanks[0x53] = 80;
   1560   this.ROMBanks[0x54] = 96;
   1561   this.numRAMBanks = 0;          //How many RAM banks were actually allocated?
   1562   ////Graphics Variables
   1563   this.currVRAMBank = 0;          //Current VRAM bank for GBC.
   1564   this.backgroundX = 0;          //Register SCX (X-Scroll)
   1565   this.backgroundY = 0;          //Register SCY (Y-Scroll)
   1566   this.gfxWindowDisplay = false;      //Is the windows enabled?
   1567   this.gfxSpriteShow = false;        //Are sprites enabled?
   1568   this.gfxSpriteNormalHeight = true;    //Are we doing 8x8 or 8x16 sprites?
   1569   this.bgEnabled = true;          //Is the BG enabled?
   1570   this.BGPriorityEnabled = true;      //Can we flag the BG for priority over sprites?
   1571   this.gfxWindowCHRBankPosition = 0;    //The current bank of the character map the window uses.
   1572   this.gfxBackgroundCHRBankPosition = 0;  //The current bank of the character map the BG uses.
   1573   this.gfxBackgroundBankOffset = 0x80;  //Fast mapping of the tile numbering/
   1574   this.windowY = 0;            //Current Y offset of the window.
   1575   this.windowX = 0;            //Current X offset of the window.
   1576   this.drewBlank = 0;            //To prevent the repeating of drawing a blank screen.
   1577   this.drewFrame = false;          //Throttle how many draws we can do to once per iteration.
   1578   this.midScanlineOffset = -1;      //mid-scanline rendering offset.
   1579   this.pixelEnd = 0;            //track the x-coord limit for line rendering (mid-scanline usage).
   1580   this.currentX = 0;            //The x-coord we left off at for mid-scanline rendering.
   1581   //BG Tile Pointer Caches:
   1582   this.BGCHRBank1 = null;
   1583   this.BGCHRBank2 = null;
   1584   this.BGCHRCurrentBank = null;
   1585   //Tile Data Cache:
   1586   this.tileCache = null;
   1587   //Palettes:
   1588   this.colors = [0xEFFFDE, 0xADD794, 0x529273, 0x183442];      //"Classic" GameBoy palette colors.
   1589   this.OBJPalette = null;
   1590   this.BGPalette = null;
   1591   this.gbcOBJRawPalette = null;
   1592   this.gbcBGRawPalette = null;
   1593   this.gbOBJPalette = null;
   1594   this.gbBGPalette = null;
   1595   this.gbcOBJPalette = null;
   1596   this.gbcBGPalette = null;
   1597   this.gbBGColorizedPalette = null;
   1598   this.gbOBJColorizedPalette = null;
   1599   this.cachedBGPaletteConversion = null;
   1600   this.cachedOBJPaletteConversion = null;
   1601   this.updateGBBGPalette = this.updateGBRegularBGPalette;
   1602   this.updateGBOBJPalette = this.updateGBRegularOBJPalette;
   1603   this.colorizedGBPalettes = false;
   1604   this.BGLayerRender = null;      //Reference to the BG rendering function.
   1605   this.WindowLayerRender = null;    //Reference to the window rendering function.
   1606   this.SpriteLayerRender = null;    //Reference to the OAM rendering function.
   1607   this.frameBuffer = [];        //The internal frame-buffer.
   1608   this.swizzledFrame = null;      //The secondary gfx buffer that holds the converted RGBA values.
   1609   this.canvasBuffer = null;      //imageData handle
   1610   this.pixelStart = 0;        //Temp variable for holding the current working framebuffer offset.
   1611   //Variables used for scaling in JS:
   1612   this.onscreenWidth = this.offscreenWidth = 160;
   1613   this.onscreenHeight = this.offScreenheight = 144;
   1614   this.offscreenRGBCount = this.onscreenWidth * this.onscreenHeight * 4;
   1615   //Initialize the white noise cache tables ahead of time:
   1616   this.intializeWhiteNoise();
   1617 }
   1618 
   1619 // Start of code changed for benchmarking (removed ROM):
   1620 GameBoyCore.prototype.GBBOOTROM = [];
   1621 GameBoyCore.prototype.GBCBOOTROM = [];
   1622 // End of code changed for benchmarking.
   1623 
   1624 GameBoyCore.prototype.ffxxDump = [  //Dump of the post-BOOT I/O register state (From gambatte):
   1625   0x0F, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0x00, 0xF8,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
   1626   0x80, 0xBF, 0xF3, 0xFF, 0xBF, 0xFF, 0x3F, 0x00,   0xFF, 0xBF, 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, 0xFF,
   1627   0xFF, 0x00, 0x00, 0xBF, 0x77, 0xF3, 0xF1, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   1628   0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,   0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
   1629   0x91, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC,   0x00, 0x00, 0x00, 0x00, 0xFF, 0x7E, 0xFF, 0xFE,
   1630   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   1631   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,   0xC0, 0xFF, 0xC1, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
   1632   0xF8, 0xFF, 0x00, 0x00, 0x00, 0x8F, 0x00, 0x00,   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
   1633   0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B,   0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D,
   1634   0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E,   0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99,
   1635   0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC,   0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E,
   1636   0x45, 0xEC, 0x52, 0xFA, 0x08, 0xB7, 0x07, 0x5D,   0x01, 0xFD, 0xC0, 0xFF, 0x08, 0xFC, 0x00, 0xE5,
   1637   0x0B, 0xF8, 0xC2, 0xCE, 0xF4, 0xF9, 0x0F, 0x7F,   0x45, 0x6D, 0x3D, 0xFE, 0x46, 0x97, 0x33, 0x5E,
   1638   0x08, 0xEF, 0xF1, 0xFF, 0x86, 0x83, 0x24, 0x74,   0x12, 0xFC, 0x00, 0x9F, 0xB4, 0xB7, 0x06, 0xD5,
   1639   0xD0, 0x7A, 0x00, 0x9E, 0x04, 0x5F, 0x41, 0x2F,   0x1D, 0x77, 0x36, 0x75, 0x81, 0xAA, 0x70, 0x3A,
   1640   0x98, 0xD1, 0x71, 0x02, 0x4D, 0x01, 0xC1, 0xFF,   0x0D, 0x00, 0xD3, 0x05, 0xF9, 0x00, 0x0B, 0x00
   1641 ];
   1642 GameBoyCore.prototype.OPCODE = [
   1643   //NOP
   1644   //#0x00:
   1645   function (parentObj) {
   1646     //Do Nothing...
   1647   },
   1648   //LD BC, nn
   1649   //#0x01:
   1650   function (parentObj) {
   1651     parentObj.registerC = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   1652     parentObj.registerB = parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF);
   1653     parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   1654   },
   1655   //LD (BC), A
   1656   //#0x02:
   1657   function (parentObj) {
   1658     parentObj.memoryWrite((parentObj.registerB << 8) | parentObj.registerC, parentObj.registerA);
   1659   },
   1660   //INC BC
   1661   //#0x03:
   1662   function (parentObj) {
   1663     var temp_var = ((parentObj.registerB << 8) | parentObj.registerC) + 1;
   1664     parentObj.registerB = (temp_var >> 8) & 0xFF;
   1665     parentObj.registerC = temp_var & 0xFF;
   1666   },
   1667   //INC B
   1668   //#0x04:
   1669   function (parentObj) {
   1670     parentObj.registerB = (parentObj.registerB + 1) & 0xFF;
   1671     parentObj.FZero = (parentObj.registerB == 0);
   1672     parentObj.FHalfCarry = ((parentObj.registerB & 0xF) == 0);
   1673     parentObj.FSubtract = false;
   1674   },
   1675   //DEC B
   1676   //#0x05:
   1677   function (parentObj) {
   1678     parentObj.registerB = (parentObj.registerB - 1) & 0xFF;
   1679     parentObj.FZero = (parentObj.registerB == 0);
   1680     parentObj.FHalfCarry = ((parentObj.registerB & 0xF) == 0xF);
   1681     parentObj.FSubtract = true;
   1682   },
   1683   //LD B, n
   1684   //#0x06:
   1685   function (parentObj) {
   1686     parentObj.registerB = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   1687     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   1688   },
   1689   //RLCA
   1690   //#0x07:
   1691   function (parentObj) {
   1692     parentObj.FCarry = (parentObj.registerA > 0x7F);
   1693     parentObj.registerA = ((parentObj.registerA << 1) & 0xFF) | (parentObj.registerA >> 7);
   1694     parentObj.FZero = parentObj.FSubtract = parentObj.FHalfCarry = false;
   1695   },
   1696   //LD (nn), SP
   1697   //#0x08:
   1698   function (parentObj) {
   1699     var temp_var = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   1700     parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   1701     parentObj.memoryWrite(temp_var, parentObj.stackPointer & 0xFF);
   1702     parentObj.memoryWrite((temp_var + 1) & 0xFFFF, parentObj.stackPointer >> 8);
   1703   },
   1704   //ADD HL, BC
   1705   //#0x09:
   1706   function (parentObj) {
   1707     var dirtySum = parentObj.registersHL + ((parentObj.registerB << 8) | parentObj.registerC);
   1708     parentObj.FHalfCarry = ((parentObj.registersHL & 0xFFF) > (dirtySum & 0xFFF));
   1709     parentObj.FCarry = (dirtySum > 0xFFFF);
   1710     parentObj.registersHL = dirtySum & 0xFFFF;
   1711     parentObj.FSubtract = false;
   1712   },
   1713   //LD A, (BC)
   1714   //#0x0A:
   1715   function (parentObj) {
   1716     parentObj.registerA = parentObj.memoryRead((parentObj.registerB << 8) | parentObj.registerC);
   1717   },
   1718   //DEC BC
   1719   //#0x0B:
   1720   function (parentObj) {
   1721     var temp_var = (((parentObj.registerB << 8) | parentObj.registerC) - 1) & 0xFFFF;
   1722     parentObj.registerB = temp_var >> 8;
   1723     parentObj.registerC = temp_var & 0xFF;
   1724   },
   1725   //INC C
   1726   //#0x0C:
   1727   function (parentObj) {
   1728     parentObj.registerC = (parentObj.registerC + 1) & 0xFF;
   1729     parentObj.FZero = (parentObj.registerC == 0);
   1730     parentObj.FHalfCarry = ((parentObj.registerC & 0xF) == 0);
   1731     parentObj.FSubtract = false;
   1732   },
   1733   //DEC C
   1734   //#0x0D:
   1735   function (parentObj) {
   1736     parentObj.registerC = (parentObj.registerC - 1) & 0xFF;
   1737     parentObj.FZero = (parentObj.registerC == 0);
   1738     parentObj.FHalfCarry = ((parentObj.registerC & 0xF) == 0xF);
   1739     parentObj.FSubtract = true;
   1740   },
   1741   //LD C, n
   1742   //#0x0E:
   1743   function (parentObj) {
   1744     parentObj.registerC = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   1745     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   1746   },
   1747   //RRCA
   1748   //#0x0F:
   1749   function (parentObj) {
   1750     parentObj.registerA = (parentObj.registerA >> 1) | ((parentObj.registerA & 1) << 7);
   1751     parentObj.FCarry = (parentObj.registerA > 0x7F);
   1752     parentObj.FZero = parentObj.FSubtract = parentObj.FHalfCarry = false;
   1753   },
   1754   //STOP
   1755   //#0x10:
   1756   function (parentObj) {
   1757     if (parentObj.cGBC) {
   1758       if ((parentObj.memory[0xFF4D] & 0x01) == 0x01) {    //Speed change requested.
   1759         if (parentObj.memory[0xFF4D] > 0x7F) {        //Go back to single speed mode.
   1760           cout("Going into single clock speed mode.", 0);
   1761           parentObj.doubleSpeedShifter = 0;
   1762           parentObj.memory[0xFF4D] &= 0x7F;        //Clear the double speed mode flag.
   1763         }
   1764         else {                        //Go to double speed mode.
   1765           cout("Going into double clock speed mode.", 0);
   1766           parentObj.doubleSpeedShifter = 1;
   1767           parentObj.memory[0xFF4D] |= 0x80;        //Set the double speed mode flag.
   1768         }
   1769         parentObj.memory[0xFF4D] &= 0xFE;          //Reset the request bit.
   1770       }
   1771       else {
   1772         parentObj.handleSTOP();
   1773       }
   1774     }
   1775     else {
   1776       parentObj.handleSTOP();
   1777     }
   1778   },
   1779   //LD DE, nn
   1780   //#0x11:
   1781   function (parentObj) {
   1782     parentObj.registerE = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   1783     parentObj.registerD = parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF);
   1784     parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   1785   },
   1786   //LD (DE), A
   1787   //#0x12:
   1788   function (parentObj) {
   1789     parentObj.memoryWrite((parentObj.registerD << 8) | parentObj.registerE, parentObj.registerA);
   1790   },
   1791   //INC DE
   1792   //#0x13:
   1793   function (parentObj) {
   1794     var temp_var = ((parentObj.registerD << 8) | parentObj.registerE) + 1;
   1795     parentObj.registerD = (temp_var >> 8) & 0xFF;
   1796     parentObj.registerE = temp_var & 0xFF;
   1797   },
   1798   //INC D
   1799   //#0x14:
   1800   function (parentObj) {
   1801     parentObj.registerD = (parentObj.registerD + 1) & 0xFF;
   1802     parentObj.FZero = (parentObj.registerD == 0);
   1803     parentObj.FHalfCarry = ((parentObj.registerD & 0xF) == 0);
   1804     parentObj.FSubtract = false;
   1805   },
   1806   //DEC D
   1807   //#0x15:
   1808   function (parentObj) {
   1809     parentObj.registerD = (parentObj.registerD - 1) & 0xFF;
   1810     parentObj.FZero = (parentObj.registerD == 0);
   1811     parentObj.FHalfCarry = ((parentObj.registerD & 0xF) == 0xF);
   1812     parentObj.FSubtract = true;
   1813   },
   1814   //LD D, n
   1815   //#0x16:
   1816   function (parentObj) {
   1817     parentObj.registerD = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   1818     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   1819   },
   1820   //RLA
   1821   //#0x17:
   1822   function (parentObj) {
   1823     var carry_flag = (parentObj.FCarry) ? 1 : 0;
   1824     parentObj.FCarry = (parentObj.registerA > 0x7F);
   1825     parentObj.registerA = ((parentObj.registerA << 1) & 0xFF) | carry_flag;
   1826     parentObj.FZero = parentObj.FSubtract = parentObj.FHalfCarry = false;
   1827   },
   1828   //JR n
   1829   //#0x18:
   1830   function (parentObj) {
   1831     parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
   1832   },
   1833   //ADD HL, DE
   1834   //#0x19:
   1835   function (parentObj) {
   1836     var dirtySum = parentObj.registersHL + ((parentObj.registerD << 8) | parentObj.registerE);
   1837     parentObj.FHalfCarry = ((parentObj.registersHL & 0xFFF) > (dirtySum & 0xFFF));
   1838     parentObj.FCarry = (dirtySum > 0xFFFF);
   1839     parentObj.registersHL = dirtySum & 0xFFFF;
   1840     parentObj.FSubtract = false;
   1841   },
   1842   //LD A, (DE)
   1843   //#0x1A:
   1844   function (parentObj) {
   1845     parentObj.registerA = parentObj.memoryRead((parentObj.registerD << 8) | parentObj.registerE);
   1846   },
   1847   //DEC DE
   1848   //#0x1B:
   1849   function (parentObj) {
   1850     var temp_var = (((parentObj.registerD << 8) | parentObj.registerE) - 1) & 0xFFFF;
   1851     parentObj.registerD = temp_var >> 8;
   1852     parentObj.registerE = temp_var & 0xFF;
   1853   },
   1854   //INC E
   1855   //#0x1C:
   1856   function (parentObj) {
   1857     parentObj.registerE = (parentObj.registerE + 1) & 0xFF;
   1858     parentObj.FZero = (parentObj.registerE == 0);
   1859     parentObj.FHalfCarry = ((parentObj.registerE & 0xF) == 0);
   1860     parentObj.FSubtract = false;
   1861   },
   1862   //DEC E
   1863   //#0x1D:
   1864   function (parentObj) {
   1865     parentObj.registerE = (parentObj.registerE - 1) & 0xFF;
   1866     parentObj.FZero = (parentObj.registerE == 0);
   1867     parentObj.FHalfCarry = ((parentObj.registerE & 0xF) == 0xF);
   1868     parentObj.FSubtract = true;
   1869   },
   1870   //LD E, n
   1871   //#0x1E:
   1872   function (parentObj) {
   1873     parentObj.registerE = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   1874     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   1875   },
   1876   //RRA
   1877   //#0x1F:
   1878   function (parentObj) {
   1879     var carry_flag = (parentObj.FCarry) ? 0x80 : 0;
   1880     parentObj.FCarry = ((parentObj.registerA & 1) == 1);
   1881     parentObj.registerA = (parentObj.registerA >> 1) | carry_flag;
   1882     parentObj.FZero = parentObj.FSubtract = parentObj.FHalfCarry = false;
   1883   },
   1884   //JR NZ, n
   1885   //#0x20:
   1886   function (parentObj) {
   1887     if (!parentObj.FZero) {
   1888       parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
   1889       parentObj.CPUTicks += 4;
   1890     }
   1891     else {
   1892       parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   1893     }
   1894   },
   1895   //LD HL, nn
   1896   //#0x21:
   1897   function (parentObj) {
   1898     parentObj.registersHL = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   1899     parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   1900   },
   1901   //LDI (HL), A
   1902   //#0x22:
   1903   function (parentObj) {
   1904     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerA);
   1905     parentObj.registersHL = (parentObj.registersHL + 1) & 0xFFFF;
   1906   },
   1907   //INC HL
   1908   //#0x23:
   1909   function (parentObj) {
   1910     parentObj.registersHL = (parentObj.registersHL + 1) & 0xFFFF;
   1911   },
   1912   //INC H
   1913   //#0x24:
   1914   function (parentObj) {
   1915     var H = ((parentObj.registersHL >> 8) + 1) & 0xFF;
   1916     parentObj.FZero = (H == 0);
   1917     parentObj.FHalfCarry = ((H & 0xF) == 0);
   1918     parentObj.FSubtract = false;
   1919     parentObj.registersHL = (H << 8) | (parentObj.registersHL & 0xFF);
   1920   },
   1921   //DEC H
   1922   //#0x25:
   1923   function (parentObj) {
   1924     var H = ((parentObj.registersHL >> 8) - 1) & 0xFF;
   1925     parentObj.FZero = (H == 0);
   1926     parentObj.FHalfCarry = ((H & 0xF) == 0xF);
   1927     parentObj.FSubtract = true;
   1928     parentObj.registersHL = (H << 8) | (parentObj.registersHL & 0xFF);
   1929   },
   1930   //LD H, n
   1931   //#0x26:
   1932   function (parentObj) {
   1933     parentObj.registersHL = (parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 8) | (parentObj.registersHL & 0xFF);
   1934     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   1935   },
   1936   //DAA
   1937   //#0x27:
   1938   function (parentObj) {
   1939     if (!parentObj.FSubtract) {
   1940       if (parentObj.FCarry || parentObj.registerA > 0x99) {
   1941         parentObj.registerA = (parentObj.registerA + 0x60) & 0xFF;
   1942         parentObj.FCarry = true;
   1943       }
   1944       if (parentObj.FHalfCarry || (parentObj.registerA & 0xF) > 0x9) {
   1945         parentObj.registerA = (parentObj.registerA + 0x06) & 0xFF;
   1946         parentObj.FHalfCarry = false;
   1947       }
   1948     }
   1949     else if (parentObj.FCarry && parentObj.FHalfCarry) {
   1950       parentObj.registerA = (parentObj.registerA + 0x9A) & 0xFF;
   1951       parentObj.FHalfCarry = false;
   1952     }
   1953     else if (parentObj.FCarry) {
   1954       parentObj.registerA = (parentObj.registerA + 0xA0) & 0xFF;
   1955     }
   1956     else if (parentObj.FHalfCarry) {
   1957       parentObj.registerA = (parentObj.registerA + 0xFA) & 0xFF;
   1958       parentObj.FHalfCarry = false;
   1959     }
   1960     parentObj.FZero = (parentObj.registerA == 0);
   1961   },
   1962   //JR Z, n
   1963   //#0x28:
   1964   function (parentObj) {
   1965     if (parentObj.FZero) {
   1966       parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
   1967       parentObj.CPUTicks += 4;
   1968     }
   1969     else {
   1970       parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   1971     }
   1972   },
   1973   //ADD HL, HL
   1974   //#0x29:
   1975   function (parentObj) {
   1976     parentObj.FHalfCarry = ((parentObj.registersHL & 0xFFF) > 0x7FF);
   1977     parentObj.FCarry = (parentObj.registersHL > 0x7FFF);
   1978     parentObj.registersHL = (parentObj.registersHL << 1) & 0xFFFF;
   1979     parentObj.FSubtract = false;
   1980   },
   1981   //LDI A, (HL)
   1982   //#0x2A:
   1983   function (parentObj) {
   1984     parentObj.registerA = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   1985     parentObj.registersHL = (parentObj.registersHL + 1) & 0xFFFF;
   1986   },
   1987   //DEC HL
   1988   //#0x2B:
   1989   function (parentObj) {
   1990     parentObj.registersHL = (parentObj.registersHL - 1) & 0xFFFF;
   1991   },
   1992   //INC L
   1993   //#0x2C:
   1994   function (parentObj) {
   1995     var L = (parentObj.registersHL + 1) & 0xFF;
   1996     parentObj.FZero = (L == 0);
   1997     parentObj.FHalfCarry = ((L & 0xF) == 0);
   1998     parentObj.FSubtract = false;
   1999     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | L;
   2000   },
   2001   //DEC L
   2002   //#0x2D:
   2003   function (parentObj) {
   2004     var L = (parentObj.registersHL - 1) & 0xFF;
   2005     parentObj.FZero = (L == 0);
   2006     parentObj.FHalfCarry = ((L & 0xF) == 0xF);
   2007     parentObj.FSubtract = true;
   2008     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | L;
   2009   },
   2010   //LD L, n
   2011   //#0x2E:
   2012   function (parentObj) {
   2013     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   2014     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   2015   },
   2016   //CPL
   2017   //#0x2F:
   2018   function (parentObj) {
   2019     parentObj.registerA ^= 0xFF;
   2020     parentObj.FSubtract = parentObj.FHalfCarry = true;
   2021   },
   2022   //JR NC, n
   2023   //#0x30:
   2024   function (parentObj) {
   2025     if (!parentObj.FCarry) {
   2026       parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
   2027       parentObj.CPUTicks += 4;
   2028     }
   2029     else {
   2030       parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   2031     }
   2032   },
   2033   //LD SP, nn
   2034   //#0x31:
   2035   function (parentObj) {
   2036     parentObj.stackPointer = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   2037     parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   2038   },
   2039   //LDD (HL), A
   2040   //#0x32:
   2041   function (parentObj) {
   2042     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerA);
   2043     parentObj.registersHL = (parentObj.registersHL - 1) & 0xFFFF;
   2044   },
   2045   //INC SP
   2046   //#0x33:
   2047   function (parentObj) {
   2048     parentObj.stackPointer = (parentObj.stackPointer + 1) & 0xFFFF;
   2049   },
   2050   //INC (HL)
   2051   //#0x34:
   2052   function (parentObj) {
   2053     var temp_var = (parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) + 1) & 0xFF;
   2054     parentObj.FZero = (temp_var == 0);
   2055     parentObj.FHalfCarry = ((temp_var & 0xF) == 0);
   2056     parentObj.FSubtract = false;
   2057     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
   2058   },
   2059   //DEC (HL)
   2060   //#0x35:
   2061   function (parentObj) {
   2062     var temp_var = (parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) - 1) & 0xFF;
   2063     parentObj.FZero = (temp_var == 0);
   2064     parentObj.FHalfCarry = ((temp_var & 0xF) == 0xF);
   2065     parentObj.FSubtract = true;
   2066     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
   2067   },
   2068   //LD (HL), n
   2069   //#0x36:
   2070   function (parentObj) {
   2071     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter));
   2072     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   2073   },
   2074   //SCF
   2075   //#0x37:
   2076   function (parentObj) {
   2077     parentObj.FCarry = true;
   2078     parentObj.FSubtract = parentObj.FHalfCarry = false;
   2079   },
   2080   //JR C, n
   2081   //#0x38:
   2082   function (parentObj) {
   2083     if (parentObj.FCarry) {
   2084       parentObj.programCounter = (parentObj.programCounter + ((parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24) + 1) & 0xFFFF;
   2085       parentObj.CPUTicks += 4;
   2086     }
   2087     else {
   2088       parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   2089     }
   2090   },
   2091   //ADD HL, SP
   2092   //#0x39:
   2093   function (parentObj) {
   2094     var dirtySum = parentObj.registersHL + parentObj.stackPointer;
   2095     parentObj.FHalfCarry = ((parentObj.registersHL & 0xFFF) > (dirtySum & 0xFFF));
   2096     parentObj.FCarry = (dirtySum > 0xFFFF);
   2097     parentObj.registersHL = dirtySum & 0xFFFF;
   2098     parentObj.FSubtract = false;
   2099   },
   2100   //LDD A, (HL)
   2101   //#0x3A:
   2102   function (parentObj) {
   2103     parentObj.registerA = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2104     parentObj.registersHL = (parentObj.registersHL - 1) & 0xFFFF;
   2105   },
   2106   //DEC SP
   2107   //#0x3B:
   2108   function (parentObj) {
   2109     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   2110   },
   2111   //INC A
   2112   //#0x3C:
   2113   function (parentObj) {
   2114     parentObj.registerA = (parentObj.registerA + 1) & 0xFF;
   2115     parentObj.FZero = (parentObj.registerA == 0);
   2116     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) == 0);
   2117     parentObj.FSubtract = false;
   2118   },
   2119   //DEC A
   2120   //#0x3D:
   2121   function (parentObj) {
   2122     parentObj.registerA = (parentObj.registerA - 1) & 0xFF;
   2123     parentObj.FZero = (parentObj.registerA == 0);
   2124     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) == 0xF);
   2125     parentObj.FSubtract = true;
   2126   },
   2127   //LD A, n
   2128   //#0x3E:
   2129   function (parentObj) {
   2130     parentObj.registerA = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   2131     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   2132   },
   2133   //CCF
   2134   //#0x3F:
   2135   function (parentObj) {
   2136     parentObj.FCarry = !parentObj.FCarry;
   2137     parentObj.FSubtract = parentObj.FHalfCarry = false;
   2138   },
   2139   //LD B, B
   2140   //#0x40:
   2141   function (parentObj) {
   2142     //Do nothing...
   2143   },
   2144   //LD B, C
   2145   //#0x41:
   2146   function (parentObj) {
   2147     parentObj.registerB = parentObj.registerC;
   2148   },
   2149   //LD B, D
   2150   //#0x42:
   2151   function (parentObj) {
   2152     parentObj.registerB = parentObj.registerD;
   2153   },
   2154   //LD B, E
   2155   //#0x43:
   2156   function (parentObj) {
   2157     parentObj.registerB = parentObj.registerE;
   2158   },
   2159   //LD B, H
   2160   //#0x44:
   2161   function (parentObj) {
   2162     parentObj.registerB = parentObj.registersHL >> 8;
   2163   },
   2164   //LD B, L
   2165   //#0x45:
   2166   function (parentObj) {
   2167     parentObj.registerB = parentObj.registersHL & 0xFF;
   2168   },
   2169   //LD B, (HL)
   2170   //#0x46:
   2171   function (parentObj) {
   2172     parentObj.registerB = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2173   },
   2174   //LD B, A
   2175   //#0x47:
   2176   function (parentObj) {
   2177     parentObj.registerB = parentObj.registerA;
   2178   },
   2179   //LD C, B
   2180   //#0x48:
   2181   function (parentObj) {
   2182     parentObj.registerC = parentObj.registerB;
   2183   },
   2184   //LD C, C
   2185   //#0x49:
   2186   function (parentObj) {
   2187     //Do nothing...
   2188   },
   2189   //LD C, D
   2190   //#0x4A:
   2191   function (parentObj) {
   2192     parentObj.registerC = parentObj.registerD;
   2193   },
   2194   //LD C, E
   2195   //#0x4B:
   2196   function (parentObj) {
   2197     parentObj.registerC = parentObj.registerE;
   2198   },
   2199   //LD C, H
   2200   //#0x4C:
   2201   function (parentObj) {
   2202     parentObj.registerC = parentObj.registersHL >> 8;
   2203   },
   2204   //LD C, L
   2205   //#0x4D:
   2206   function (parentObj) {
   2207     parentObj.registerC = parentObj.registersHL & 0xFF;
   2208   },
   2209   //LD C, (HL)
   2210   //#0x4E:
   2211   function (parentObj) {
   2212     parentObj.registerC = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2213   },
   2214   //LD C, A
   2215   //#0x4F:
   2216   function (parentObj) {
   2217     parentObj.registerC = parentObj.registerA;
   2218   },
   2219   //LD D, B
   2220   //#0x50:
   2221   function (parentObj) {
   2222     parentObj.registerD = parentObj.registerB;
   2223   },
   2224   //LD D, C
   2225   //#0x51:
   2226   function (parentObj) {
   2227     parentObj.registerD = parentObj.registerC;
   2228   },
   2229   //LD D, D
   2230   //#0x52:
   2231   function (parentObj) {
   2232     //Do nothing...
   2233   },
   2234   //LD D, E
   2235   //#0x53:
   2236   function (parentObj) {
   2237     parentObj.registerD = parentObj.registerE;
   2238   },
   2239   //LD D, H
   2240   //#0x54:
   2241   function (parentObj) {
   2242     parentObj.registerD = parentObj.registersHL >> 8;
   2243   },
   2244   //LD D, L
   2245   //#0x55:
   2246   function (parentObj) {
   2247     parentObj.registerD = parentObj.registersHL & 0xFF;
   2248   },
   2249   //LD D, (HL)
   2250   //#0x56:
   2251   function (parentObj) {
   2252     parentObj.registerD = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2253   },
   2254   //LD D, A
   2255   //#0x57:
   2256   function (parentObj) {
   2257     parentObj.registerD = parentObj.registerA;
   2258   },
   2259   //LD E, B
   2260   //#0x58:
   2261   function (parentObj) {
   2262     parentObj.registerE = parentObj.registerB;
   2263   },
   2264   //LD E, C
   2265   //#0x59:
   2266   function (parentObj) {
   2267     parentObj.registerE = parentObj.registerC;
   2268   },
   2269   //LD E, D
   2270   //#0x5A:
   2271   function (parentObj) {
   2272     parentObj.registerE = parentObj.registerD;
   2273   },
   2274   //LD E, E
   2275   //#0x5B:
   2276   function (parentObj) {
   2277     //Do nothing...
   2278   },
   2279   //LD E, H
   2280   //#0x5C:
   2281   function (parentObj) {
   2282     parentObj.registerE = parentObj.registersHL >> 8;
   2283   },
   2284   //LD E, L
   2285   //#0x5D:
   2286   function (parentObj) {
   2287     parentObj.registerE = parentObj.registersHL & 0xFF;
   2288   },
   2289   //LD E, (HL)
   2290   //#0x5E:
   2291   function (parentObj) {
   2292     parentObj.registerE = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2293   },
   2294   //LD E, A
   2295   //#0x5F:
   2296   function (parentObj) {
   2297     parentObj.registerE = parentObj.registerA;
   2298   },
   2299   //LD H, B
   2300   //#0x60:
   2301   function (parentObj) {
   2302     parentObj.registersHL = (parentObj.registerB << 8) | (parentObj.registersHL & 0xFF);
   2303   },
   2304   //LD H, C
   2305   //#0x61:
   2306   function (parentObj) {
   2307     parentObj.registersHL = (parentObj.registerC << 8) | (parentObj.registersHL & 0xFF);
   2308   },
   2309   //LD H, D
   2310   //#0x62:
   2311   function (parentObj) {
   2312     parentObj.registersHL = (parentObj.registerD << 8) | (parentObj.registersHL & 0xFF);
   2313   },
   2314   //LD H, E
   2315   //#0x63:
   2316   function (parentObj) {
   2317     parentObj.registersHL = (parentObj.registerE << 8) | (parentObj.registersHL & 0xFF);
   2318   },
   2319   //LD H, H
   2320   //#0x64:
   2321   function (parentObj) {
   2322     //Do nothing...
   2323   },
   2324   //LD H, L
   2325   //#0x65:
   2326   function (parentObj) {
   2327     parentObj.registersHL = (parentObj.registersHL & 0xFF) * 0x101;
   2328   },
   2329   //LD H, (HL)
   2330   //#0x66:
   2331   function (parentObj) {
   2332     parentObj.registersHL = (parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) << 8) | (parentObj.registersHL & 0xFF);
   2333   },
   2334   //LD H, A
   2335   //#0x67:
   2336   function (parentObj) {
   2337     parentObj.registersHL = (parentObj.registerA << 8) | (parentObj.registersHL & 0xFF);
   2338   },
   2339   //LD L, B
   2340   //#0x68:
   2341   function (parentObj) {
   2342     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerB;
   2343   },
   2344   //LD L, C
   2345   //#0x69:
   2346   function (parentObj) {
   2347     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerC;
   2348   },
   2349   //LD L, D
   2350   //#0x6A:
   2351   function (parentObj) {
   2352     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerD;
   2353   },
   2354   //LD L, E
   2355   //#0x6B:
   2356   function (parentObj) {
   2357     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerE;
   2358   },
   2359   //LD L, H
   2360   //#0x6C:
   2361   function (parentObj) {
   2362     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | (parentObj.registersHL >> 8);
   2363   },
   2364   //LD L, L
   2365   //#0x6D:
   2366   function (parentObj) {
   2367     //Do nothing...
   2368   },
   2369   //LD L, (HL)
   2370   //#0x6E:
   2371   function (parentObj) {
   2372     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2373   },
   2374   //LD L, A
   2375   //#0x6F:
   2376   function (parentObj) {
   2377     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | parentObj.registerA;
   2378   },
   2379   //LD (HL), B
   2380   //#0x70:
   2381   function (parentObj) {
   2382     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerB);
   2383   },
   2384   //LD (HL), C
   2385   //#0x71:
   2386   function (parentObj) {
   2387     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerC);
   2388   },
   2389   //LD (HL), D
   2390   //#0x72:
   2391   function (parentObj) {
   2392     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerD);
   2393   },
   2394   //LD (HL), E
   2395   //#0x73:
   2396   function (parentObj) {
   2397     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerE);
   2398   },
   2399   //LD (HL), H
   2400   //#0x74:
   2401   function (parentObj) {
   2402     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registersHL >> 8);
   2403   },
   2404   //LD (HL), L
   2405   //#0x75:
   2406   function (parentObj) {
   2407     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registersHL & 0xFF);
   2408   },
   2409   //HALT
   2410   //#0x76:
   2411   function (parentObj) {
   2412     //See if there's already an IRQ match:
   2413     if ((parentObj.interruptsEnabled & parentObj.interruptsRequested & 0x1F) > 0) {
   2414       if (!parentObj.cGBC && !parentObj.usedBootROM) {
   2415         //HALT bug in the DMG CPU model (Program Counter fails to increment for one instruction after HALT):
   2416         parentObj.skipPCIncrement = true;
   2417       }
   2418       else {
   2419         //CGB gets around the HALT PC bug by doubling the hidden NOP.
   2420         parentObj.CPUTicks += 4;
   2421       }
   2422     }
   2423     else {
   2424       //CPU is stalled until the next IRQ match:
   2425       parentObj.calculateHALTPeriod();
   2426     }
   2427   },
   2428   //LD (HL), A
   2429   //#0x77:
   2430   function (parentObj) {
   2431     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.registerA);
   2432   },
   2433   //LD A, B
   2434   //#0x78:
   2435   function (parentObj) {
   2436     parentObj.registerA = parentObj.registerB;
   2437   },
   2438   //LD A, C
   2439   //#0x79:
   2440   function (parentObj) {
   2441     parentObj.registerA = parentObj.registerC;
   2442   },
   2443   //LD A, D
   2444   //#0x7A:
   2445   function (parentObj) {
   2446     parentObj.registerA = parentObj.registerD;
   2447   },
   2448   //LD A, E
   2449   //#0x7B:
   2450   function (parentObj) {
   2451     parentObj.registerA = parentObj.registerE;
   2452   },
   2453   //LD A, H
   2454   //#0x7C:
   2455   function (parentObj) {
   2456     parentObj.registerA = parentObj.registersHL >> 8;
   2457   },
   2458   //LD A, L
   2459   //#0x7D:
   2460   function (parentObj) {
   2461     parentObj.registerA = parentObj.registersHL & 0xFF;
   2462   },
   2463   //LD, A, (HL)
   2464   //#0x7E:
   2465   function (parentObj) {
   2466     parentObj.registerA = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2467   },
   2468   //LD A, A
   2469   //#0x7F:
   2470   function (parentObj) {
   2471     //Do Nothing...
   2472   },
   2473   //ADD A, B
   2474   //#0x80:
   2475   function (parentObj) {
   2476     var dirtySum = parentObj.registerA + parentObj.registerB;
   2477     parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
   2478     parentObj.FCarry = (dirtySum > 0xFF);
   2479     parentObj.registerA = dirtySum & 0xFF;
   2480     parentObj.FZero = (parentObj.registerA == 0);
   2481     parentObj.FSubtract = false;
   2482   },
   2483   //ADD A, C
   2484   //#0x81:
   2485   function (parentObj) {
   2486     var dirtySum = parentObj.registerA + parentObj.registerC;
   2487     parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
   2488     parentObj.FCarry = (dirtySum > 0xFF);
   2489     parentObj.registerA = dirtySum & 0xFF;
   2490     parentObj.FZero = (parentObj.registerA == 0);
   2491     parentObj.FSubtract = false;
   2492   },
   2493   //ADD A, D
   2494   //#0x82:
   2495   function (parentObj) {
   2496     var dirtySum = parentObj.registerA + parentObj.registerD;
   2497     parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
   2498     parentObj.FCarry = (dirtySum > 0xFF);
   2499     parentObj.registerA = dirtySum & 0xFF;
   2500     parentObj.FZero = (parentObj.registerA == 0);
   2501     parentObj.FSubtract = false;
   2502   },
   2503   //ADD A, E
   2504   //#0x83:
   2505   function (parentObj) {
   2506     var dirtySum = parentObj.registerA + parentObj.registerE;
   2507     parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
   2508     parentObj.FCarry = (dirtySum > 0xFF);
   2509     parentObj.registerA = dirtySum & 0xFF;
   2510     parentObj.FZero = (parentObj.registerA == 0);
   2511     parentObj.FSubtract = false;
   2512   },
   2513   //ADD A, H
   2514   //#0x84:
   2515   function (parentObj) {
   2516     var dirtySum = parentObj.registerA + (parentObj.registersHL >> 8);
   2517     parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
   2518     parentObj.FCarry = (dirtySum > 0xFF);
   2519     parentObj.registerA = dirtySum & 0xFF;
   2520     parentObj.FZero = (parentObj.registerA == 0);
   2521     parentObj.FSubtract = false;
   2522   },
   2523   //ADD A, L
   2524   //#0x85:
   2525   function (parentObj) {
   2526     var dirtySum = parentObj.registerA + (parentObj.registersHL & 0xFF);
   2527     parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
   2528     parentObj.FCarry = (dirtySum > 0xFF);
   2529     parentObj.registerA = dirtySum & 0xFF;
   2530     parentObj.FZero = (parentObj.registerA == 0);
   2531     parentObj.FSubtract = false;
   2532   },
   2533   //ADD A, (HL)
   2534   //#0x86:
   2535   function (parentObj) {
   2536     var dirtySum = parentObj.registerA + parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2537     parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
   2538     parentObj.FCarry = (dirtySum > 0xFF);
   2539     parentObj.registerA = dirtySum & 0xFF;
   2540     parentObj.FZero = (parentObj.registerA == 0);
   2541     parentObj.FSubtract = false;
   2542   },
   2543   //ADD A, A
   2544   //#0x87:
   2545   function (parentObj) {
   2546     parentObj.FHalfCarry = ((parentObj.registerA & 0x8) == 0x8);
   2547     parentObj.FCarry = (parentObj.registerA > 0x7F);
   2548     parentObj.registerA = (parentObj.registerA << 1) & 0xFF;
   2549     parentObj.FZero = (parentObj.registerA == 0);
   2550     parentObj.FSubtract = false;
   2551   },
   2552   //ADC A, B
   2553   //#0x88:
   2554   function (parentObj) {
   2555     var dirtySum = parentObj.registerA + parentObj.registerB + ((parentObj.FCarry) ? 1 : 0);
   2556     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (parentObj.registerB & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
   2557     parentObj.FCarry = (dirtySum > 0xFF);
   2558     parentObj.registerA = dirtySum & 0xFF;
   2559     parentObj.FZero = (parentObj.registerA == 0);
   2560     parentObj.FSubtract = false;
   2561   },
   2562   //ADC A, C
   2563   //#0x89:
   2564   function (parentObj) {
   2565     var dirtySum = parentObj.registerA + parentObj.registerC + ((parentObj.FCarry) ? 1 : 0);
   2566     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (parentObj.registerC & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
   2567     parentObj.FCarry = (dirtySum > 0xFF);
   2568     parentObj.registerA = dirtySum & 0xFF;
   2569     parentObj.FZero = (parentObj.registerA == 0);
   2570     parentObj.FSubtract = false;
   2571   },
   2572   //ADC A, D
   2573   //#0x8A:
   2574   function (parentObj) {
   2575     var dirtySum = parentObj.registerA + parentObj.registerD + ((parentObj.FCarry) ? 1 : 0);
   2576     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (parentObj.registerD & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
   2577     parentObj.FCarry = (dirtySum > 0xFF);
   2578     parentObj.registerA = dirtySum & 0xFF;
   2579     parentObj.FZero = (parentObj.registerA == 0);
   2580     parentObj.FSubtract = false;
   2581   },
   2582   //ADC A, E
   2583   //#0x8B:
   2584   function (parentObj) {
   2585     var dirtySum = parentObj.registerA + parentObj.registerE + ((parentObj.FCarry) ? 1 : 0);
   2586     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (parentObj.registerE & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
   2587     parentObj.FCarry = (dirtySum > 0xFF);
   2588     parentObj.registerA = dirtySum & 0xFF;
   2589     parentObj.FZero = (parentObj.registerA == 0);
   2590     parentObj.FSubtract = false;
   2591   },
   2592   //ADC A, H
   2593   //#0x8C:
   2594   function (parentObj) {
   2595     var tempValue = (parentObj.registersHL >> 8);
   2596     var dirtySum = parentObj.registerA + tempValue + ((parentObj.FCarry) ? 1 : 0);
   2597     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (tempValue & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
   2598     parentObj.FCarry = (dirtySum > 0xFF);
   2599     parentObj.registerA = dirtySum & 0xFF;
   2600     parentObj.FZero = (parentObj.registerA == 0);
   2601     parentObj.FSubtract = false;
   2602   },
   2603   //ADC A, L
   2604   //#0x8D:
   2605   function (parentObj) {
   2606     var tempValue = (parentObj.registersHL & 0xFF);
   2607     var dirtySum = parentObj.registerA + tempValue + ((parentObj.FCarry) ? 1 : 0);
   2608     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (tempValue & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
   2609     parentObj.FCarry = (dirtySum > 0xFF);
   2610     parentObj.registerA = dirtySum & 0xFF;
   2611     parentObj.FZero = (parentObj.registerA == 0);
   2612     parentObj.FSubtract = false;
   2613   },
   2614   //ADC A, (HL)
   2615   //#0x8E:
   2616   function (parentObj) {
   2617     var tempValue = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2618     var dirtySum = parentObj.registerA + tempValue + ((parentObj.FCarry) ? 1 : 0);
   2619     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (tempValue & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
   2620     parentObj.FCarry = (dirtySum > 0xFF);
   2621     parentObj.registerA = dirtySum & 0xFF;
   2622     parentObj.FZero = (parentObj.registerA == 0);
   2623     parentObj.FSubtract = false;
   2624   },
   2625   //ADC A, A
   2626   //#0x8F:
   2627   function (parentObj) {
   2628     //shift left register A one bit for some ops here as an optimization:
   2629     var dirtySum = (parentObj.registerA << 1) | ((parentObj.FCarry) ? 1 : 0);
   2630     parentObj.FHalfCarry = ((((parentObj.registerA << 1) & 0x1E) | ((parentObj.FCarry) ? 1 : 0)) > 0xF);
   2631     parentObj.FCarry = (dirtySum > 0xFF);
   2632     parentObj.registerA = dirtySum & 0xFF;
   2633     parentObj.FZero = (parentObj.registerA == 0);
   2634     parentObj.FSubtract = false;
   2635   },
   2636   //SUB A, B
   2637   //#0x90:
   2638   function (parentObj) {
   2639     var dirtySum = parentObj.registerA - parentObj.registerB;
   2640     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
   2641     parentObj.FCarry = (dirtySum < 0);
   2642     parentObj.registerA = dirtySum & 0xFF;
   2643     parentObj.FZero = (dirtySum == 0);
   2644     parentObj.FSubtract = true;
   2645   },
   2646   //SUB A, C
   2647   //#0x91:
   2648   function (parentObj) {
   2649     var dirtySum = parentObj.registerA - parentObj.registerC;
   2650     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
   2651     parentObj.FCarry = (dirtySum < 0);
   2652     parentObj.registerA = dirtySum & 0xFF;
   2653     parentObj.FZero = (dirtySum == 0);
   2654     parentObj.FSubtract = true;
   2655   },
   2656   //SUB A, D
   2657   //#0x92:
   2658   function (parentObj) {
   2659     var dirtySum = parentObj.registerA - parentObj.registerD;
   2660     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
   2661     parentObj.FCarry = (dirtySum < 0);
   2662     parentObj.registerA = dirtySum & 0xFF;
   2663     parentObj.FZero = (dirtySum == 0);
   2664     parentObj.FSubtract = true;
   2665   },
   2666   //SUB A, E
   2667   //#0x93:
   2668   function (parentObj) {
   2669     var dirtySum = parentObj.registerA - parentObj.registerE;
   2670     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
   2671     parentObj.FCarry = (dirtySum < 0);
   2672     parentObj.registerA = dirtySum & 0xFF;
   2673     parentObj.FZero = (dirtySum == 0);
   2674     parentObj.FSubtract = true;
   2675   },
   2676   //SUB A, H
   2677   //#0x94:
   2678   function (parentObj) {
   2679     var dirtySum = parentObj.registerA - (parentObj.registersHL >> 8);
   2680     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
   2681     parentObj.FCarry = (dirtySum < 0);
   2682     parentObj.registerA = dirtySum & 0xFF;
   2683     parentObj.FZero = (dirtySum == 0);
   2684     parentObj.FSubtract = true;
   2685   },
   2686   //SUB A, L
   2687   //#0x95:
   2688   function (parentObj) {
   2689     var dirtySum = parentObj.registerA - (parentObj.registersHL & 0xFF);
   2690     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
   2691     parentObj.FCarry = (dirtySum < 0);
   2692     parentObj.registerA = dirtySum & 0xFF;
   2693     parentObj.FZero = (dirtySum == 0);
   2694     parentObj.FSubtract = true;
   2695   },
   2696   //SUB A, (HL)
   2697   //#0x96:
   2698   function (parentObj) {
   2699     var dirtySum = parentObj.registerA - parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2700     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
   2701     parentObj.FCarry = (dirtySum < 0);
   2702     parentObj.registerA = dirtySum & 0xFF;
   2703     parentObj.FZero = (dirtySum == 0);
   2704     parentObj.FSubtract = true;
   2705   },
   2706   //SUB A, A
   2707   //#0x97:
   2708   function (parentObj) {
   2709     //number - same number == 0
   2710     parentObj.registerA = 0;
   2711     parentObj.FHalfCarry = parentObj.FCarry = false;
   2712     parentObj.FZero = parentObj.FSubtract = true;
   2713   },
   2714   //SBC A, B
   2715   //#0x98:
   2716   function (parentObj) {
   2717     var dirtySum = parentObj.registerA - parentObj.registerB - ((parentObj.FCarry) ? 1 : 0);
   2718     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registerB & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
   2719     parentObj.FCarry = (dirtySum < 0);
   2720     parentObj.registerA = dirtySum & 0xFF;
   2721     parentObj.FZero = (parentObj.registerA == 0);
   2722     parentObj.FSubtract = true;
   2723   },
   2724   //SBC A, C
   2725   //#0x99:
   2726   function (parentObj) {
   2727     var dirtySum = parentObj.registerA - parentObj.registerC - ((parentObj.FCarry) ? 1 : 0);
   2728     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registerC & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
   2729     parentObj.FCarry = (dirtySum < 0);
   2730     parentObj.registerA = dirtySum & 0xFF;
   2731     parentObj.FZero = (parentObj.registerA == 0);
   2732     parentObj.FSubtract = true;
   2733   },
   2734   //SBC A, D
   2735   //#0x9A:
   2736   function (parentObj) {
   2737     var dirtySum = parentObj.registerA - parentObj.registerD - ((parentObj.FCarry) ? 1 : 0);
   2738     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registerD & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
   2739     parentObj.FCarry = (dirtySum < 0);
   2740     parentObj.registerA = dirtySum & 0xFF;
   2741     parentObj.FZero = (parentObj.registerA == 0);
   2742     parentObj.FSubtract = true;
   2743   },
   2744   //SBC A, E
   2745   //#0x9B:
   2746   function (parentObj) {
   2747     var dirtySum = parentObj.registerA - parentObj.registerE - ((parentObj.FCarry) ? 1 : 0);
   2748     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registerE & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
   2749     parentObj.FCarry = (dirtySum < 0);
   2750     parentObj.registerA = dirtySum & 0xFF;
   2751     parentObj.FZero = (parentObj.registerA == 0);
   2752     parentObj.FSubtract = true;
   2753   },
   2754   //SBC A, H
   2755   //#0x9C:
   2756   function (parentObj) {
   2757     var temp_var = parentObj.registersHL >> 8;
   2758     var dirtySum = parentObj.registerA - temp_var - ((parentObj.FCarry) ? 1 : 0);
   2759     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (temp_var & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
   2760     parentObj.FCarry = (dirtySum < 0);
   2761     parentObj.registerA = dirtySum & 0xFF;
   2762     parentObj.FZero = (parentObj.registerA == 0);
   2763     parentObj.FSubtract = true;
   2764   },
   2765   //SBC A, L
   2766   //#0x9D:
   2767   function (parentObj) {
   2768     var dirtySum = parentObj.registerA - (parentObj.registersHL & 0xFF) - ((parentObj.FCarry) ? 1 : 0);
   2769     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (parentObj.registersHL & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
   2770     parentObj.FCarry = (dirtySum < 0);
   2771     parentObj.registerA = dirtySum & 0xFF;
   2772     parentObj.FZero = (parentObj.registerA == 0);
   2773     parentObj.FSubtract = true;
   2774   },
   2775   //SBC A, (HL)
   2776   //#0x9E:
   2777   function (parentObj) {
   2778     var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2779     var dirtySum = parentObj.registerA - temp_var - ((parentObj.FCarry) ? 1 : 0);
   2780     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (temp_var & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
   2781     parentObj.FCarry = (dirtySum < 0);
   2782     parentObj.registerA = dirtySum & 0xFF;
   2783     parentObj.FZero = (parentObj.registerA == 0);
   2784     parentObj.FSubtract = true;
   2785   },
   2786   //SBC A, A
   2787   //#0x9F:
   2788   function (parentObj) {
   2789     //Optimized SBC A:
   2790     if (parentObj.FCarry) {
   2791       parentObj.FZero = false;
   2792       parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = true;
   2793       parentObj.registerA = 0xFF;
   2794     }
   2795     else {
   2796       parentObj.FHalfCarry = parentObj.FCarry = false;
   2797       parentObj.FSubtract = parentObj.FZero = true;
   2798       parentObj.registerA = 0;
   2799     }
   2800   },
   2801   //AND B
   2802   //#0xA0:
   2803   function (parentObj) {
   2804     parentObj.registerA &= parentObj.registerB;
   2805     parentObj.FZero = (parentObj.registerA == 0);
   2806     parentObj.FHalfCarry = true;
   2807     parentObj.FSubtract = parentObj.FCarry = false;
   2808   },
   2809   //AND C
   2810   //#0xA1:
   2811   function (parentObj) {
   2812     parentObj.registerA &= parentObj.registerC;
   2813     parentObj.FZero = (parentObj.registerA == 0);
   2814     parentObj.FHalfCarry = true;
   2815     parentObj.FSubtract = parentObj.FCarry = false;
   2816   },
   2817   //AND D
   2818   //#0xA2:
   2819   function (parentObj) {
   2820     parentObj.registerA &= parentObj.registerD;
   2821     parentObj.FZero = (parentObj.registerA == 0);
   2822     parentObj.FHalfCarry = true;
   2823     parentObj.FSubtract = parentObj.FCarry = false;
   2824   },
   2825   //AND E
   2826   //#0xA3:
   2827   function (parentObj) {
   2828     parentObj.registerA &= parentObj.registerE;
   2829     parentObj.FZero = (parentObj.registerA == 0);
   2830     parentObj.FHalfCarry = true;
   2831     parentObj.FSubtract = parentObj.FCarry = false;
   2832   },
   2833   //AND H
   2834   //#0xA4:
   2835   function (parentObj) {
   2836     parentObj.registerA &= (parentObj.registersHL >> 8);
   2837     parentObj.FZero = (parentObj.registerA == 0);
   2838     parentObj.FHalfCarry = true;
   2839     parentObj.FSubtract = parentObj.FCarry = false;
   2840   },
   2841   //AND L
   2842   //#0xA5:
   2843   function (parentObj) {
   2844     parentObj.registerA &= parentObj.registersHL;
   2845     parentObj.FZero = (parentObj.registerA == 0);
   2846     parentObj.FHalfCarry = true;
   2847     parentObj.FSubtract = parentObj.FCarry = false;
   2848   },
   2849   //AND (HL)
   2850   //#0xA6:
   2851   function (parentObj) {
   2852     parentObj.registerA &= parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2853     parentObj.FZero = (parentObj.registerA == 0);
   2854     parentObj.FHalfCarry = true;
   2855     parentObj.FSubtract = parentObj.FCarry = false;
   2856   },
   2857   //AND A
   2858   //#0xA7:
   2859   function (parentObj) {
   2860     //number & same number = same number
   2861     parentObj.FZero = (parentObj.registerA == 0);
   2862     parentObj.FHalfCarry = true;
   2863     parentObj.FSubtract = parentObj.FCarry = false;
   2864   },
   2865   //XOR B
   2866   //#0xA8:
   2867   function (parentObj) {
   2868     parentObj.registerA ^= parentObj.registerB;
   2869     parentObj.FZero = (parentObj.registerA == 0);
   2870     parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
   2871   },
   2872   //XOR C
   2873   //#0xA9:
   2874   function (parentObj) {
   2875     parentObj.registerA ^= parentObj.registerC;
   2876     parentObj.FZero = (parentObj.registerA == 0);
   2877     parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
   2878   },
   2879   //XOR D
   2880   //#0xAA:
   2881   function (parentObj) {
   2882     parentObj.registerA ^= parentObj.registerD;
   2883     parentObj.FZero = (parentObj.registerA == 0);
   2884     parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
   2885   },
   2886   //XOR E
   2887   //#0xAB:
   2888   function (parentObj) {
   2889     parentObj.registerA ^= parentObj.registerE;
   2890     parentObj.FZero = (parentObj.registerA == 0);
   2891     parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
   2892   },
   2893   //XOR H
   2894   //#0xAC:
   2895   function (parentObj) {
   2896     parentObj.registerA ^= (parentObj.registersHL >> 8);
   2897     parentObj.FZero = (parentObj.registerA == 0);
   2898     parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
   2899   },
   2900   //XOR L
   2901   //#0xAD:
   2902   function (parentObj) {
   2903     parentObj.registerA ^= (parentObj.registersHL & 0xFF);
   2904     parentObj.FZero = (parentObj.registerA == 0);
   2905     parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
   2906   },
   2907   //XOR (HL)
   2908   //#0xAE:
   2909   function (parentObj) {
   2910     parentObj.registerA ^= parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2911     parentObj.FZero = (parentObj.registerA == 0);
   2912     parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
   2913   },
   2914   //XOR A
   2915   //#0xAF:
   2916   function (parentObj) {
   2917     //number ^ same number == 0
   2918     parentObj.registerA = 0;
   2919     parentObj.FZero = true;
   2920     parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
   2921   },
   2922   //OR B
   2923   //#0xB0:
   2924   function (parentObj) {
   2925     parentObj.registerA |= parentObj.registerB;
   2926     parentObj.FZero = (parentObj.registerA == 0);
   2927     parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
   2928   },
   2929   //OR C
   2930   //#0xB1:
   2931   function (parentObj) {
   2932     parentObj.registerA |= parentObj.registerC;
   2933     parentObj.FZero = (parentObj.registerA == 0);
   2934     parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
   2935   },
   2936   //OR D
   2937   //#0xB2:
   2938   function (parentObj) {
   2939     parentObj.registerA |= parentObj.registerD;
   2940     parentObj.FZero = (parentObj.registerA == 0);
   2941     parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
   2942   },
   2943   //OR E
   2944   //#0xB3:
   2945   function (parentObj) {
   2946     parentObj.registerA |= parentObj.registerE;
   2947     parentObj.FZero = (parentObj.registerA == 0);
   2948     parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
   2949   },
   2950   //OR H
   2951   //#0xB4:
   2952   function (parentObj) {
   2953     parentObj.registerA |= (parentObj.registersHL >> 8);
   2954     parentObj.FZero = (parentObj.registerA == 0);
   2955     parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
   2956   },
   2957   //OR L
   2958   //#0xB5:
   2959   function (parentObj) {
   2960     parentObj.registerA |= (parentObj.registersHL & 0xFF);
   2961     parentObj.FZero = (parentObj.registerA == 0);
   2962     parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
   2963   },
   2964   //OR (HL)
   2965   //#0xB6:
   2966   function (parentObj) {
   2967     parentObj.registerA |= parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   2968     parentObj.FZero = (parentObj.registerA == 0);
   2969     parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
   2970   },
   2971   //OR A
   2972   //#0xB7:
   2973   function (parentObj) {
   2974     //number | same number == same number
   2975     parentObj.FZero = (parentObj.registerA == 0);
   2976     parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
   2977   },
   2978   //CP B
   2979   //#0xB8:
   2980   function (parentObj) {
   2981     var dirtySum = parentObj.registerA - parentObj.registerB;
   2982     parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
   2983     parentObj.FCarry = (dirtySum < 0);
   2984     parentObj.FZero = (dirtySum == 0);
   2985     parentObj.FSubtract = true;
   2986   },
   2987   //CP C
   2988   //#0xB9:
   2989   function (parentObj) {
   2990     var dirtySum = parentObj.registerA - parentObj.registerC;
   2991     parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
   2992     parentObj.FCarry = (dirtySum < 0);
   2993     parentObj.FZero = (dirtySum == 0);
   2994     parentObj.FSubtract = true;
   2995   },
   2996   //CP D
   2997   //#0xBA:
   2998   function (parentObj) {
   2999     var dirtySum = parentObj.registerA - parentObj.registerD;
   3000     parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
   3001     parentObj.FCarry = (dirtySum < 0);
   3002     parentObj.FZero = (dirtySum == 0);
   3003     parentObj.FSubtract = true;
   3004   },
   3005   //CP E
   3006   //#0xBB:
   3007   function (parentObj) {
   3008     var dirtySum = parentObj.registerA - parentObj.registerE;
   3009     parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
   3010     parentObj.FCarry = (dirtySum < 0);
   3011     parentObj.FZero = (dirtySum == 0);
   3012     parentObj.FSubtract = true;
   3013   },
   3014   //CP H
   3015   //#0xBC:
   3016   function (parentObj) {
   3017     var dirtySum = parentObj.registerA - (parentObj.registersHL >> 8);
   3018     parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
   3019     parentObj.FCarry = (dirtySum < 0);
   3020     parentObj.FZero = (dirtySum == 0);
   3021     parentObj.FSubtract = true;
   3022   },
   3023   //CP L
   3024   //#0xBD:
   3025   function (parentObj) {
   3026     var dirtySum = parentObj.registerA - (parentObj.registersHL & 0xFF);
   3027     parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
   3028     parentObj.FCarry = (dirtySum < 0);
   3029     parentObj.FZero = (dirtySum == 0);
   3030     parentObj.FSubtract = true;
   3031   },
   3032   //CP (HL)
   3033   //#0xBE:
   3034   function (parentObj) {
   3035     var dirtySum = parentObj.registerA - parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   3036     parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
   3037     parentObj.FCarry = (dirtySum < 0);
   3038     parentObj.FZero = (dirtySum == 0);
   3039     parentObj.FSubtract = true;
   3040   },
   3041   //CP A
   3042   //#0xBF:
   3043   function (parentObj) {
   3044     parentObj.FHalfCarry = parentObj.FCarry = false;
   3045     parentObj.FZero = parentObj.FSubtract = true;
   3046   },
   3047   //RET !FZ
   3048   //#0xC0:
   3049   function (parentObj) {
   3050     if (!parentObj.FZero) {
   3051       parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3052       parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3053       parentObj.CPUTicks += 12;
   3054     }
   3055   },
   3056   //POP BC
   3057   //#0xC1:
   3058   function (parentObj) {
   3059     parentObj.registerC = parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3060     parentObj.registerB = parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF);
   3061     parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3062   },
   3063   //JP !FZ, nn
   3064   //#0xC2:
   3065   function (parentObj) {
   3066     if (!parentObj.FZero) {
   3067       parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3068       parentObj.CPUTicks += 4;
   3069     }
   3070     else {
   3071       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3072     }
   3073   },
   3074   //JP nn
   3075   //#0xC3:
   3076   function (parentObj) {
   3077     parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3078   },
   3079   //CALL !FZ, nn
   3080   //#0xC4:
   3081   function (parentObj) {
   3082     if (!parentObj.FZero) {
   3083       var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3084       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3085       parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3086       parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3087       parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3088       parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3089       parentObj.programCounter = temp_pc;
   3090       parentObj.CPUTicks += 12;
   3091     }
   3092     else {
   3093       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3094     }
   3095   },
   3096   //PUSH BC
   3097   //#0xC5:
   3098   function (parentObj) {
   3099     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3100     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerB);
   3101     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3102     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerC);
   3103   },
   3104   //ADD, n
   3105   //#0xC6:
   3106   function (parentObj) {
   3107     var dirtySum = parentObj.registerA + parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3108     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3109     parentObj.FHalfCarry = ((dirtySum & 0xF) < (parentObj.registerA & 0xF));
   3110     parentObj.FCarry = (dirtySum > 0xFF);
   3111     parentObj.registerA = dirtySum & 0xFF;
   3112     parentObj.FZero = (parentObj.registerA == 0);
   3113     parentObj.FSubtract = false;
   3114   },
   3115   //RST 0
   3116   //#0xC7:
   3117   function (parentObj) {
   3118     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3119     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3120     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3121     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3122     parentObj.programCounter = 0;
   3123   },
   3124   //RET FZ
   3125   //#0xC8:
   3126   function (parentObj) {
   3127     if (parentObj.FZero) {
   3128       parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3129       parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3130       parentObj.CPUTicks += 12;
   3131     }
   3132   },
   3133   //RET
   3134   //#0xC9:
   3135   function (parentObj) {
   3136     parentObj.programCounter =  (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3137     parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3138   },
   3139   //JP FZ, nn
   3140   //#0xCA:
   3141   function (parentObj) {
   3142     if (parentObj.FZero) {
   3143       parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3144       parentObj.CPUTicks += 4;
   3145     }
   3146     else {
   3147       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3148     }
   3149   },
   3150   //Secondary OP Code Set:
   3151   //#0xCB:
   3152   function (parentObj) {
   3153     var opcode = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3154     //Increment the program counter to the next instruction:
   3155     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3156     //Get how many CPU cycles the current 0xCBXX op code counts for:
   3157     parentObj.CPUTicks += parentObj.SecondaryTICKTable[opcode];
   3158     //Execute secondary OP codes for the 0xCB OP code call.
   3159     parentObj.CBOPCODE[opcode](parentObj);
   3160   },
   3161   //CALL FZ, nn
   3162   //#0xCC:
   3163   function (parentObj) {
   3164     if (parentObj.FZero) {
   3165       var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3166       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3167       parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3168       parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3169       parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3170       parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3171       parentObj.programCounter = temp_pc;
   3172       parentObj.CPUTicks += 12;
   3173     }
   3174     else {
   3175       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3176     }
   3177   },
   3178   //CALL nn
   3179   //#0xCD:
   3180   function (parentObj) {
   3181     var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3182     parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3183     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3184     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3185     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3186     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3187     parentObj.programCounter = temp_pc;
   3188   },
   3189   //ADC A, n
   3190   //#0xCE:
   3191   function (parentObj) {
   3192     var tempValue = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3193     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3194     var dirtySum = parentObj.registerA + tempValue + ((parentObj.FCarry) ? 1 : 0);
   3195     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) + (tempValue & 0xF) + ((parentObj.FCarry) ? 1 : 0) > 0xF);
   3196     parentObj.FCarry = (dirtySum > 0xFF);
   3197     parentObj.registerA = dirtySum & 0xFF;
   3198     parentObj.FZero = (parentObj.registerA == 0);
   3199     parentObj.FSubtract = false;
   3200   },
   3201   //RST 0x8
   3202   //#0xCF:
   3203   function (parentObj) {
   3204     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3205     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3206     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3207     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3208     parentObj.programCounter = 0x8;
   3209   },
   3210   //RET !FC
   3211   //#0xD0:
   3212   function (parentObj) {
   3213     if (!parentObj.FCarry) {
   3214       parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3215       parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3216       parentObj.CPUTicks += 12;
   3217     }
   3218   },
   3219   //POP DE
   3220   //#0xD1:
   3221   function (parentObj) {
   3222     parentObj.registerE = parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3223     parentObj.registerD = parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF);
   3224     parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3225   },
   3226   //JP !FC, nn
   3227   //#0xD2:
   3228   function (parentObj) {
   3229     if (!parentObj.FCarry) {
   3230       parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3231       parentObj.CPUTicks += 4;
   3232     }
   3233     else {
   3234       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3235     }
   3236   },
   3237   //0xD3 - Illegal
   3238   //#0xD3:
   3239   function (parentObj) {
   3240     cout("Illegal op code 0xD3 called, pausing emulation.", 2);
   3241     pause();
   3242   },
   3243   //CALL !FC, nn
   3244   //#0xD4:
   3245   function (parentObj) {
   3246     if (!parentObj.FCarry) {
   3247       var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3248       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3249       parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3250       parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3251       parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3252       parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3253       parentObj.programCounter = temp_pc;
   3254       parentObj.CPUTicks += 12;
   3255     }
   3256     else {
   3257       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3258     }
   3259   },
   3260   //PUSH DE
   3261   //#0xD5:
   3262   function (parentObj) {
   3263     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3264     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerD);
   3265     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3266     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerE);
   3267   },
   3268   //SUB A, n
   3269   //#0xD6:
   3270   function (parentObj) {
   3271     var dirtySum = parentObj.registerA - parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3272     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3273     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) < (dirtySum & 0xF));
   3274     parentObj.FCarry = (dirtySum < 0);
   3275     parentObj.registerA = dirtySum & 0xFF;
   3276     parentObj.FZero = (dirtySum == 0);
   3277     parentObj.FSubtract = true;
   3278   },
   3279   //RST 0x10
   3280   //#0xD7:
   3281   function (parentObj) {
   3282     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3283     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3284     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3285     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3286     parentObj.programCounter = 0x10;
   3287   },
   3288   //RET FC
   3289   //#0xD8:
   3290   function (parentObj) {
   3291     if (parentObj.FCarry) {
   3292       parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3293       parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3294       parentObj.CPUTicks += 12;
   3295     }
   3296   },
   3297   //RETI
   3298   //#0xD9:
   3299   function (parentObj) {
   3300     parentObj.programCounter = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3301     parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3302     //Immediate for HALT:
   3303     parentObj.IRQEnableDelay = (parentObj.IRQEnableDelay == 2 || parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) == 0x76) ? 1 : 2;
   3304   },
   3305   //JP FC, nn
   3306   //#0xDA:
   3307   function (parentObj) {
   3308     if (parentObj.FCarry) {
   3309       parentObj.programCounter = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3310       parentObj.CPUTicks += 4;
   3311     }
   3312     else {
   3313       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3314     }
   3315   },
   3316   //0xDB - Illegal
   3317   //#0xDB:
   3318   function (parentObj) {
   3319     cout("Illegal op code 0xDB called, pausing emulation.", 2);
   3320     pause();
   3321   },
   3322   //CALL FC, nn
   3323   //#0xDC:
   3324   function (parentObj) {
   3325     if (parentObj.FCarry) {
   3326       var temp_pc = (parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3327       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3328       parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3329       parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3330       parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3331       parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3332       parentObj.programCounter = temp_pc;
   3333       parentObj.CPUTicks += 12;
   3334     }
   3335     else {
   3336       parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3337     }
   3338   },
   3339   //0xDD - Illegal
   3340   //#0xDD:
   3341   function (parentObj) {
   3342     cout("Illegal op code 0xDD called, pausing emulation.", 2);
   3343     pause();
   3344   },
   3345   //SBC A, n
   3346   //#0xDE:
   3347   function (parentObj) {
   3348     var temp_var = parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3349     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3350     var dirtySum = parentObj.registerA - temp_var - ((parentObj.FCarry) ? 1 : 0);
   3351     parentObj.FHalfCarry = ((parentObj.registerA & 0xF) - (temp_var & 0xF) - ((parentObj.FCarry) ? 1 : 0) < 0);
   3352     parentObj.FCarry = (dirtySum < 0);
   3353     parentObj.registerA = dirtySum & 0xFF;
   3354     parentObj.FZero = (parentObj.registerA == 0);
   3355     parentObj.FSubtract = true;
   3356   },
   3357   //RST 0x18
   3358   //#0xDF:
   3359   function (parentObj) {
   3360     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3361     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3362     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3363     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3364     parentObj.programCounter = 0x18;
   3365   },
   3366   //LDH (n), A
   3367   //#0xE0:
   3368   function (parentObj) {
   3369     parentObj.memoryHighWrite(parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter), parentObj.registerA);
   3370     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3371   },
   3372   //POP HL
   3373   //#0xE1:
   3374   function (parentObj) {
   3375     parentObj.registersHL = (parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3376     parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3377   },
   3378   //LD (0xFF00 + C), A
   3379   //#0xE2:
   3380   function (parentObj) {
   3381     parentObj.memoryHighWriter[parentObj.registerC](parentObj, parentObj.registerC, parentObj.registerA);
   3382   },
   3383   //0xE3 - Illegal
   3384   //#0xE3:
   3385   function (parentObj) {
   3386     cout("Illegal op code 0xE3 called, pausing emulation.", 2);
   3387     pause();
   3388   },
   3389   //0xE4 - Illegal
   3390   //#0xE4:
   3391   function (parentObj) {
   3392     cout("Illegal op code 0xE4 called, pausing emulation.", 2);
   3393     pause();
   3394   },
   3395   //PUSH HL
   3396   //#0xE5:
   3397   function (parentObj) {
   3398     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3399     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registersHL >> 8);
   3400     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3401     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registersHL & 0xFF);
   3402   },
   3403   //AND n
   3404   //#0xE6:
   3405   function (parentObj) {
   3406     parentObj.registerA &= parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3407     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3408     parentObj.FZero = (parentObj.registerA == 0);
   3409     parentObj.FHalfCarry = true;
   3410     parentObj.FSubtract = parentObj.FCarry = false;
   3411   },
   3412   //RST 0x20
   3413   //#0xE7:
   3414   function (parentObj) {
   3415     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3416     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3417     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3418     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3419     parentObj.programCounter = 0x20;
   3420   },
   3421   //ADD SP, n
   3422   //#0xE8:
   3423   function (parentObj) {
   3424     var temp_value2 = (parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24;
   3425     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3426     var temp_value = (parentObj.stackPointer + temp_value2) & 0xFFFF;
   3427     temp_value2 = parentObj.stackPointer ^ temp_value2 ^ temp_value;
   3428     parentObj.stackPointer = temp_value;
   3429     parentObj.FCarry = ((temp_value2 & 0x100) == 0x100);
   3430     parentObj.FHalfCarry = ((temp_value2 & 0x10) == 0x10);
   3431     parentObj.FZero = parentObj.FSubtract = false;
   3432   },
   3433   //JP, (HL)
   3434   //#0xE9:
   3435   function (parentObj) {
   3436     parentObj.programCounter = parentObj.registersHL;
   3437   },
   3438   //LD n, A
   3439   //#0xEA:
   3440   function (parentObj) {
   3441     parentObj.memoryWrite((parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter), parentObj.registerA);
   3442     parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3443   },
   3444   //0xEB - Illegal
   3445   //#0xEB:
   3446   function (parentObj) {
   3447     cout("Illegal op code 0xEB called, pausing emulation.", 2);
   3448     pause();
   3449   },
   3450   //0xEC - Illegal
   3451   //#0xEC:
   3452   function (parentObj) {
   3453     cout("Illegal op code 0xEC called, pausing emulation.", 2);
   3454     pause();
   3455   },
   3456   //0xED - Illegal
   3457   //#0xED:
   3458   function (parentObj) {
   3459     cout("Illegal op code 0xED called, pausing emulation.", 2);
   3460     pause();
   3461   },
   3462   //XOR n
   3463   //#0xEE:
   3464   function (parentObj) {
   3465     parentObj.registerA ^= parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3466     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3467     parentObj.FZero = (parentObj.registerA == 0);
   3468     parentObj.FSubtract = parentObj.FHalfCarry = parentObj.FCarry = false;
   3469   },
   3470   //RST 0x28
   3471   //#0xEF:
   3472   function (parentObj) {
   3473     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3474     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3475     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3476     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3477     parentObj.programCounter = 0x28;
   3478   },
   3479   //LDH A, (n)
   3480   //#0xF0:
   3481   function (parentObj) {
   3482     parentObj.registerA = parentObj.memoryHighRead(parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter));
   3483     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3484   },
   3485   //POP AF
   3486   //#0xF1:
   3487   function (parentObj) {
   3488     var temp_var = parentObj.memoryReader[parentObj.stackPointer](parentObj, parentObj.stackPointer);
   3489     parentObj.FZero = (temp_var > 0x7F);
   3490     parentObj.FSubtract = ((temp_var & 0x40) == 0x40);
   3491     parentObj.FHalfCarry = ((temp_var & 0x20) == 0x20);
   3492     parentObj.FCarry = ((temp_var & 0x10) == 0x10);
   3493     parentObj.registerA = parentObj.memoryRead((parentObj.stackPointer + 1) & 0xFFFF);
   3494     parentObj.stackPointer = (parentObj.stackPointer + 2) & 0xFFFF;
   3495   },
   3496   //LD A, (0xFF00 + C)
   3497   //#0xF2:
   3498   function (parentObj) {
   3499     parentObj.registerA = parentObj.memoryHighReader[parentObj.registerC](parentObj, parentObj.registerC);
   3500   },
   3501   //DI
   3502   //#0xF3:
   3503   function (parentObj) {
   3504     parentObj.IME = false;
   3505     parentObj.IRQEnableDelay = 0;
   3506   },
   3507   //0xF4 - Illegal
   3508   //#0xF4:
   3509   function (parentObj) {
   3510     cout("Illegal op code 0xF4 called, pausing emulation.", 2);
   3511     pause();
   3512   },
   3513   //PUSH AF
   3514   //#0xF5:
   3515   function (parentObj) {
   3516     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3517     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.registerA);
   3518     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3519     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, ((parentObj.FZero) ? 0x80 : 0) | ((parentObj.FSubtract) ? 0x40 : 0) | ((parentObj.FHalfCarry) ? 0x20 : 0) | ((parentObj.FCarry) ? 0x10 : 0));
   3520   },
   3521   //OR n
   3522   //#0xF6:
   3523   function (parentObj) {
   3524     parentObj.registerA |= parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3525     parentObj.FZero = (parentObj.registerA == 0);
   3526     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3527     parentObj.FSubtract = parentObj.FCarry = parentObj.FHalfCarry = false;
   3528   },
   3529   //RST 0x30
   3530   //#0xF7:
   3531   function (parentObj) {
   3532     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3533     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3534     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3535     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3536     parentObj.programCounter = 0x30;
   3537   },
   3538   //LDHL SP, n
   3539   //#0xF8:
   3540   function (parentObj) {
   3541     var temp_var = (parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) << 24) >> 24;
   3542     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3543     parentObj.registersHL = (parentObj.stackPointer + temp_var) & 0xFFFF;
   3544     temp_var = parentObj.stackPointer ^ temp_var ^ parentObj.registersHL;
   3545     parentObj.FCarry = ((temp_var & 0x100) == 0x100);
   3546     parentObj.FHalfCarry = ((temp_var & 0x10) == 0x10);
   3547     parentObj.FZero = parentObj.FSubtract = false;
   3548   },
   3549   //LD SP, HL
   3550   //#0xF9:
   3551   function (parentObj) {
   3552     parentObj.stackPointer = parentObj.registersHL;
   3553   },
   3554   //LD A, (nn)
   3555   //#0xFA:
   3556   function (parentObj) {
   3557     parentObj.registerA = parentObj.memoryRead((parentObj.memoryRead((parentObj.programCounter + 1) & 0xFFFF) << 8) | parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter));
   3558     parentObj.programCounter = (parentObj.programCounter + 2) & 0xFFFF;
   3559   },
   3560   //EI
   3561   //#0xFB:
   3562   function (parentObj) {
   3563     //Immediate for HALT:
   3564     parentObj.IRQEnableDelay = (parentObj.IRQEnableDelay == 2 || parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter) == 0x76) ? 1 : 2;
   3565   },
   3566   //0xFC - Illegal
   3567   //#0xFC:
   3568   function (parentObj) {
   3569     cout("Illegal op code 0xFC called, pausing emulation.", 2);
   3570     pause();
   3571   },
   3572   //0xFD - Illegal
   3573   //#0xFD:
   3574   function (parentObj) {
   3575     cout("Illegal op code 0xFD called, pausing emulation.", 2);
   3576     pause();
   3577   },
   3578   //CP n
   3579   //#0xFE:
   3580   function (parentObj) {
   3581     var dirtySum = parentObj.registerA - parentObj.memoryReader[parentObj.programCounter](parentObj, parentObj.programCounter);
   3582     parentObj.programCounter = (parentObj.programCounter + 1) & 0xFFFF;
   3583     parentObj.FHalfCarry = ((dirtySum & 0xF) > (parentObj.registerA & 0xF));
   3584     parentObj.FCarry = (dirtySum < 0);
   3585     parentObj.FZero = (dirtySum == 0);
   3586     parentObj.FSubtract = true;
   3587   },
   3588   //RST 0x38
   3589   //#0xFF:
   3590   function (parentObj) {
   3591     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3592     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter >> 8);
   3593     parentObj.stackPointer = (parentObj.stackPointer - 1) & 0xFFFF;
   3594     parentObj.memoryWriter[parentObj.stackPointer](parentObj, parentObj.stackPointer, parentObj.programCounter & 0xFF);
   3595     parentObj.programCounter = 0x38;
   3596   }
   3597 ];
   3598 GameBoyCore.prototype.CBOPCODE = [
   3599   //RLC B
   3600   //#0x00:
   3601   function (parentObj) {
   3602     parentObj.FCarry = (parentObj.registerB > 0x7F);
   3603     parentObj.registerB = ((parentObj.registerB << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3604     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3605     parentObj.FZero = (parentObj.registerB == 0);
   3606   }
   3607   //RLC C
   3608   //#0x01:
   3609   ,function (parentObj) {
   3610     parentObj.FCarry = (parentObj.registerC > 0x7F);
   3611     parentObj.registerC = ((parentObj.registerC << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3612     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3613     parentObj.FZero = (parentObj.registerC == 0);
   3614   }
   3615   //RLC D
   3616   //#0x02:
   3617   ,function (parentObj) {
   3618     parentObj.FCarry = (parentObj.registerD > 0x7F);
   3619     parentObj.registerD = ((parentObj.registerD << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3620     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3621     parentObj.FZero = (parentObj.registerD == 0);
   3622   }
   3623   //RLC E
   3624   //#0x03:
   3625   ,function (parentObj) {
   3626     parentObj.FCarry = (parentObj.registerE > 0x7F);
   3627     parentObj.registerE = ((parentObj.registerE << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3628     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3629     parentObj.FZero = (parentObj.registerE == 0);
   3630   }
   3631   //RLC H
   3632   //#0x04:
   3633   ,function (parentObj) {
   3634     parentObj.FCarry = (parentObj.registersHL > 0x7FFF);
   3635     parentObj.registersHL = ((parentObj.registersHL << 1) & 0xFE00) | ((parentObj.FCarry) ? 0x100 : 0) | (parentObj.registersHL & 0xFF);
   3636     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3637     parentObj.FZero = (parentObj.registersHL < 0x100);
   3638   }
   3639   //RLC L
   3640   //#0x05:
   3641   ,function (parentObj) {
   3642     parentObj.FCarry = ((parentObj.registersHL & 0x80) == 0x80);
   3643     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3644     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3645     parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
   3646   }
   3647   //RLC (HL)
   3648   //#0x06:
   3649   ,function (parentObj) {
   3650     var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   3651     parentObj.FCarry = (temp_var > 0x7F);
   3652     temp_var = ((temp_var << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3653     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
   3654     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3655     parentObj.FZero = (temp_var == 0);
   3656   }
   3657   //RLC A
   3658   //#0x07:
   3659   ,function (parentObj) {
   3660     parentObj.FCarry = (parentObj.registerA > 0x7F);
   3661     parentObj.registerA = ((parentObj.registerA << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3662     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3663     parentObj.FZero = (parentObj.registerA == 0);
   3664   }
   3665   //RRC B
   3666   //#0x08:
   3667   ,function (parentObj) {
   3668     parentObj.FCarry = ((parentObj.registerB & 0x01) == 0x01);
   3669     parentObj.registerB = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerB >> 1);
   3670     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3671     parentObj.FZero = (parentObj.registerB == 0);
   3672   }
   3673   //RRC C
   3674   //#0x09:
   3675   ,function (parentObj) {
   3676     parentObj.FCarry = ((parentObj.registerC & 0x01) == 0x01);
   3677     parentObj.registerC = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerC >> 1);
   3678     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3679     parentObj.FZero = (parentObj.registerC == 0);
   3680   }
   3681   //RRC D
   3682   //#0x0A:
   3683   ,function (parentObj) {
   3684     parentObj.FCarry = ((parentObj.registerD & 0x01) == 0x01);
   3685     parentObj.registerD = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerD >> 1);
   3686     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3687     parentObj.FZero = (parentObj.registerD == 0);
   3688   }
   3689   //RRC E
   3690   //#0x0B:
   3691   ,function (parentObj) {
   3692     parentObj.FCarry = ((parentObj.registerE & 0x01) == 0x01);
   3693     parentObj.registerE = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerE >> 1);
   3694     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3695     parentObj.FZero = (parentObj.registerE == 0);
   3696   }
   3697   //RRC H
   3698   //#0x0C:
   3699   ,function (parentObj) {
   3700     parentObj.FCarry = ((parentObj.registersHL & 0x0100) == 0x0100);
   3701     parentObj.registersHL = ((parentObj.FCarry) ? 0x8000 : 0) | ((parentObj.registersHL >> 1) & 0xFF00) | (parentObj.registersHL & 0xFF);
   3702     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3703     parentObj.FZero = (parentObj.registersHL < 0x100);
   3704   }
   3705   //RRC L
   3706   //#0x0D:
   3707   ,function (parentObj) {
   3708     parentObj.FCarry = ((parentObj.registersHL & 0x01) == 0x01);
   3709     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.FCarry) ? 0x80 : 0) | ((parentObj.registersHL & 0xFF) >> 1);
   3710     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3711     parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
   3712   }
   3713   //RRC (HL)
   3714   //#0x0E:
   3715   ,function (parentObj) {
   3716     var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   3717     parentObj.FCarry = ((temp_var & 0x01) == 0x01);
   3718     temp_var = ((parentObj.FCarry) ? 0x80 : 0) | (temp_var >> 1);
   3719     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
   3720     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3721     parentObj.FZero = (temp_var == 0);
   3722   }
   3723   //RRC A
   3724   //#0x0F:
   3725   ,function (parentObj) {
   3726     parentObj.FCarry = ((parentObj.registerA & 0x01) == 0x01);
   3727     parentObj.registerA = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerA >> 1);
   3728     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3729     parentObj.FZero = (parentObj.registerA == 0);
   3730   }
   3731   //RL B
   3732   //#0x10:
   3733   ,function (parentObj) {
   3734     var newFCarry = (parentObj.registerB > 0x7F);
   3735     parentObj.registerB = ((parentObj.registerB << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3736     parentObj.FCarry = newFCarry;
   3737     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3738     parentObj.FZero = (parentObj.registerB == 0);
   3739   }
   3740   //RL C
   3741   //#0x11:
   3742   ,function (parentObj) {
   3743     var newFCarry = (parentObj.registerC > 0x7F);
   3744     parentObj.registerC = ((parentObj.registerC << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3745     parentObj.FCarry = newFCarry;
   3746     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3747     parentObj.FZero = (parentObj.registerC == 0);
   3748   }
   3749   //RL D
   3750   //#0x12:
   3751   ,function (parentObj) {
   3752     var newFCarry = (parentObj.registerD > 0x7F);
   3753     parentObj.registerD = ((parentObj.registerD << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3754     parentObj.FCarry = newFCarry;
   3755     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3756     parentObj.FZero = (parentObj.registerD == 0);
   3757   }
   3758   //RL E
   3759   //#0x13:
   3760   ,function (parentObj) {
   3761     var newFCarry = (parentObj.registerE > 0x7F);
   3762     parentObj.registerE = ((parentObj.registerE << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3763     parentObj.FCarry = newFCarry;
   3764     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3765     parentObj.FZero = (parentObj.registerE == 0);
   3766   }
   3767   //RL H
   3768   //#0x14:
   3769   ,function (parentObj) {
   3770     var newFCarry = (parentObj.registersHL > 0x7FFF);
   3771     parentObj.registersHL = ((parentObj.registersHL << 1) & 0xFE00) | ((parentObj.FCarry) ? 0x100 : 0) | (parentObj.registersHL & 0xFF);
   3772     parentObj.FCarry = newFCarry;
   3773     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3774     parentObj.FZero = (parentObj.registersHL < 0x100);
   3775   }
   3776   //RL L
   3777   //#0x15:
   3778   ,function (parentObj) {
   3779     var newFCarry = ((parentObj.registersHL & 0x80) == 0x80);
   3780     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3781     parentObj.FCarry = newFCarry;
   3782     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3783     parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
   3784   }
   3785   //RL (HL)
   3786   //#0x16:
   3787   ,function (parentObj) {
   3788     var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   3789     var newFCarry = (temp_var > 0x7F);
   3790     temp_var = ((temp_var << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3791     parentObj.FCarry = newFCarry;
   3792     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
   3793     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3794     parentObj.FZero = (temp_var == 0);
   3795   }
   3796   //RL A
   3797   //#0x17:
   3798   ,function (parentObj) {
   3799     var newFCarry = (parentObj.registerA > 0x7F);
   3800     parentObj.registerA = ((parentObj.registerA << 1) & 0xFF) | ((parentObj.FCarry) ? 1 : 0);
   3801     parentObj.FCarry = newFCarry;
   3802     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3803     parentObj.FZero = (parentObj.registerA == 0);
   3804   }
   3805   //RR B
   3806   //#0x18:
   3807   ,function (parentObj) {
   3808     var newFCarry = ((parentObj.registerB & 0x01) == 0x01);
   3809     parentObj.registerB = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerB >> 1);
   3810     parentObj.FCarry = newFCarry;
   3811     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3812     parentObj.FZero = (parentObj.registerB == 0);
   3813   }
   3814   //RR C
   3815   //#0x19:
   3816   ,function (parentObj) {
   3817     var newFCarry = ((parentObj.registerC & 0x01) == 0x01);
   3818     parentObj.registerC = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerC >> 1);
   3819     parentObj.FCarry = newFCarry;
   3820     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3821     parentObj.FZero = (parentObj.registerC == 0);
   3822   }
   3823   //RR D
   3824   //#0x1A:
   3825   ,function (parentObj) {
   3826     var newFCarry = ((parentObj.registerD & 0x01) == 0x01);
   3827     parentObj.registerD = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerD >> 1);
   3828     parentObj.FCarry = newFCarry;
   3829     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3830     parentObj.FZero = (parentObj.registerD == 0);
   3831   }
   3832   //RR E
   3833   //#0x1B:
   3834   ,function (parentObj) {
   3835     var newFCarry = ((parentObj.registerE & 0x01) == 0x01);
   3836     parentObj.registerE = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerE >> 1);
   3837     parentObj.FCarry = newFCarry;
   3838     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3839     parentObj.FZero = (parentObj.registerE == 0);
   3840   }
   3841   //RR H
   3842   //#0x1C:
   3843   ,function (parentObj) {
   3844     var newFCarry = ((parentObj.registersHL & 0x0100) == 0x0100);
   3845     parentObj.registersHL = ((parentObj.FCarry) ? 0x8000 : 0) | ((parentObj.registersHL >> 1) & 0xFF00) | (parentObj.registersHL & 0xFF);
   3846     parentObj.FCarry = newFCarry;
   3847     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3848     parentObj.FZero = (parentObj.registersHL < 0x100);
   3849   }
   3850   //RR L
   3851   //#0x1D:
   3852   ,function (parentObj) {
   3853     var newFCarry = ((parentObj.registersHL & 0x01) == 0x01);
   3854     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.FCarry) ? 0x80 : 0) | ((parentObj.registersHL & 0xFF) >> 1);
   3855     parentObj.FCarry = newFCarry;
   3856     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3857     parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
   3858   }
   3859   //RR (HL)
   3860   //#0x1E:
   3861   ,function (parentObj) {
   3862     var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   3863     var newFCarry = ((temp_var & 0x01) == 0x01);
   3864     temp_var = ((parentObj.FCarry) ? 0x80 : 0) | (temp_var >> 1);
   3865     parentObj.FCarry = newFCarry;
   3866     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
   3867     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3868     parentObj.FZero = (temp_var == 0);
   3869   }
   3870   //RR A
   3871   //#0x1F:
   3872   ,function (parentObj) {
   3873     var newFCarry = ((parentObj.registerA & 0x01) == 0x01);
   3874     parentObj.registerA = ((parentObj.FCarry) ? 0x80 : 0) | (parentObj.registerA >> 1);
   3875     parentObj.FCarry = newFCarry;
   3876     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3877     parentObj.FZero = (parentObj.registerA == 0);
   3878   }
   3879   //SLA B
   3880   //#0x20:
   3881   ,function (parentObj) {
   3882     parentObj.FCarry = (parentObj.registerB > 0x7F);
   3883     parentObj.registerB = (parentObj.registerB << 1) & 0xFF;
   3884     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3885     parentObj.FZero = (parentObj.registerB == 0);
   3886   }
   3887   //SLA C
   3888   //#0x21:
   3889   ,function (parentObj) {
   3890     parentObj.FCarry = (parentObj.registerC > 0x7F);
   3891     parentObj.registerC = (parentObj.registerC << 1) & 0xFF;
   3892     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3893     parentObj.FZero = (parentObj.registerC == 0);
   3894   }
   3895   //SLA D
   3896   //#0x22:
   3897   ,function (parentObj) {
   3898     parentObj.FCarry = (parentObj.registerD > 0x7F);
   3899     parentObj.registerD = (parentObj.registerD << 1) & 0xFF;
   3900     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3901     parentObj.FZero = (parentObj.registerD == 0);
   3902   }
   3903   //SLA E
   3904   //#0x23:
   3905   ,function (parentObj) {
   3906     parentObj.FCarry = (parentObj.registerE > 0x7F);
   3907     parentObj.registerE = (parentObj.registerE << 1) & 0xFF;
   3908     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3909     parentObj.FZero = (parentObj.registerE == 0);
   3910   }
   3911   //SLA H
   3912   //#0x24:
   3913   ,function (parentObj) {
   3914     parentObj.FCarry = (parentObj.registersHL > 0x7FFF);
   3915     parentObj.registersHL = ((parentObj.registersHL << 1) & 0xFE00) | (parentObj.registersHL & 0xFF);
   3916     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3917     parentObj.FZero = (parentObj.registersHL < 0x100);
   3918   }
   3919   //SLA L
   3920   //#0x25:
   3921   ,function (parentObj) {
   3922     parentObj.FCarry = ((parentObj.registersHL & 0x0080) == 0x0080);
   3923     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL << 1) & 0xFF);
   3924     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3925     parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
   3926   }
   3927   //SLA (HL)
   3928   //#0x26:
   3929   ,function (parentObj) {
   3930     var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   3931     parentObj.FCarry = (temp_var > 0x7F);
   3932     temp_var = (temp_var << 1) & 0xFF;
   3933     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
   3934     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3935     parentObj.FZero = (temp_var == 0);
   3936   }
   3937   //SLA A
   3938   //#0x27:
   3939   ,function (parentObj) {
   3940     parentObj.FCarry = (parentObj.registerA > 0x7F);
   3941     parentObj.registerA = (parentObj.registerA << 1) & 0xFF;
   3942     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3943     parentObj.FZero = (parentObj.registerA == 0);
   3944   }
   3945   //SRA B
   3946   //#0x28:
   3947   ,function (parentObj) {
   3948     parentObj.FCarry = ((parentObj.registerB & 0x01) == 0x01);
   3949     parentObj.registerB = (parentObj.registerB & 0x80) | (parentObj.registerB >> 1);
   3950     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3951     parentObj.FZero = (parentObj.registerB == 0);
   3952   }
   3953   //SRA C
   3954   //#0x29:
   3955   ,function (parentObj) {
   3956     parentObj.FCarry = ((parentObj.registerC & 0x01) == 0x01);
   3957     parentObj.registerC = (parentObj.registerC & 0x80) | (parentObj.registerC >> 1);
   3958     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3959     parentObj.FZero = (parentObj.registerC == 0);
   3960   }
   3961   //SRA D
   3962   //#0x2A:
   3963   ,function (parentObj) {
   3964     parentObj.FCarry = ((parentObj.registerD & 0x01) == 0x01);
   3965     parentObj.registerD = (parentObj.registerD & 0x80) | (parentObj.registerD >> 1);
   3966     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3967     parentObj.FZero = (parentObj.registerD == 0);
   3968   }
   3969   //SRA E
   3970   //#0x2B:
   3971   ,function (parentObj) {
   3972     parentObj.FCarry = ((parentObj.registerE & 0x01) == 0x01);
   3973     parentObj.registerE = (parentObj.registerE & 0x80) | (parentObj.registerE >> 1);
   3974     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3975     parentObj.FZero = (parentObj.registerE == 0);
   3976   }
   3977   //SRA H
   3978   //#0x2C:
   3979   ,function (parentObj) {
   3980     parentObj.FCarry = ((parentObj.registersHL & 0x0100) == 0x0100);
   3981     parentObj.registersHL = ((parentObj.registersHL >> 1) & 0xFF00) | (parentObj.registersHL & 0x80FF);
   3982     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3983     parentObj.FZero = (parentObj.registersHL < 0x100);
   3984   }
   3985   //SRA L
   3986   //#0x2D:
   3987   ,function (parentObj) {
   3988     parentObj.FCarry = ((parentObj.registersHL & 0x0001) == 0x0001);
   3989     parentObj.registersHL = (parentObj.registersHL & 0xFF80) | ((parentObj.registersHL & 0xFF) >> 1);
   3990     parentObj.FHalfCarry = parentObj.FSubtract = false;
   3991     parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
   3992   }
   3993   //SRA (HL)
   3994   //#0x2E:
   3995   ,function (parentObj) {
   3996     var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   3997     parentObj.FCarry = ((temp_var & 0x01) == 0x01);
   3998     temp_var = (temp_var & 0x80) | (temp_var >> 1);
   3999     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
   4000     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4001     parentObj.FZero = (temp_var == 0);
   4002   }
   4003   //SRA A
   4004   //#0x2F:
   4005   ,function (parentObj) {
   4006     parentObj.FCarry = ((parentObj.registerA & 0x01) == 0x01);
   4007     parentObj.registerA = (parentObj.registerA & 0x80) | (parentObj.registerA >> 1);
   4008     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4009     parentObj.FZero = (parentObj.registerA == 0);
   4010   }
   4011   //SWAP B
   4012   //#0x30:
   4013   ,function (parentObj) {
   4014     parentObj.registerB = ((parentObj.registerB & 0xF) << 4) | (parentObj.registerB >> 4);
   4015     parentObj.FZero = (parentObj.registerB == 0);
   4016     parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
   4017   }
   4018   //SWAP C
   4019   //#0x31:
   4020   ,function (parentObj) {
   4021     parentObj.registerC = ((parentObj.registerC & 0xF) << 4) | (parentObj.registerC >> 4);
   4022     parentObj.FZero = (parentObj.registerC == 0);
   4023     parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
   4024   }
   4025   //SWAP D
   4026   //#0x32:
   4027   ,function (parentObj) {
   4028     parentObj.registerD = ((parentObj.registerD & 0xF) << 4) | (parentObj.registerD >> 4);
   4029     parentObj.FZero = (parentObj.registerD == 0);
   4030     parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
   4031   }
   4032   //SWAP E
   4033   //#0x33:
   4034   ,function (parentObj) {
   4035     parentObj.registerE = ((parentObj.registerE & 0xF) << 4) | (parentObj.registerE >> 4);
   4036     parentObj.FZero = (parentObj.registerE == 0);
   4037     parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
   4038   }
   4039   //SWAP H
   4040   //#0x34:
   4041   ,function (parentObj) {
   4042     parentObj.registersHL = ((parentObj.registersHL & 0xF00) << 4) | ((parentObj.registersHL & 0xF000) >> 4) | (parentObj.registersHL & 0xFF);
   4043     parentObj.FZero = (parentObj.registersHL < 0x100);
   4044     parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
   4045   }
   4046   //SWAP L
   4047   //#0x35:
   4048   ,function (parentObj) {
   4049     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL & 0xF) << 4) | ((parentObj.registersHL & 0xF0) >> 4);
   4050     parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
   4051     parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
   4052   }
   4053   //SWAP (HL)
   4054   //#0x36:
   4055   ,function (parentObj) {
   4056     var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   4057     temp_var = ((temp_var & 0xF) << 4) | (temp_var >> 4);
   4058     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var);
   4059     parentObj.FZero = (temp_var == 0);
   4060     parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
   4061   }
   4062   //SWAP A
   4063   //#0x37:
   4064   ,function (parentObj) {
   4065     parentObj.registerA = ((parentObj.registerA & 0xF) << 4) | (parentObj.registerA >> 4);
   4066     parentObj.FZero = (parentObj.registerA == 0);
   4067     parentObj.FCarry = parentObj.FHalfCarry = parentObj.FSubtract = false;
   4068   }
   4069   //SRL B
   4070   //#0x38:
   4071   ,function (parentObj) {
   4072     parentObj.FCarry = ((parentObj.registerB & 0x01) == 0x01);
   4073     parentObj.registerB >>= 1;
   4074     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4075     parentObj.FZero = (parentObj.registerB == 0);
   4076   }
   4077   //SRL C
   4078   //#0x39:
   4079   ,function (parentObj) {
   4080     parentObj.FCarry = ((parentObj.registerC & 0x01) == 0x01);
   4081     parentObj.registerC >>= 1;
   4082     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4083     parentObj.FZero = (parentObj.registerC == 0);
   4084   }
   4085   //SRL D
   4086   //#0x3A:
   4087   ,function (parentObj) {
   4088     parentObj.FCarry = ((parentObj.registerD & 0x01) == 0x01);
   4089     parentObj.registerD >>= 1;
   4090     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4091     parentObj.FZero = (parentObj.registerD == 0);
   4092   }
   4093   //SRL E
   4094   //#0x3B:
   4095   ,function (parentObj) {
   4096     parentObj.FCarry = ((parentObj.registerE & 0x01) == 0x01);
   4097     parentObj.registerE >>= 1;
   4098     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4099     parentObj.FZero = (parentObj.registerE == 0);
   4100   }
   4101   //SRL H
   4102   //#0x3C:
   4103   ,function (parentObj) {
   4104     parentObj.FCarry = ((parentObj.registersHL & 0x0100) == 0x0100);
   4105     parentObj.registersHL = ((parentObj.registersHL >> 1) & 0xFF00) | (parentObj.registersHL & 0xFF);
   4106     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4107     parentObj.FZero = (parentObj.registersHL < 0x100);
   4108   }
   4109   //SRL L
   4110   //#0x3D:
   4111   ,function (parentObj) {
   4112     parentObj.FCarry = ((parentObj.registersHL & 0x0001) == 0x0001);
   4113     parentObj.registersHL = (parentObj.registersHL & 0xFF00) | ((parentObj.registersHL & 0xFF) >> 1);
   4114     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4115     parentObj.FZero = ((parentObj.registersHL & 0xFF) == 0);
   4116   }
   4117   //SRL (HL)
   4118   //#0x3E:
   4119   ,function (parentObj) {
   4120     var temp_var = parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL);
   4121     parentObj.FCarry = ((temp_var & 0x01) == 0x01);
   4122     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, temp_var >> 1);
   4123     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4124     parentObj.FZero = (temp_var < 2);
   4125   }
   4126   //SRL A
   4127   //#0x3F:
   4128   ,function (parentObj) {
   4129     parentObj.FCarry = ((parentObj.registerA & 0x01) == 0x01);
   4130     parentObj.registerA >>= 1;
   4131     parentObj.FHalfCarry = parentObj.FSubtract = false;
   4132     parentObj.FZero = (parentObj.registerA == 0);
   4133   }
   4134   //BIT 0, B
   4135   //#0x40:
   4136   ,function (parentObj) {
   4137     parentObj.FHalfCarry = true;
   4138     parentObj.FSubtract = false;
   4139     parentObj.FZero = ((parentObj.registerB & 0x01) == 0);
   4140   }
   4141   //BIT 0, C
   4142   //#0x41:
   4143   ,function (parentObj) {
   4144     parentObj.FHalfCarry = true;
   4145     parentObj.FSubtract = false;
   4146     parentObj.FZero = ((parentObj.registerC & 0x01) == 0);
   4147   }
   4148   //BIT 0, D
   4149   //#0x42:
   4150   ,function (parentObj) {
   4151     parentObj.FHalfCarry = true;
   4152     parentObj.FSubtract = false;
   4153     parentObj.FZero = ((parentObj.registerD & 0x01) == 0);
   4154   }
   4155   //BIT 0, E
   4156   //#0x43:
   4157   ,function (parentObj) {
   4158     parentObj.FHalfCarry = true;
   4159     parentObj.FSubtract = false;
   4160     parentObj.FZero = ((parentObj.registerE & 0x01) == 0);
   4161   }
   4162   //BIT 0, H
   4163   //#0x44:
   4164   ,function (parentObj) {
   4165     parentObj.FHalfCarry = true;
   4166     parentObj.FSubtract = false;
   4167     parentObj.FZero = ((parentObj.registersHL & 0x0100) == 0);
   4168   }
   4169   //BIT 0, L
   4170   //#0x45:
   4171   ,function (parentObj) {
   4172     parentObj.FHalfCarry = true;
   4173     parentObj.FSubtract = false;
   4174     parentObj.FZero = ((parentObj.registersHL & 0x0001) == 0);
   4175   }
   4176   //BIT 0, (HL)
   4177   //#0x46:
   4178   ,function (parentObj) {
   4179     parentObj.FHalfCarry = true;
   4180     parentObj.FSubtract = false;
   4181     parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x01) == 0);
   4182   }
   4183   //BIT 0, A
   4184   //#0x47:
   4185   ,function (parentObj) {
   4186     parentObj.FHalfCarry = true;
   4187     parentObj.FSubtract = false;
   4188     parentObj.FZero = ((parentObj.registerA & 0x01) == 0);
   4189   }
   4190   //BIT 1, B
   4191   //#0x48:
   4192   ,function (parentObj) {
   4193     parentObj.FHalfCarry = true;
   4194     parentObj.FSubtract = false;
   4195     parentObj.FZero = ((parentObj.registerB & 0x02) == 0);
   4196   }
   4197   //BIT 1, C
   4198   //#0x49:
   4199   ,function (parentObj) {
   4200     parentObj.FHalfCarry = true;
   4201     parentObj.FSubtract = false;
   4202     parentObj.FZero = ((parentObj.registerC & 0x02) == 0);
   4203   }
   4204   //BIT 1, D
   4205   //#0x4A:
   4206   ,function (parentObj) {
   4207     parentObj.FHalfCarry = true;
   4208     parentObj.FSubtract = false;
   4209     parentObj.FZero = ((parentObj.registerD & 0x02) == 0);
   4210   }
   4211   //BIT 1, E
   4212   //#0x4B:
   4213   ,function (parentObj) {
   4214     parentObj.FHalfCarry = true;
   4215     parentObj.FSubtract = false;
   4216     parentObj.FZero = ((parentObj.registerE & 0x02) == 0);
   4217   }
   4218   //BIT 1, H
   4219   //#0x4C:
   4220   ,function (parentObj) {
   4221     parentObj.FHalfCarry = true;
   4222     parentObj.FSubtract = false;
   4223     parentObj.FZero = ((parentObj.registersHL & 0x0200) == 0);
   4224   }
   4225   //BIT 1, L
   4226   //#0x4D:
   4227   ,function (parentObj) {
   4228     parentObj.FHalfCarry = true;
   4229     parentObj.FSubtract = false;
   4230     parentObj.FZero = ((parentObj.registersHL & 0x0002) == 0);
   4231   }
   4232   //BIT 1, (HL)
   4233   //#0x4E:
   4234   ,function (parentObj) {
   4235     parentObj.FHalfCarry = true;
   4236     parentObj.FSubtract = false;
   4237     parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x02) == 0);
   4238   }
   4239   //BIT 1, A
   4240   //#0x4F:
   4241   ,function (parentObj) {
   4242     parentObj.FHalfCarry = true;
   4243     parentObj.FSubtract = false;
   4244     parentObj.FZero = ((parentObj.registerA & 0x02) == 0);
   4245   }
   4246   //BIT 2, B
   4247   //#0x50:
   4248   ,function (parentObj) {
   4249     parentObj.FHalfCarry = true;
   4250     parentObj.FSubtract = false;
   4251     parentObj.FZero = ((parentObj.registerB & 0x04) == 0);
   4252   }
   4253   //BIT 2, C
   4254   //#0x51:
   4255   ,function (parentObj) {
   4256     parentObj.FHalfCarry = true;
   4257     parentObj.FSubtract = false;
   4258     parentObj.FZero = ((parentObj.registerC & 0x04) == 0);
   4259   }
   4260   //BIT 2, D
   4261   //#0x52:
   4262   ,function (parentObj) {
   4263     parentObj.FHalfCarry = true;
   4264     parentObj.FSubtract = false;
   4265     parentObj.FZero = ((parentObj.registerD & 0x04) == 0);
   4266   }
   4267   //BIT 2, E
   4268   //#0x53:
   4269   ,function (parentObj) {
   4270     parentObj.FHalfCarry = true;
   4271     parentObj.FSubtract = false;
   4272     parentObj.FZero = ((parentObj.registerE & 0x04) == 0);
   4273   }
   4274   //BIT 2, H
   4275   //#0x54:
   4276   ,function (parentObj) {
   4277     parentObj.FHalfCarry = true;
   4278     parentObj.FSubtract = false;
   4279     parentObj.FZero = ((parentObj.registersHL & 0x0400) == 0);
   4280   }
   4281   //BIT 2, L
   4282   //#0x55:
   4283   ,function (parentObj) {
   4284     parentObj.FHalfCarry = true;
   4285     parentObj.FSubtract = false;
   4286     parentObj.FZero = ((parentObj.registersHL & 0x0004) == 0);
   4287   }
   4288   //BIT 2, (HL)
   4289   //#0x56:
   4290   ,function (parentObj) {
   4291     parentObj.FHalfCarry = true;
   4292     parentObj.FSubtract = false;
   4293     parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x04) == 0);
   4294   }
   4295   //BIT 2, A
   4296   //#0x57:
   4297   ,function (parentObj) {
   4298     parentObj.FHalfCarry = true;
   4299     parentObj.FSubtract = false;
   4300     parentObj.FZero = ((parentObj.registerA & 0x04) == 0);
   4301   }
   4302   //BIT 3, B
   4303   //#0x58:
   4304   ,function (parentObj) {
   4305     parentObj.FHalfCarry = true;
   4306     parentObj.FSubtract = false;
   4307     parentObj.FZero = ((parentObj.registerB & 0x08) == 0);
   4308   }
   4309   //BIT 3, C
   4310   //#0x59:
   4311   ,function (parentObj) {
   4312     parentObj.FHalfCarry = true;
   4313     parentObj.FSubtract = false;
   4314     parentObj.FZero = ((parentObj.registerC & 0x08) == 0);
   4315   }
   4316   //BIT 3, D
   4317   //#0x5A:
   4318   ,function (parentObj) {
   4319     parentObj.FHalfCarry = true;
   4320     parentObj.FSubtract = false;
   4321     parentObj.FZero = ((parentObj.registerD & 0x08) == 0);
   4322   }
   4323   //BIT 3, E
   4324   //#0x5B:
   4325   ,function (parentObj) {
   4326     parentObj.FHalfCarry = true;
   4327     parentObj.FSubtract = false;
   4328     parentObj.FZero = ((parentObj.registerE & 0x08) == 0);
   4329   }
   4330   //BIT 3, H
   4331   //#0x5C:
   4332   ,function (parentObj) {
   4333     parentObj.FHalfCarry = true;
   4334     parentObj.FSubtract = false;
   4335     parentObj.FZero = ((parentObj.registersHL & 0x0800) == 0);
   4336   }
   4337   //BIT 3, L
   4338   //#0x5D:
   4339   ,function (parentObj) {
   4340     parentObj.FHalfCarry = true;
   4341     parentObj.FSubtract = false;
   4342     parentObj.FZero = ((parentObj.registersHL & 0x0008) == 0);
   4343   }
   4344   //BIT 3, (HL)
   4345   //#0x5E:
   4346   ,function (parentObj) {
   4347     parentObj.FHalfCarry = true;
   4348     parentObj.FSubtract = false;
   4349     parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x08) == 0);
   4350   }
   4351   //BIT 3, A
   4352   //#0x5F:
   4353   ,function (parentObj) {
   4354     parentObj.FHalfCarry = true;
   4355     parentObj.FSubtract = false;
   4356     parentObj.FZero = ((parentObj.registerA & 0x08) == 0);
   4357   }
   4358   //BIT 4, B
   4359   //#0x60:
   4360   ,function (parentObj) {
   4361     parentObj.FHalfCarry = true;
   4362     parentObj.FSubtract = false;
   4363     parentObj.FZero = ((parentObj.registerB & 0x10) == 0);
   4364   }
   4365   //BIT 4, C
   4366   //#0x61:
   4367   ,function (parentObj) {
   4368     parentObj.FHalfCarry = true;
   4369     parentObj.FSubtract = false;
   4370     parentObj.FZero = ((parentObj.registerC & 0x10) == 0);
   4371   }
   4372   //BIT 4, D
   4373   //#0x62:
   4374   ,function (parentObj) {
   4375     parentObj.FHalfCarry = true;
   4376     parentObj.FSubtract = false;
   4377     parentObj.FZero = ((parentObj.registerD & 0x10) == 0);
   4378   }
   4379   //BIT 4, E
   4380   //#0x63:
   4381   ,function (parentObj) {
   4382     parentObj.FHalfCarry = true;
   4383     parentObj.FSubtract = false;
   4384     parentObj.FZero = ((parentObj.registerE & 0x10) == 0);
   4385   }
   4386   //BIT 4, H
   4387   //#0x64:
   4388   ,function (parentObj) {
   4389     parentObj.FHalfCarry = true;
   4390     parentObj.FSubtract = false;
   4391     parentObj.FZero = ((parentObj.registersHL & 0x1000) == 0);
   4392   }
   4393   //BIT 4, L
   4394   //#0x65:
   4395   ,function (parentObj) {
   4396     parentObj.FHalfCarry = true;
   4397     parentObj.FSubtract = false;
   4398     parentObj.FZero = ((parentObj.registersHL & 0x0010) == 0);
   4399   }
   4400   //BIT 4, (HL)
   4401   //#0x66:
   4402   ,function (parentObj) {
   4403     parentObj.FHalfCarry = true;
   4404     parentObj.FSubtract = false;
   4405     parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x10) == 0);
   4406   }
   4407   //BIT 4, A
   4408   //#0x67:
   4409   ,function (parentObj) {
   4410     parentObj.FHalfCarry = true;
   4411     parentObj.FSubtract = false;
   4412     parentObj.FZero = ((parentObj.registerA & 0x10) == 0);
   4413   }
   4414   //BIT 5, B
   4415   //#0x68:
   4416   ,function (parentObj) {
   4417     parentObj.FHalfCarry = true;
   4418     parentObj.FSubtract = false;
   4419     parentObj.FZero = ((parentObj.registerB & 0x20) == 0);
   4420   }
   4421   //BIT 5, C
   4422   //#0x69:
   4423   ,function (parentObj) {
   4424     parentObj.FHalfCarry = true;
   4425     parentObj.FSubtract = false;
   4426     parentObj.FZero = ((parentObj.registerC & 0x20) == 0);
   4427   }
   4428   //BIT 5, D
   4429   //#0x6A:
   4430   ,function (parentObj) {
   4431     parentObj.FHalfCarry = true;
   4432     parentObj.FSubtract = false;
   4433     parentObj.FZero = ((parentObj.registerD & 0x20) == 0);
   4434   }
   4435   //BIT 5, E
   4436   //#0x6B:
   4437   ,function (parentObj) {
   4438     parentObj.FHalfCarry = true;
   4439     parentObj.FSubtract = false;
   4440     parentObj.FZero = ((parentObj.registerE & 0x20) == 0);
   4441   }
   4442   //BIT 5, H
   4443   //#0x6C:
   4444   ,function (parentObj) {
   4445     parentObj.FHalfCarry = true;
   4446     parentObj.FSubtract = false;
   4447     parentObj.FZero = ((parentObj.registersHL & 0x2000) == 0);
   4448   }
   4449   //BIT 5, L
   4450   //#0x6D:
   4451   ,function (parentObj) {
   4452     parentObj.FHalfCarry = true;
   4453     parentObj.FSubtract = false;
   4454     parentObj.FZero = ((parentObj.registersHL & 0x0020) == 0);
   4455   }
   4456   //BIT 5, (HL)
   4457   //#0x6E:
   4458   ,function (parentObj) {
   4459     parentObj.FHalfCarry = true;
   4460     parentObj.FSubtract = false;
   4461     parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x20) == 0);
   4462   }
   4463   //BIT 5, A
   4464   //#0x6F:
   4465   ,function (parentObj) {
   4466     parentObj.FHalfCarry = true;
   4467     parentObj.FSubtract = false;
   4468     parentObj.FZero = ((parentObj.registerA & 0x20) == 0);
   4469   }
   4470   //BIT 6, B
   4471   //#0x70:
   4472   ,function (parentObj) {
   4473     parentObj.FHalfCarry = true;
   4474     parentObj.FSubtract = false;
   4475     parentObj.FZero = ((parentObj.registerB & 0x40) == 0);
   4476   }
   4477   //BIT 6, C
   4478   //#0x71:
   4479   ,function (parentObj) {
   4480     parentObj.FHalfCarry = true;
   4481     parentObj.FSubtract = false;
   4482     parentObj.FZero = ((parentObj.registerC & 0x40) == 0);
   4483   }
   4484   //BIT 6, D
   4485   //#0x72:
   4486   ,function (parentObj) {
   4487     parentObj.FHalfCarry = true;
   4488     parentObj.FSubtract = false;
   4489     parentObj.FZero = ((parentObj.registerD & 0x40) == 0);
   4490   }
   4491   //BIT 6, E
   4492   //#0x73:
   4493   ,function (parentObj) {
   4494     parentObj.FHalfCarry = true;
   4495     parentObj.FSubtract = false;
   4496     parentObj.FZero = ((parentObj.registerE & 0x40) == 0);
   4497   }
   4498   //BIT 6, H
   4499   //#0x74:
   4500   ,function (parentObj) {
   4501     parentObj.FHalfCarry = true;
   4502     parentObj.FSubtract = false;
   4503     parentObj.FZero = ((parentObj.registersHL & 0x4000) == 0);
   4504   }
   4505   //BIT 6, L
   4506   //#0x75:
   4507   ,function (parentObj) {
   4508     parentObj.FHalfCarry = true;
   4509     parentObj.FSubtract = false;
   4510     parentObj.FZero = ((parentObj.registersHL & 0x0040) == 0);
   4511   }
   4512   //BIT 6, (HL)
   4513   //#0x76:
   4514   ,function (parentObj) {
   4515     parentObj.FHalfCarry = true;
   4516     parentObj.FSubtract = false;
   4517     parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x40) == 0);
   4518   }
   4519   //BIT 6, A
   4520   //#0x77:
   4521   ,function (parentObj) {
   4522     parentObj.FHalfCarry = true;
   4523     parentObj.FSubtract = false;
   4524     parentObj.FZero = ((parentObj.registerA & 0x40) == 0);
   4525   }
   4526   //BIT 7, B
   4527   //#0x78:
   4528   ,function (parentObj) {
   4529     parentObj.FHalfCarry = true;
   4530     parentObj.FSubtract = false;
   4531     parentObj.FZero = ((parentObj.registerB & 0x80) == 0);
   4532   }
   4533   //BIT 7, C
   4534   //#0x79:
   4535   ,function (parentObj) {
   4536     parentObj.FHalfCarry = true;
   4537     parentObj.FSubtract = false;
   4538     parentObj.FZero = ((parentObj.registerC & 0x80) == 0);
   4539   }
   4540   //BIT 7, D
   4541   //#0x7A:
   4542   ,function (parentObj) {
   4543     parentObj.FHalfCarry = true;
   4544     parentObj.FSubtract = false;
   4545     parentObj.FZero = ((parentObj.registerD & 0x80) == 0);
   4546   }
   4547   //BIT 7, E
   4548   //#0x7B:
   4549   ,function (parentObj) {
   4550     parentObj.FHalfCarry = true;
   4551     parentObj.FSubtract = false;
   4552     parentObj.FZero = ((parentObj.registerE & 0x80) == 0);
   4553   }
   4554   //BIT 7, H
   4555   //#0x7C:
   4556   ,function (parentObj) {
   4557     parentObj.FHalfCarry = true;
   4558     parentObj.FSubtract = false;
   4559     parentObj.FZero = ((parentObj.registersHL & 0x8000) == 0);
   4560   }
   4561   //BIT 7, L
   4562   //#0x7D:
   4563   ,function (parentObj) {
   4564     parentObj.FHalfCarry = true;
   4565     parentObj.FSubtract = false;
   4566     parentObj.FZero = ((parentObj.registersHL & 0x0080) == 0);
   4567   }
   4568   //BIT 7, (HL)
   4569   //#0x7E:
   4570   ,function (parentObj) {
   4571     parentObj.FHalfCarry = true;
   4572     parentObj.FSubtract = false;
   4573     parentObj.FZero = ((parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x80) == 0);
   4574   }
   4575   //BIT 7, A
   4576   //#0x7F:
   4577   ,function (parentObj) {
   4578     parentObj.FHalfCarry = true;
   4579     parentObj.FSubtract = false;
   4580     parentObj.FZero = ((parentObj.registerA & 0x80) == 0);
   4581   }
   4582   //RES 0, B
   4583   //#0x80:
   4584   ,function (parentObj) {
   4585     parentObj.registerB &= 0xFE;
   4586   }
   4587   //RES 0, C
   4588   //#0x81:
   4589   ,function (parentObj) {
   4590     parentObj.registerC &= 0xFE;
   4591   }
   4592   //RES 0, D
   4593   //#0x82:
   4594   ,function (parentObj) {
   4595     parentObj.registerD &= 0xFE;
   4596   }
   4597   //RES 0, E
   4598   //#0x83:
   4599   ,function (parentObj) {
   4600     parentObj.registerE &= 0xFE;
   4601   }
   4602   //RES 0, H
   4603   //#0x84:
   4604   ,function (parentObj) {
   4605     parentObj.registersHL &= 0xFEFF;
   4606   }
   4607   //RES 0, L
   4608   //#0x85:
   4609   ,function (parentObj) {
   4610     parentObj.registersHL &= 0xFFFE;
   4611   }
   4612   //RES 0, (HL)
   4613   //#0x86:
   4614   ,function (parentObj) {
   4615     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xFE);
   4616   }
   4617   //RES 0, A
   4618   //#0x87:
   4619   ,function (parentObj) {
   4620     parentObj.registerA &= 0xFE;
   4621   }
   4622   //RES 1, B
   4623   //#0x88:
   4624   ,function (parentObj) {
   4625     parentObj.registerB &= 0xFD;
   4626   }
   4627   //RES 1, C
   4628   //#0x89:
   4629   ,function (parentObj) {
   4630     parentObj.registerC &= 0xFD;
   4631   }
   4632   //RES 1, D
   4633   //#0x8A:
   4634   ,function (parentObj) {
   4635     parentObj.registerD &= 0xFD;
   4636   }
   4637   //RES 1, E
   4638   //#0x8B:
   4639   ,function (parentObj) {
   4640     parentObj.registerE &= 0xFD;
   4641   }
   4642   //RES 1, H
   4643   //#0x8C:
   4644   ,function (parentObj) {
   4645     parentObj.registersHL &= 0xFDFF;
   4646   }
   4647   //RES 1, L
   4648   //#0x8D:
   4649   ,function (parentObj) {
   4650     parentObj.registersHL &= 0xFFFD;
   4651   }
   4652   //RES 1, (HL)
   4653   //#0x8E:
   4654   ,function (parentObj) {
   4655     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xFD);
   4656   }
   4657   //RES 1, A
   4658   //#0x8F:
   4659   ,function (parentObj) {
   4660     parentObj.registerA &= 0xFD;
   4661   }
   4662   //RES 2, B
   4663   //#0x90:
   4664   ,function (parentObj) {
   4665     parentObj.registerB &= 0xFB;
   4666   }
   4667   //RES 2, C
   4668   //#0x91:
   4669   ,function (parentObj) {
   4670     parentObj.registerC &= 0xFB;
   4671   }
   4672   //RES 2, D
   4673   //#0x92:
   4674   ,function (parentObj) {
   4675     parentObj.registerD &= 0xFB;
   4676   }
   4677   //RES 2, E
   4678   //#0x93:
   4679   ,function (parentObj) {
   4680     parentObj.registerE &= 0xFB;
   4681   }
   4682   //RES 2, H
   4683   //#0x94:
   4684   ,function (parentObj) {
   4685     parentObj.registersHL &= 0xFBFF;
   4686   }
   4687   //RES 2, L
   4688   //#0x95:
   4689   ,function (parentObj) {
   4690     parentObj.registersHL &= 0xFFFB;
   4691   }
   4692   //RES 2, (HL)
   4693   //#0x96:
   4694   ,function (parentObj) {
   4695     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xFB);
   4696   }
   4697   //RES 2, A
   4698   //#0x97:
   4699   ,function (parentObj) {
   4700     parentObj.registerA &= 0xFB;
   4701   }
   4702   //RES 3, B
   4703   //#0x98:
   4704   ,function (parentObj) {
   4705     parentObj.registerB &= 0xF7;
   4706   }
   4707   //RES 3, C
   4708   //#0x99:
   4709   ,function (parentObj) {
   4710     parentObj.registerC &= 0xF7;
   4711   }
   4712   //RES 3, D
   4713   //#0x9A:
   4714   ,function (parentObj) {
   4715     parentObj.registerD &= 0xF7;
   4716   }
   4717   //RES 3, E
   4718   //#0x9B:
   4719   ,function (parentObj) {
   4720     parentObj.registerE &= 0xF7;
   4721   }
   4722   //RES 3, H
   4723   //#0x9C:
   4724   ,function (parentObj) {
   4725     parentObj.registersHL &= 0xF7FF;
   4726   }
   4727   //RES 3, L
   4728   //#0x9D:
   4729   ,function (parentObj) {
   4730     parentObj.registersHL &= 0xFFF7;
   4731   }
   4732   //RES 3, (HL)
   4733   //#0x9E:
   4734   ,function (parentObj) {
   4735     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xF7);
   4736   }
   4737   //RES 3, A
   4738   //#0x9F:
   4739   ,function (parentObj) {
   4740     parentObj.registerA &= 0xF7;
   4741   }
   4742   //RES 3, B
   4743   //#0xA0:
   4744   ,function (parentObj) {
   4745     parentObj.registerB &= 0xEF;
   4746   }
   4747   //RES 4, C
   4748   //#0xA1:
   4749   ,function (parentObj) {
   4750     parentObj.registerC &= 0xEF;
   4751   }
   4752   //RES 4, D
   4753   //#0xA2:
   4754   ,function (parentObj) {
   4755     parentObj.registerD &= 0xEF;
   4756   }
   4757   //RES 4, E
   4758   //#0xA3:
   4759   ,function (parentObj) {
   4760     parentObj.registerE &= 0xEF;
   4761   }
   4762   //RES 4, H
   4763   //#0xA4:
   4764   ,function (parentObj) {
   4765     parentObj.registersHL &= 0xEFFF;
   4766   }
   4767   //RES 4, L
   4768   //#0xA5:
   4769   ,function (parentObj) {
   4770     parentObj.registersHL &= 0xFFEF;
   4771   }
   4772   //RES 4, (HL)
   4773   //#0xA6:
   4774   ,function (parentObj) {
   4775     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xEF);
   4776   }
   4777   //RES 4, A
   4778   //#0xA7:
   4779   ,function (parentObj) {
   4780     parentObj.registerA &= 0xEF;
   4781   }
   4782   //RES 5, B
   4783   //#0xA8:
   4784   ,function (parentObj) {
   4785     parentObj.registerB &= 0xDF;
   4786   }
   4787   //RES 5, C
   4788   //#0xA9:
   4789   ,function (parentObj) {
   4790     parentObj.registerC &= 0xDF;
   4791   }
   4792   //RES 5, D
   4793   //#0xAA:
   4794   ,function (parentObj) {
   4795     parentObj.registerD &= 0xDF;
   4796   }
   4797   //RES 5, E
   4798   //#0xAB:
   4799   ,function (parentObj) {
   4800     parentObj.registerE &= 0xDF;
   4801   }
   4802   //RES 5, H
   4803   //#0xAC:
   4804   ,function (parentObj) {
   4805     parentObj.registersHL &= 0xDFFF;
   4806   }
   4807   //RES 5, L
   4808   //#0xAD:
   4809   ,function (parentObj) {
   4810     parentObj.registersHL &= 0xFFDF;
   4811   }
   4812   //RES 5, (HL)
   4813   //#0xAE:
   4814   ,function (parentObj) {
   4815     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xDF);
   4816   }
   4817   //RES 5, A
   4818   //#0xAF:
   4819   ,function (parentObj) {
   4820     parentObj.registerA &= 0xDF;
   4821   }
   4822   //RES 6, B
   4823   //#0xB0:
   4824   ,function (parentObj) {
   4825     parentObj.registerB &= 0xBF;
   4826   }
   4827   //RES 6, C
   4828   //#0xB1:
   4829   ,function (parentObj) {
   4830     parentObj.registerC &= 0xBF;
   4831   }
   4832   //RES 6, D
   4833   //#0xB2:
   4834   ,function (parentObj) {
   4835     parentObj.registerD &= 0xBF;
   4836   }
   4837   //RES 6, E
   4838   //#0xB3:
   4839   ,function (parentObj) {
   4840     parentObj.registerE &= 0xBF;
   4841   }
   4842   //RES 6, H
   4843   //#0xB4:
   4844   ,function (parentObj) {
   4845     parentObj.registersHL &= 0xBFFF;
   4846   }
   4847   //RES 6, L
   4848   //#0xB5:
   4849   ,function (parentObj) {
   4850     parentObj.registersHL &= 0xFFBF;
   4851   }
   4852   //RES 6, (HL)
   4853   //#0xB6:
   4854   ,function (parentObj) {
   4855     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0xBF);
   4856   }
   4857   //RES 6, A
   4858   //#0xB7:
   4859   ,function (parentObj) {
   4860     parentObj.registerA &= 0xBF;
   4861   }
   4862   //RES 7, B
   4863   //#0xB8:
   4864   ,function (parentObj) {
   4865     parentObj.registerB &= 0x7F;
   4866   }
   4867   //RES 7, C
   4868   //#0xB9:
   4869   ,function (parentObj) {
   4870     parentObj.registerC &= 0x7F;
   4871   }
   4872   //RES 7, D
   4873   //#0xBA:
   4874   ,function (parentObj) {
   4875     parentObj.registerD &= 0x7F;
   4876   }
   4877   //RES 7, E
   4878   //#0xBB:
   4879   ,function (parentObj) {
   4880     parentObj.registerE &= 0x7F;
   4881   }
   4882   //RES 7, H
   4883   //#0xBC:
   4884   ,function (parentObj) {
   4885     parentObj.registersHL &= 0x7FFF;
   4886   }
   4887   //RES 7, L
   4888   //#0xBD:
   4889   ,function (parentObj) {
   4890     parentObj.registersHL &= 0xFF7F;
   4891   }
   4892   //RES 7, (HL)
   4893   //#0xBE:
   4894   ,function (parentObj) {
   4895     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) & 0x7F);
   4896   }
   4897   //RES 7, A
   4898   //#0xBF:
   4899   ,function (parentObj) {
   4900     parentObj.registerA &= 0x7F;
   4901   }
   4902   //SET 0, B
   4903   //#0xC0:
   4904   ,function (parentObj) {
   4905     parentObj.registerB |= 0x01;
   4906   }
   4907   //SET 0, C
   4908   //#0xC1:
   4909   ,function (parentObj) {
   4910     parentObj.registerC |= 0x01;
   4911   }
   4912   //SET 0, D
   4913   //#0xC2:
   4914   ,function (parentObj) {
   4915     parentObj.registerD |= 0x01;
   4916   }
   4917   //SET 0, E
   4918   //#0xC3:
   4919   ,function (parentObj) {
   4920     parentObj.registerE |= 0x01;
   4921   }
   4922   //SET 0, H
   4923   //#0xC4:
   4924   ,function (parentObj) {
   4925     parentObj.registersHL |= 0x0100;
   4926   }
   4927   //SET 0, L
   4928   //#0xC5:
   4929   ,function (parentObj) {
   4930     parentObj.registersHL |= 0x01;
   4931   }
   4932   //SET 0, (HL)
   4933   //#0xC6:
   4934   ,function (parentObj) {
   4935     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x01);
   4936   }
   4937   //SET 0, A
   4938   //#0xC7:
   4939   ,function (parentObj) {
   4940     parentObj.registerA |= 0x01;
   4941   }
   4942   //SET 1, B
   4943   //#0xC8:
   4944   ,function (parentObj) {
   4945     parentObj.registerB |= 0x02;
   4946   }
   4947   //SET 1, C
   4948   //#0xC9:
   4949   ,function (parentObj) {
   4950     parentObj.registerC |= 0x02;
   4951   }
   4952   //SET 1, D
   4953   //#0xCA:
   4954   ,function (parentObj) {
   4955     parentObj.registerD |= 0x02;
   4956   }
   4957   //SET 1, E
   4958   //#0xCB:
   4959   ,function (parentObj) {
   4960     parentObj.registerE |= 0x02;
   4961   }
   4962   //SET 1, H
   4963   //#0xCC:
   4964   ,function (parentObj) {
   4965     parentObj.registersHL |= 0x0200;
   4966   }
   4967   //SET 1, L
   4968   //#0xCD:
   4969   ,function (parentObj) {
   4970     parentObj.registersHL |= 0x02;
   4971   }
   4972   //SET 1, (HL)
   4973   //#0xCE:
   4974   ,function (parentObj) {
   4975     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x02);
   4976   }
   4977   //SET 1, A
   4978   //#0xCF:
   4979   ,function (parentObj) {
   4980     parentObj.registerA |= 0x02;
   4981   }
   4982   //SET 2, B
   4983   //#0xD0:
   4984   ,function (parentObj) {
   4985     parentObj.registerB |= 0x04;
   4986   }
   4987   //SET 2, C
   4988   //#0xD1:
   4989   ,function (parentObj) {
   4990     parentObj.registerC |= 0x04;
   4991   }
   4992   //SET 2, D
   4993   //#0xD2:
   4994   ,function (parentObj) {
   4995     parentObj.registerD |= 0x04;
   4996   }
   4997   //SET 2, E
   4998   //#0xD3:
   4999   ,function (parentObj) {
   5000     parentObj.registerE |= 0x04;
   5001   }
   5002   //SET 2, H
   5003   //#0xD4:
   5004   ,function (parentObj) {
   5005     parentObj.registersHL |= 0x0400;
   5006   }
   5007   //SET 2, L
   5008   //#0xD5:
   5009   ,function (parentObj) {
   5010     parentObj.registersHL |= 0x04;
   5011   }
   5012   //SET 2, (HL)
   5013   //#0xD6:
   5014   ,function (parentObj) {
   5015     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x04);
   5016   }
   5017   //SET 2, A
   5018   //#0xD7:
   5019   ,function (parentObj) {
   5020     parentObj.registerA |= 0x04;
   5021   }
   5022   //SET 3, B
   5023   //#0xD8:
   5024   ,function (parentObj) {
   5025     parentObj.registerB |= 0x08;
   5026   }
   5027   //SET 3, C
   5028   //#0xD9:
   5029   ,function (parentObj) {
   5030     parentObj.registerC |= 0x08;
   5031   }
   5032   //SET 3, D
   5033   //#0xDA:
   5034   ,function (parentObj) {
   5035     parentObj.registerD |= 0x08;
   5036   }
   5037   //SET 3, E
   5038   //#0xDB:
   5039   ,function (parentObj) {
   5040     parentObj.registerE |= 0x08;
   5041   }
   5042   //SET 3, H
   5043   //#0xDC:
   5044   ,function (parentObj) {
   5045     parentObj.registersHL |= 0x0800;
   5046   }
   5047   //SET 3, L
   5048   //#0xDD:
   5049   ,function (parentObj) {
   5050     parentObj.registersHL |= 0x08;
   5051   }
   5052   //SET 3, (HL)
   5053   //#0xDE:
   5054   ,function (parentObj) {
   5055     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x08);
   5056   }
   5057   //SET 3, A
   5058   //#0xDF:
   5059   ,function (parentObj) {
   5060     parentObj.registerA |= 0x08;
   5061   }
   5062   //SET 4, B
   5063   //#0xE0:
   5064   ,function (parentObj) {
   5065     parentObj.registerB |= 0x10;
   5066   }
   5067   //SET 4, C
   5068   //#0xE1:
   5069   ,function (parentObj) {
   5070     parentObj.registerC |= 0x10;
   5071   }
   5072   //SET 4, D
   5073   //#0xE2:
   5074   ,function (parentObj) {
   5075     parentObj.registerD |= 0x10;
   5076   }
   5077   //SET 4, E
   5078   //#0xE3:
   5079   ,function (parentObj) {
   5080     parentObj.registerE |= 0x10;
   5081   }
   5082   //SET 4, H
   5083   //#0xE4:
   5084   ,function (parentObj) {
   5085     parentObj.registersHL |= 0x1000;
   5086   }
   5087   //SET 4, L
   5088   //#0xE5:
   5089   ,function (parentObj) {
   5090     parentObj.registersHL |= 0x10;
   5091   }
   5092   //SET 4, (HL)
   5093   //#0xE6:
   5094   ,function (parentObj) {
   5095     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x10);
   5096   }
   5097   //SET 4, A
   5098   //#0xE7:
   5099   ,function (parentObj) {
   5100     parentObj.registerA |= 0x10;
   5101   }
   5102   //SET 5, B
   5103   //#0xE8:
   5104   ,function (parentObj) {
   5105     parentObj.registerB |= 0x20;
   5106   }
   5107   //SET 5, C
   5108   //#0xE9:
   5109   ,function (parentObj) {
   5110     parentObj.registerC |= 0x20;
   5111   }
   5112   //SET 5, D
   5113   //#0xEA:
   5114   ,function (parentObj) {
   5115     parentObj.registerD |= 0x20;
   5116   }
   5117   //SET 5, E
   5118   //#0xEB:
   5119   ,function (parentObj) {
   5120     parentObj.registerE |= 0x20;
   5121   }
   5122   //SET 5, H
   5123   //#0xEC:
   5124   ,function (parentObj) {
   5125     parentObj.registersHL |= 0x2000;
   5126   }
   5127   //SET 5, L
   5128   //#0xED:
   5129   ,function (parentObj) {
   5130     parentObj.registersHL |= 0x20;
   5131   }
   5132   //SET 5, (HL)
   5133   //#0xEE:
   5134   ,function (parentObj) {
   5135     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x20);
   5136   }
   5137   //SET 5, A
   5138   //#0xEF:
   5139   ,function (parentObj) {
   5140     parentObj.registerA |= 0x20;
   5141   }
   5142   //SET 6, B
   5143   //#0xF0:
   5144   ,function (parentObj) {
   5145     parentObj.registerB |= 0x40;
   5146   }
   5147   //SET 6, C
   5148   //#0xF1:
   5149   ,function (parentObj) {
   5150     parentObj.registerC |= 0x40;
   5151   }
   5152   //SET 6, D
   5153   //#0xF2:
   5154   ,function (parentObj) {
   5155     parentObj.registerD |= 0x40;
   5156   }
   5157   //SET 6, E
   5158   //#0xF3:
   5159   ,function (parentObj) {
   5160     parentObj.registerE |= 0x40;
   5161   }
   5162   //SET 6, H
   5163   //#0xF4:
   5164   ,function (parentObj) {
   5165     parentObj.registersHL |= 0x4000;
   5166   }
   5167   //SET 6, L
   5168   //#0xF5:
   5169   ,function (parentObj) {
   5170     parentObj.registersHL |= 0x40;
   5171   }
   5172   //SET 6, (HL)
   5173   //#0xF6:
   5174   ,function (parentObj) {
   5175     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x40);
   5176   }
   5177   //SET 6, A
   5178   //#0xF7:
   5179   ,function (parentObj) {
   5180     parentObj.registerA |= 0x40;
   5181   }
   5182   //SET 7, B
   5183   //#0xF8:
   5184   ,function (parentObj) {
   5185     parentObj.registerB |= 0x80;
   5186   }
   5187   //SET 7, C
   5188   //#0xF9:
   5189   ,function (parentObj) {
   5190     parentObj.registerC |= 0x80;
   5191   }
   5192   //SET 7, D
   5193   //#0xFA:
   5194   ,function (parentObj) {
   5195     parentObj.registerD |= 0x80;
   5196   }
   5197   //SET 7, E
   5198   //#0xFB:
   5199   ,function (parentObj) {
   5200     parentObj.registerE |= 0x80;
   5201   }
   5202   //SET 7, H
   5203   //#0xFC:
   5204   ,function (parentObj) {
   5205     parentObj.registersHL |= 0x8000;
   5206   }
   5207   //SET 7, L
   5208   //#0xFD:
   5209   ,function (parentObj) {
   5210     parentObj.registersHL |= 0x80;
   5211   }
   5212   //SET 7, (HL)
   5213   //#0xFE:
   5214   ,function (parentObj) {
   5215     parentObj.memoryWriter[parentObj.registersHL](parentObj, parentObj.registersHL, parentObj.memoryReader[parentObj.registersHL](parentObj, parentObj.registersHL) | 0x80);
   5216   }
   5217   //SET 7, A
   5218   //#0xFF:
   5219   ,function (parentObj) {
   5220     parentObj.registerA |= 0x80;
   5221   }
   5222 ];
   5223 GameBoyCore.prototype.TICKTable = [    //Number of machine cycles for each instruction:
   5224 /*   0,  1,  2,  3,  4,  5,  6,  7,      8,  9,  A, B,  C,  D, E,  F*/
   5225      4, 12,  8,  8,  4,  4,  8,  4,     20,  8,  8, 8,  4,  4, 8,  4,  //0
   5226      4, 12,  8,  8,  4,  4,  8,  4,     12,  8,  8, 8,  4,  4, 8,  4,  //1
   5227      8, 12,  8,  8,  4,  4,  8,  4,      8,  8,  8, 8,  4,  4, 8,  4,  //2
   5228      8, 12,  8,  8, 12, 12, 12,  4,      8,  8,  8, 8,  4,  4, 8,  4,  //3
   5229 
   5230      4,  4,  4,  4,  4,  4,  8,  4,      4,  4,  4, 4,  4,  4, 8,  4,  //4
   5231      4,  4,  4,  4,  4,  4,  8,  4,      4,  4,  4, 4,  4,  4, 8,  4,  //5
   5232      4,  4,  4,  4,  4,  4,  8,  4,      4,  4,  4, 4,  4,  4, 8,  4,  //6
   5233      8,  8,  8,  8,  8,  8,  4,  8,      4,  4,  4, 4,  4,  4, 8,  4,  //7
   5234 
   5235      4,  4,  4,  4,  4,  4,  8,  4,      4,  4,  4, 4,  4,  4, 8,  4,  //8
   5236      4,  4,  4,  4,  4,  4,  8,  4,      4,  4,  4, 4,  4,  4, 8,  4,  //9
   5237      4,  4,  4,  4,  4,  4,  8,  4,      4,  4,  4, 4,  4,  4, 8,  4,  //A
   5238      4,  4,  4,  4,  4,  4,  8,  4,      4,  4,  4, 4,  4,  4, 8,  4,  //B
   5239 
   5240      8, 12, 12, 16, 12, 16,  8, 16,      8, 16, 12, 0, 12, 24, 8, 16,  //C
   5241      8, 12, 12,  4, 12, 16,  8, 16,      8, 16, 12, 4, 12,  4, 8, 16,  //D
   5242     12, 12,  8,  4,  4, 16,  8, 16,     16,  4, 16, 4,  4,  4, 8, 16,  //E
   5243     12, 12,  8,  4,  4, 16,  8, 16,     12,  8, 16, 4,  0,  4, 8, 16   //F
   5244 ];
   5245 GameBoyCore.prototype.SecondaryTICKTable = [  //Number of machine cycles for each 0xCBXX instruction:
   5246 /*  0, 1, 2, 3, 4, 5,  6, 7,        8, 9, A, B, C, D,  E, F*/
   5247     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //0
   5248     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //1
   5249     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //2
   5250     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //3
   5251 
   5252     8, 8, 8, 8, 8, 8, 12, 8,        8, 8, 8, 8, 8, 8, 12, 8,  //4
   5253     8, 8, 8, 8, 8, 8, 12, 8,        8, 8, 8, 8, 8, 8, 12, 8,  //5
   5254     8, 8, 8, 8, 8, 8, 12, 8,        8, 8, 8, 8, 8, 8, 12, 8,  //6
   5255     8, 8, 8, 8, 8, 8, 12, 8,        8, 8, 8, 8, 8, 8, 12, 8,  //7
   5256 
   5257     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //8
   5258     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //9
   5259     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //A
   5260     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //B
   5261 
   5262     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //C
   5263     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //D
   5264     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8,  //E
   5265     8, 8, 8, 8, 8, 8, 16, 8,        8, 8, 8, 8, 8, 8, 16, 8   //F
   5266 ];
   5267 GameBoyCore.prototype.saveSRAMState = function () {
   5268   if (!this.cBATT || this.MBCRam.length == 0) {
   5269     //No battery backup...
   5270     return [];
   5271   }
   5272   else {
   5273     //Return the MBC RAM for backup...
   5274     return this.fromTypedArray(this.MBCRam);
   5275   }
   5276 }
   5277 GameBoyCore.prototype.saveRTCState = function () {
   5278   if (!this.cTIMER) {
   5279     //No battery backup...
   5280     return [];
   5281   }
   5282   else {
   5283     //Return the MBC RAM for backup...
   5284     return [
   5285       this.lastIteration,
   5286       this.RTCisLatched,
   5287       this.latchedSeconds,
   5288       this.latchedMinutes,
   5289       this.latchedHours,
   5290       this.latchedLDays,
   5291       this.latchedHDays,
   5292       this.RTCSeconds,
   5293       this.RTCMinutes,
   5294       this.RTCHours,
   5295       this.RTCDays,
   5296       this.RTCDayOverFlow,
   5297       this.RTCHALT
   5298     ];
   5299   }
   5300 }
   5301 GameBoyCore.prototype.saveState = function () {
   5302   return [
   5303     this.fromTypedArray(this.ROM),
   5304     this.inBootstrap,
   5305     this.registerA,
   5306     this.FZero,
   5307     this.FSubtract,
   5308     this.FHalfCarry,
   5309     this.FCarry,
   5310     this.registerB,
   5311     this.registerC,
   5312     this.registerD,
   5313     this.registerE,
   5314     this.registersHL,
   5315     this.stackPointer,
   5316     this.programCounter,
   5317     this.halt,
   5318     this.IME,
   5319     this.hdmaRunning,
   5320     this.CPUTicks,
   5321     this.doubleSpeedShifter,
   5322     this.fromTypedArray(this.memory),
   5323     this.fromTypedArray(this.MBCRam),
   5324     this.fromTypedArray(this.VRAM),
   5325     this.currVRAMBank,
   5326     this.fromTypedArray(this.GBCMemory),
   5327     this.MBC1Mode,
   5328     this.MBCRAMBanksEnabled,
   5329     this.currMBCRAMBank,
   5330     this.currMBCRAMBankPosition,
   5331     this.cGBC,
   5332     this.gbcRamBank,
   5333     this.gbcRamBankPosition,
   5334     this.ROMBank1offs,
   5335     this.currentROMBank,
   5336     this.cartridgeType,
   5337     this.name,
   5338     this.gameCode,
   5339     this.modeSTAT,
   5340     this.LYCMatchTriggerSTAT,
   5341     this.mode2TriggerSTAT,
   5342     this.mode1TriggerSTAT,
   5343     this.mode0TriggerSTAT,
   5344     this.LCDisOn,
   5345     this.gfxWindowCHRBankPosition,
   5346     this.gfxWindowDisplay,
   5347     this.gfxSpriteShow,
   5348     this.gfxSpriteNormalHeight,
   5349     this.gfxBackgroundCHRBankPosition,
   5350     this.gfxBackgroundBankOffset,
   5351     this.TIMAEnabled,
   5352     this.DIVTicks,
   5353     this.LCDTicks,
   5354     this.timerTicks,
   5355     this.TACClocker,
   5356     this.serialTimer,
   5357     this.serialShiftTimer,
   5358     this.serialShiftTimerAllocated,
   5359     this.IRQEnableDelay,
   5360     this.lastIteration,
   5361     this.cMBC1,
   5362     this.cMBC2,
   5363     this.cMBC3,
   5364     this.cMBC5,
   5365     this.cMBC7,
   5366     this.cSRAM,
   5367     this.cMMMO1,
   5368     this.cRUMBLE,
   5369     this.cCamera,
   5370     this.cTAMA5,
   5371     this.cHuC3,
   5372     this.cHuC1,
   5373     this.drewBlank,
   5374     this.fromTypedArray(this.frameBuffer),
   5375     this.bgEnabled,
   5376     this.BGPriorityEnabled,
   5377     this.channel1FrequencyTracker,
   5378     this.channel1FrequencyCounter,
   5379     this.channel1totalLength,
   5380     this.channel1envelopeVolume,
   5381     this.channel1envelopeType,
   5382     this.channel1envelopeSweeps,
   5383     this.channel1envelopeSweepsLast,
   5384     this.channel1consecutive,
   5385     this.channel1frequency,
   5386     this.channel1SweepFault,
   5387     this.channel1ShadowFrequency,
   5388     this.channel1timeSweep,
   5389     this.channel1lastTimeSweep,
   5390     this.channel1numSweep,
   5391     this.channel1frequencySweepDivider,
   5392     this.channel1decreaseSweep,
   5393     this.channel2FrequencyTracker,
   5394     this.channel2FrequencyCounter,
   5395     this.channel2totalLength,
   5396     this.channel2envelopeVolume,
   5397     this.channel2envelopeType,
   5398     this.channel2envelopeSweeps,
   5399     this.channel2envelopeSweepsLast,
   5400     this.channel2consecutive,
   5401     this.channel2frequency,
   5402     this.channel3canPlay,
   5403     this.channel3totalLength,
   5404     this.channel3patternType,
   5405     this.channel3frequency,
   5406     this.channel3consecutive,
   5407     this.fromTypedArray(this.channel3PCM),
   5408     this.channel4FrequencyPeriod,
   5409     this.channel4lastSampleLookup,
   5410     this.channel4totalLength,
   5411     this.channel4envelopeVolume,
   5412     this.channel4currentVolume,
   5413     this.channel4envelopeType,
   5414     this.channel4envelopeSweeps,
   5415     this.channel4envelopeSweepsLast,
   5416     this.channel4consecutive,
   5417     this.channel4BitRange,
   5418     this.soundMasterEnabled,
   5419     this.VinLeftChannelMasterVolume,
   5420     this.VinRightChannelMasterVolume,
   5421     this.leftChannel1,
   5422     this.leftChannel2,
   5423     this.leftChannel3,
   5424     this.leftChannel4,
   5425     this.rightChannel1,
   5426     this.rightChannel2,
   5427     this.rightChannel3,
   5428     this.rightChannel4,
   5429     this.channel1currentSampleLeft,
   5430     this.channel1currentSampleRight,
   5431     this.channel2currentSampleLeft,
   5432     this.channel2currentSampleRight,
   5433     this.channel3currentSampleLeft,
   5434     this.channel3currentSampleRight,
   5435     this.channel4currentSampleLeft,
   5436     this.channel4currentSampleRight,
   5437     this.channel1currentSampleLeftSecondary,
   5438     this.channel1currentSampleRightSecondary,
   5439     this.channel2currentSampleLeftSecondary,
   5440     this.channel2currentSampleRightSecondary,
   5441     this.channel3currentSampleLeftSecondary,
   5442     this.channel3currentSampleRightSecondary,
   5443     this.channel4currentSampleLeftSecondary,
   5444     this.channel4currentSampleRightSecondary,
   5445     this.channel1currentSampleLeftTrimary,
   5446     this.channel1currentSampleRightTrimary,
   5447     this.channel2currentSampleLeftTrimary,
   5448     this.channel2currentSampleRightTrimary,
   5449     this.mixerOutputCache,
   5450     this.channel1DutyTracker,
   5451     this.channel1CachedDuty,
   5452     this.channel2DutyTracker,
   5453     this.channel2CachedDuty,
   5454     this.channel1Enabled,
   5455     this.channel2Enabled,
   5456     this.channel3Enabled,
   5457     this.channel4Enabled,
   5458     this.sequencerClocks,
   5459     this.sequencePosition,
   5460     this.channel3Counter,
   5461     this.channel4Counter,
   5462     this.cachedChannel3Sample,
   5463     this.cachedChannel4Sample,
   5464     this.channel3FrequencyPeriod,
   5465     this.channel3lastSampleLookup,
   5466     this.actualScanLine,
   5467     this.lastUnrenderedLine,
   5468     this.queuedScanLines,
   5469     this.RTCisLatched,
   5470     this.latchedSeconds,
   5471     this.latchedMinutes,
   5472     this.latchedHours,
   5473     this.latchedLDays,
   5474     this.latchedHDays,
   5475     this.RTCSeconds,
   5476     this.RTCMinutes,
   5477     this.RTCHours,
   5478     this.RTCDays,
   5479     this.RTCDayOverFlow,
   5480     this.RTCHALT,
   5481     this.usedBootROM,
   5482     this.skipPCIncrement,
   5483     this.STATTracker,
   5484     this.gbcRamBankPositionECHO,
   5485     this.numRAMBanks,
   5486     this.windowY,
   5487     this.windowX,
   5488     this.fromTypedArray(this.gbcOBJRawPalette),
   5489     this.fromTypedArray(this.gbcBGRawPalette),
   5490     this.fromTypedArray(this.gbOBJPalette),
   5491     this.fromTypedArray(this.gbBGPalette),
   5492     this.fromTypedArray(this.gbcOBJPalette),
   5493     this.fromTypedArray(this.gbcBGPalette),
   5494     this.fromTypedArray(this.gbBGColorizedPalette),
   5495     this.fromTypedArray(this.gbOBJColorizedPalette),
   5496     this.fromTypedArray(this.cachedBGPaletteConversion),
   5497     this.fromTypedArray(this.cachedOBJPaletteConversion),
   5498     this.fromTypedArray(this.BGCHRBank1),
   5499     this.fromTypedArray(this.BGCHRBank2),
   5500     this.haltPostClocks,
   5501     this.interruptsRequested,
   5502     this.interruptsEnabled,
   5503     this.remainingClocks,
   5504     this.colorizedGBPalettes,
   5505     this.backgroundY,
   5506     this.backgroundX,
   5507     this.CPUStopped
   5508   ];
   5509 }
   5510 GameBoyCore.prototype.returnFromState = function (returnedFrom) {
   5511   var index = 0;
   5512   var state = returnedFrom.slice(0);
   5513   this.ROM = this.toTypedArray(state[index++], "uint8");
   5514   this.ROMBankEdge = Math.floor(this.ROM.length / 0x4000);
   5515   this.inBootstrap = state[index++];
   5516   this.registerA = state[index++];
   5517   this.FZero = state[index++];
   5518   this.FSubtract = state[index++];
   5519   this.FHalfCarry = state[index++];
   5520   this.FCarry = state[index++];
   5521   this.registerB = state[index++];
   5522   this.registerC = state[index++];
   5523   this.registerD = state[index++];
   5524   this.registerE = state[index++];
   5525   this.registersHL = state[index++];
   5526   this.stackPointer = state[index++];
   5527   this.programCounter = state[index++];
   5528   this.halt = state[index++];
   5529   this.IME = state[index++];
   5530   this.hdmaRunning = state[index++];
   5531   this.CPUTicks = state[index++];
   5532   this.doubleSpeedShifter = state[index++];
   5533   this.memory = this.toTypedArray(state[index++], "uint8");
   5534   this.MBCRam = this.toTypedArray(state[index++], "uint8");
   5535   this.VRAM = this.toTypedArray(state[index++], "uint8");
   5536   this.currVRAMBank = state[index++];
   5537   this.GBCMemory = this.toTypedArray(state[index++], "uint8");
   5538   this.MBC1Mode = state[index++];
   5539   this.MBCRAMBanksEnabled = state[index++];
   5540   this.currMBCRAMBank = state[index++];
   5541   this.currMBCRAMBankPosition = state[index++];
   5542   this.cGBC = state[index++];
   5543   this.gbcRamBank = state[index++];
   5544   this.gbcRamBankPosition = state[index++];
   5545   this.ROMBank1offs = state[index++];
   5546   this.currentROMBank = state[index++];
   5547   this.cartridgeType = state[index++];
   5548   this.name = state[index++];
   5549   this.gameCode = state[index++];
   5550   this.modeSTAT = state[index++];
   5551   this.LYCMatchTriggerSTAT = state[index++];
   5552   this.mode2TriggerSTAT = state[index++];
   5553   this.mode1TriggerSTAT = state[index++];
   5554   this.mode0TriggerSTAT = state[index++];
   5555   this.LCDisOn = state[index++];
   5556   this.gfxWindowCHRBankPosition = state[index++];
   5557   this.gfxWindowDisplay = state[index++];
   5558   this.gfxSpriteShow = state[index++];
   5559   this.gfxSpriteNormalHeight = state[index++];
   5560   this.gfxBackgroundCHRBankPosition = state[index++];
   5561   this.gfxBackgroundBankOffset = state[index++];
   5562   this.TIMAEnabled = state[index++];
   5563   this.DIVTicks = state[index++];
   5564   this.LCDTicks = state[index++];
   5565   this.timerTicks = state[index++];
   5566   this.TACClocker = state[index++];
   5567   this.serialTimer = state[index++];
   5568   this.serialShiftTimer = state[index++];
   5569   this.serialShiftTimerAllocated = state[index++];
   5570   this.IRQEnableDelay = state[index++];
   5571   this.lastIteration = state[index++];
   5572   this.cMBC1 = state[index++];
   5573   this.cMBC2 = state[index++];
   5574   this.cMBC3 = state[index++];
   5575   this.cMBC5 = state[index++];
   5576   this.cMBC7 = state[index++];
   5577   this.cSRAM = state[index++];
   5578   this.cMMMO1 = state[index++];
   5579   this.cRUMBLE = state[index++];
   5580   this.cCamera = state[index++];
   5581   this.cTAMA5 = state[index++];
   5582   this.cHuC3 = state[index++];
   5583   this.cHuC1 = state[index++];
   5584   this.drewBlank = state[index++];
   5585   this.frameBuffer = this.toTypedArray(state[index++], "int32");
   5586   this.bgEnabled = state[index++];
   5587   this.BGPriorityEnabled = state[index++];
   5588   this.channel1FrequencyTracker = state[index++];
   5589   this.channel1FrequencyCounter = state[index++];
   5590   this.channel1totalLength = state[index++];
   5591   this.channel1envelopeVolume = state[index++];
   5592   this.channel1envelopeType = state[index++];
   5593   this.channel1envelopeSweeps = state[index++];
   5594   this.channel1envelopeSweepsLast = state[index++];
   5595   this.channel1consecutive = state[index++];
   5596   this.channel1frequency = state[index++];
   5597   this.channel1SweepFault = state[index++];
   5598   this.channel1ShadowFrequency = state[index++];
   5599   this.channel1timeSweep = state[index++];
   5600   this.channel1lastTimeSweep = state[index++];
   5601   this.channel1numSweep = state[index++];
   5602   this.channel1frequencySweepDivider = state[index++];
   5603   this.channel1decreaseSweep = state[index++];
   5604   this.channel2FrequencyTracker = state[index++];
   5605   this.channel2FrequencyCounter = state[index++];
   5606   this.channel2totalLength = state[index++];
   5607   this.channel2envelopeVolume = state[index++];
   5608   this.channel2envelopeType = state[index++];
   5609   this.channel2envelopeSweeps = state[index++];
   5610   this.channel2envelopeSweepsLast = state[index++];
   5611   this.channel2consecutive = state[index++];
   5612   this.channel2frequency = state[index++];
   5613   this.channel3canPlay = state[index++];
   5614   this.channel3totalLength = state[index++];
   5615   this.channel3patternType = state[index++];
   5616   this.channel3frequency = state[index++];
   5617   this.channel3consecutive = state[index++];
   5618   this.channel3PCM = this.toTypedArray(state[index++], "int8");
   5619   this.channel4FrequencyPeriod = state[index++];
   5620   this.channel4lastSampleLookup = state[index++];
   5621   this.channel4totalLength = state[index++];
   5622   this.channel4envelopeVolume = state[index++];
   5623   this.channel4currentVolume = state[index++];
   5624   this.channel4envelopeType = state[index++];
   5625   this.channel4envelopeSweeps = state[index++];
   5626   this.channel4envelopeSweepsLast = state[index++];
   5627   this.channel4consecutive = state[index++];
   5628   this.channel4BitRange = state[index++];
   5629   this.soundMasterEnabled = state[index++];
   5630   this.VinLeftChannelMasterVolume = state[index++];
   5631   this.VinRightChannelMasterVolume = state[index++];
   5632   this.leftChannel1 = state[index++];
   5633   this.leftChannel2 = state[index++];
   5634   this.leftChannel3 = state[index++];
   5635   this.leftChannel4 = state[index++];
   5636   this.rightChannel1 = state[index++];
   5637   this.rightChannel2 = state[index++];
   5638   this.rightChannel3 = state[index++];
   5639   this.rightChannel4 = state[index++];
   5640   this.channel1currentSampleLeft = state[index++];
   5641   this.channel1currentSampleRight = state[index++];
   5642   this.channel2currentSampleLeft = state[index++];
   5643   this.channel2currentSampleRight = state[index++];
   5644   this.channel3currentSampleLeft = state[index++];
   5645   this.channel3currentSampleRight = state[index++];
   5646   this.channel4currentSampleLeft = state[index++];
   5647   this.channel4currentSampleRight = state[index++];
   5648   this.channel1currentSampleLeftSecondary = state[index++];
   5649   this.channel1currentSampleRightSecondary = state[index++];
   5650   this.channel2currentSampleLeftSecondary = state[index++];
   5651   this.channel2currentSampleRightSecondary = state[index++];
   5652   this.channel3currentSampleLeftSecondary = state[index++];
   5653   this.channel3currentSampleRightSecondary = state[index++];
   5654   this.channel4currentSampleLeftSecondary = state[index++];
   5655   this.channel4currentSampleRightSecondary = state[index++];
   5656   this.channel1currentSampleLeftTrimary = state[index++];
   5657   this.channel1currentSampleRightTrimary = state[index++];
   5658   this.channel2currentSampleLeftTrimary = state[index++];
   5659   this.channel2currentSampleRightTrimary = state[index++];
   5660   this.mixerOutputCache = state[index++];
   5661   this.channel1DutyTracker = state[index++];
   5662   this.channel1CachedDuty = state[index++];
   5663   this.channel2DutyTracker = state[index++];
   5664   this.channel2CachedDuty = state[index++];
   5665   this.channel1Enabled = state[index++];
   5666   this.channel2Enabled = state[index++];
   5667   this.channel3Enabled = state[index++];
   5668   this.channel4Enabled = state[index++];
   5669   this.sequencerClocks = state[index++];
   5670   this.sequencePosition = state[index++];
   5671   this.channel3Counter = state[index++];
   5672   this.channel4Counter = state[index++];
   5673   this.cachedChannel3Sample = state[index++];
   5674   this.cachedChannel4Sample = state[index++];
   5675   this.channel3FrequencyPeriod = state[index++];
   5676   this.channel3lastSampleLookup = state[index++];
   5677   this.actualScanLine = state[index++];
   5678   this.lastUnrenderedLine = state[index++];
   5679   this.queuedScanLines = state[index++];
   5680   this.RTCisLatched = state[index++];
   5681   this.latchedSeconds = state[index++];
   5682   this.latchedMinutes = state[index++];
   5683   this.latchedHours = state[index++];
   5684   this.latchedLDays = state[index++];
   5685   this.latchedHDays = state[index++];
   5686   this.RTCSeconds = state[index++];
   5687   this.RTCMinutes = state[index++];
   5688   this.RTCHours = state[index++];
   5689   this.RTCDays = state[index++];
   5690   this.RTCDayOverFlow = state[index++];
   5691   this.RTCHALT = state[index++];
   5692   this.usedBootROM = state[index++];
   5693   this.skipPCIncrement = state[index++];
   5694   this.STATTracker = state[index++];
   5695   this.gbcRamBankPositionECHO = state[index++];
   5696   this.numRAMBanks = state[index++];
   5697   this.windowY = state[index++];
   5698   this.windowX = state[index++];
   5699   this.gbcOBJRawPalette = this.toTypedArray(state[index++], "uint8");
   5700   this.gbcBGRawPalette = this.toTypedArray(state[index++], "uint8");
   5701   this.gbOBJPalette = this.toTypedArray(state[index++], "int32");
   5702   this.gbBGPalette = this.toTypedArray(state[index++], "int32");
   5703   this.gbcOBJPalette = this.toTypedArray(state[index++], "int32");
   5704   this.gbcBGPalette = this.toTypedArray(state[index++], "int32");
   5705   this.gbBGColorizedPalette = this.toTypedArray(state[index++], "int32");
   5706   this.gbOBJColorizedPalette = this.toTypedArray(state[index++], "int32");
   5707   this.cachedBGPaletteConversion = this.toTypedArray(state[index++], "int32");
   5708   this.cachedOBJPaletteConversion = this.toTypedArray(state[index++], "int32");
   5709   this.BGCHRBank1 = this.toTypedArray(state[index++], "uint8");
   5710   this.BGCHRBank2 = this.toTypedArray(state[index++], "uint8");
   5711   this.haltPostClocks = state[index++];
   5712   this.interruptsRequested = state[index++];
   5713   this.interruptsEnabled = state[index++];
   5714   this.checkIRQMatching();
   5715   this.remainingClocks = state[index++];
   5716   this.colorizedGBPalettes = state[index++];
   5717   this.backgroundY = state[index++];
   5718   this.backgroundX = state[index++];
   5719   this.CPUStopped = state[index];
   5720   this.fromSaveState = true;
   5721   this.TICKTable = this.toTypedArray(this.TICKTable, "uint8");
   5722   this.SecondaryTICKTable = this.toTypedArray(this.SecondaryTICKTable, "uint8");
   5723   this.initializeReferencesFromSaveState();
   5724   this.memoryReadJumpCompile();
   5725   this.memoryWriteJumpCompile();
   5726   this.initLCD();
   5727   this.initSound();
   5728   this.noiseSampleTable = (this.channel4BitRange == 0x7FFF) ? this.LSFR15Table : this.LSFR7Table;
   5729   this.channel4VolumeShifter = (this.channel4BitRange == 0x7FFF) ? 15 : 7;
   5730 }
   5731 GameBoyCore.prototype.returnFromRTCState = function () {
   5732   if (typeof this.openRTC == "function" && this.cTIMER) {
   5733     var rtcData = this.openRTC(this.name);
   5734     var index = 0;
   5735     this.lastIteration = rtcData[index++];
   5736     this.RTCisLatched = rtcData[index++];
   5737     this.latchedSeconds = rtcData[index++];
   5738     this.latchedMinutes = rtcData[index++];
   5739     this.latchedHours = rtcData[index++];
   5740     this.latchedLDays = rtcData[index++];
   5741     this.latchedHDays = rtcData[index++];
   5742     this.RTCSeconds = rtcData[index++];
   5743     this.RTCMinutes = rtcData[index++];
   5744     this.RTCHours = rtcData[index++];
   5745     this.RTCDays = rtcData[index++];
   5746     this.RTCDayOverFlow = rtcData[index++];
   5747     this.RTCHALT = rtcData[index];
   5748   }
   5749 }
   5750 
   5751 GameBoyCore.prototype.start = function () {
   5752   this.initMemory();  //Write the startup memory.
   5753   this.ROMLoad();    //Load the ROM into memory and get cartridge information from it.
   5754   this.initLCD();    //Initialize the graphics.
   5755   this.initSound();  //Sound object initialization.
   5756   this.run();      //Start the emulation.
   5757 }
   5758 GameBoyCore.prototype.initMemory = function () {
   5759   //Initialize the RAM:
   5760   this.memory = this.getTypedArray(0x10000, 0, "uint8");
   5761   this.frameBuffer = this.getTypedArray(23040, 0xF8F8F8, "int32");
   5762   this.BGCHRBank1 = this.getTypedArray(0x800, 0, "uint8");
   5763   this.TICKTable = this.toTypedArray(this.TICKTable, "uint8");
   5764   this.SecondaryTICKTable = this.toTypedArray(this.SecondaryTICKTable, "uint8");
   5765   this.channel3PCM = this.getTypedArray(0x20, 0, "int8");
   5766 }
   5767 GameBoyCore.prototype.generateCacheArray = function (tileAmount) {
   5768   var tileArray = [];
   5769   var tileNumber = 0;
   5770   while (tileNumber < tileAmount) {
   5771     tileArray[tileNumber++] = this.getTypedArray(64, 0, "uint8");
   5772   }
   5773   return tileArray;
   5774 }
   5775 GameBoyCore.prototype.initSkipBootstrap = function () {
   5776   //Fill in the boot ROM set register values
   5777   //Default values to the GB boot ROM values, then fill in the GBC boot ROM values after ROM loading
   5778   var index = 0xFF;
   5779   while (index >= 0) {
   5780     if (index >= 0x30 && index < 0x40) {
   5781       this.memoryWrite(0xFF00 | index, this.ffxxDump[index]);
   5782     }
   5783     else {
   5784       switch (index) {
   5785         case 0x00:
   5786         case 0x01:
   5787         case 0x02:
   5788         case 0x05:
   5789         case 0x07:
   5790         case 0x0F:
   5791         case 0xFF:
   5792           this.memoryWrite(0xFF00 | index, this.ffxxDump[index]);
   5793           break;
   5794         default:
   5795           this.memory[0xFF00 | index] = this.ffxxDump[index];
   5796       }
   5797     }
   5798     --index;
   5799   }
   5800   if (this.cGBC) {
   5801     this.memory[0xFF6C] = 0xFE;
   5802     this.memory[0xFF74] = 0xFE;
   5803   }
   5804   else {
   5805     this.memory[0xFF48] = 0xFF;
   5806     this.memory[0xFF49] = 0xFF;
   5807     this.memory[0xFF6C] = 0xFF;
   5808     this.memory[0xFF74] = 0xFF;
   5809   }
   5810   //Start as an unset device:
   5811   cout("Starting without the GBC boot ROM.", 0);
   5812   this.registerA = (this.cGBC) ? 0x11 : 0x1;
   5813   this.registerB = 0;
   5814   this.registerC = 0x13;
   5815   this.registerD = 0;
   5816   this.registerE = 0xD8;
   5817   this.FZero = true;
   5818   this.FSubtract = false;
   5819   this.FHalfCarry = true;
   5820   this.FCarry = true;
   5821   this.registersHL = 0x014D;
   5822   this.LCDCONTROL = this.LINECONTROL;
   5823   this.IME = false;
   5824   this.IRQLineMatched = 0;
   5825   this.interruptsRequested = 225;
   5826   this.interruptsEnabled = 0;
   5827   this.hdmaRunning = false;
   5828   this.CPUTicks = 12;
   5829   this.STATTracker = 0;
   5830   this.modeSTAT = 1;
   5831   this.spriteCount = 252;
   5832   this.LYCMatchTriggerSTAT = false;
   5833   this.mode2TriggerSTAT = false;
   5834   this.mode1TriggerSTAT = false;
   5835   this.mode0TriggerSTAT = false;
   5836   this.LCDisOn = true;
   5837   this.channel1FrequencyTracker = 0x2000;
   5838   this.channel1DutyTracker = 0;
   5839   this.channel1CachedDuty = this.dutyLookup[2];
   5840   this.channel1totalLength = 0;
   5841   this.channel1envelopeVolume = 0;
   5842   this.channel1envelopeType = false;
   5843   this.channel1envelopeSweeps = 0;
   5844   this.channel1envelopeSweepsLast = 0;
   5845   this.channel1consecutive = true;
   5846   this.channel1frequency = 1985;
   5847   this.channel1SweepFault = true;
   5848   this.channel1ShadowFrequency = 1985;
   5849   this.channel1timeSweep = 1;
   5850   this.channel1lastTimeSweep = 0;
   5851   this.channel1numSweep = 0;
   5852   this.channel1frequencySweepDivider = 0;
   5853   this.channel1decreaseSweep = false;
   5854   this.channel2FrequencyTracker = 0x2000;
   5855   this.channel2DutyTracker = 0;
   5856   this.channel2CachedDuty = this.dutyLookup[2];
   5857   this.channel2totalLength = 0;
   5858   this.channel2envelopeVolume = 0;
   5859   this.channel2envelopeType = false;
   5860   this.channel2envelopeSweeps = 0;
   5861   this.channel2envelopeSweepsLast = 0;
   5862   this.channel2consecutive = true;
   5863   this.channel2frequency = 0;
   5864   this.channel3canPlay = false;
   5865   this.channel3totalLength = 0;
   5866   this.channel3patternType = 4;
   5867   this.channel3frequency = 0;
   5868   this.channel3consecutive = true;
   5869   this.channel3Counter = 0x418;
   5870   this.channel4FrequencyPeriod = 8;
   5871   this.channel4totalLength = 0;
   5872   this.channel4envelopeVolume = 0;
   5873   this.channel4currentVolume = 0;
   5874   this.channel4envelopeType = false;
   5875   this.channel4envelopeSweeps = 0;
   5876   this.channel4envelopeSweepsLast = 0;
   5877   this.channel4consecutive = true;
   5878   this.channel4BitRange = 0x7FFF;
   5879   this.channel4VolumeShifter = 15;
   5880   this.channel1FrequencyCounter = 0x200;
   5881   this.channel2FrequencyCounter = 0x200;
   5882   this.channel3Counter = 0x800;
   5883   this.channel3FrequencyPeriod = 0x800;
   5884   this.channel3lastSampleLookup = 0;
   5885   this.channel4lastSampleLookup = 0;
   5886   this.VinLeftChannelMasterVolume = 1;
   5887   this.VinRightChannelMasterVolume = 1;
   5888   this.soundMasterEnabled = true;
   5889   this.leftChannel1 = true;
   5890   this.leftChannel2 = true;
   5891   this.leftChannel3 = true;
   5892   this.leftChannel4 = true;
   5893   this.rightChannel1 = true;
   5894   this.rightChannel2 = true;
   5895   this.rightChannel3 = false;
   5896   this.rightChannel4 = false;
   5897   this.DIVTicks = 27044;
   5898   this.LCDTicks = 160;
   5899   this.timerTicks = 0;
   5900   this.TIMAEnabled = false;
   5901   this.TACClocker = 1024;
   5902   this.serialTimer = 0;
   5903   this.serialShiftTimer = 0;
   5904   this.serialShiftTimerAllocated = 0;
   5905   this.IRQEnableDelay = 0;
   5906   this.actualScanLine = 144;
   5907   this.lastUnrenderedLine = 0;
   5908   this.gfxWindowDisplay = false;
   5909   this.gfxSpriteShow = false;
   5910   this.gfxSpriteNormalHeight = true;
   5911   this.bgEnabled = true;
   5912   this.BGPriorityEnabled = true;
   5913   this.gfxWindowCHRBankPosition = 0;
   5914   this.gfxBackgroundCHRBankPosition = 0;
   5915   this.gfxBackgroundBankOffset = 0;
   5916   this.windowY = 0;
   5917   this.windowX = 0;
   5918   this.drewBlank = 0;
   5919   this.midScanlineOffset = -1;
   5920   this.currentX = 0;
   5921 }
   5922 GameBoyCore.prototype.initBootstrap = function () {
   5923   //Start as an unset device:
   5924   cout("Starting the selected boot ROM.", 0);
   5925   this.programCounter = 0;
   5926   this.stackPointer = 0;
   5927   this.IME = false;
   5928   this.LCDTicks = 0;
   5929   this.DIVTicks = 0;
   5930   this.registerA = 0;
   5931   this.registerB = 0;
   5932   this.registerC = 0;
   5933   this.registerD = 0;
   5934   this.registerE = 0;
   5935   this.FZero = this.FSubtract = this.FHalfCarry = this.FCarry = false;
   5936   this.registersHL = 0;
   5937   this.leftChannel1 = false;
   5938   this.leftChannel2 = false;
   5939   this.leftChannel3 = false;
   5940   this.leftChannel4 = false;
   5941   this.rightChannel1 = false;
   5942   this.rightChannel2 = false;
   5943   this.rightChannel3 = false;
   5944   this.rightChannel4 = false;
   5945   this.channel2frequency = this.channel1frequency = 0;
   5946   this.channel4consecutive = this.channel2consecutive = this.channel1consecutive = false;
   5947   this.VinLeftChannelMasterVolume = 8;
   5948   this.VinRightChannelMasterVolume = 8;
   5949   this.memory[0xFF00] = 0xF;  //Set the joypad state.
   5950 }
   5951 GameBoyCore.prototype.ROMLoad = function () {
   5952   //Load the first two ROM banks (0x0000 - 0x7FFF) into regular gameboy memory:
   5953   this.ROM = [];
   5954   this.usedBootROM = settings[1];
   5955   var maxLength = this.ROMImage.length;
   5956   if (maxLength < 0x4000) {
   5957     throw(new Error("ROM image size too small."));
   5958   }
   5959   this.ROM = this.getTypedArray(maxLength, 0, "uint8");
   5960   var romIndex = 0;
   5961   if (this.usedBootROM) {
   5962     if (!settings[11]) {
   5963       //Patch in the GBC boot ROM into the memory map:
   5964       for (; romIndex < 0x100; ++romIndex) {
   5965         this.memory[romIndex] = this.GBCBOOTROM[romIndex];                      //Load in the GameBoy Color BOOT ROM.
   5966         this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF);              //Decode the ROM binary for the switch out.
   5967       }
   5968       for (; romIndex < 0x200; ++romIndex) {
   5969         this.memory[romIndex] = this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF);  //Load in the game ROM.
   5970       }
   5971       for (; romIndex < 0x900; ++romIndex) {
   5972         this.memory[romIndex] = this.GBCBOOTROM[romIndex - 0x100];                  //Load in the GameBoy Color BOOT ROM.
   5973         this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF);              //Decode the ROM binary for the switch out.
   5974       }
   5975       this.usedGBCBootROM = true;
   5976     }
   5977     else {
   5978       //Patch in the GBC boot ROM into the memory map:
   5979       for (; romIndex < 0x100; ++romIndex) {
   5980         this.memory[romIndex] = this.GBBOOTROM[romIndex];                      //Load in the GameBoy Color BOOT ROM.
   5981         this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF);              //Decode the ROM binary for the switch out.
   5982       }
   5983     }
   5984     for (; romIndex < 0x4000; ++romIndex) {
   5985       this.memory[romIndex] = this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF);  //Load in the game ROM.
   5986     }
   5987   }
   5988   else {
   5989     //Don't load in the boot ROM:
   5990     for (; romIndex < 0x4000; ++romIndex) {
   5991       this.memory[romIndex] = this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF);  //Load in the game ROM.
   5992     }
   5993   }
   5994   //Finish the decoding of the ROM binary:
   5995   for (; romIndex < maxLength; ++romIndex) {
   5996     this.ROM[romIndex] = (this.ROMImage.charCodeAt(romIndex) & 0xFF);
   5997   }
   5998   this.ROMBankEdge = Math.floor(this.ROM.length / 0x4000);
   5999   //Set up the emulator for the cartidge specifics:
   6000   this.interpretCartridge();
   6001   //Check for IRQ matching upon initialization:
   6002   this.checkIRQMatching();
   6003 }
   6004 GameBoyCore.prototype.getROMImage = function () {
   6005   //Return the binary version of the ROM image currently running:
   6006   if (this.ROMImage.length > 0) {
   6007     return this.ROMImage.length;
   6008   }
   6009   var length = this.ROM.length;
   6010   for (var index = 0; index < length; index++) {
   6011     this.ROMImage += String.fromCharCode(this.ROM[index]);
   6012   }
   6013   return this.ROMImage;
   6014 }
   6015 GameBoyCore.prototype.interpretCartridge = function () {
   6016   // ROM name
   6017   for (var index = 0x134; index < 0x13F; index++) {
   6018     if (this.ROMImage.charCodeAt(index) > 0) {
   6019       this.name += this.ROMImage[index];
   6020     }
   6021   }
   6022   // ROM game code (for newer games)
   6023   for (var index = 0x13F; index < 0x143; index++) {
   6024     if (this.ROMImage.charCodeAt(index) > 0) {
   6025       this.gameCode += this.ROMImage[index];
   6026     }
   6027   }
   6028   cout("Game Title: " + this.name + "[" + this.gameCode + "][" + this.ROMImage[0x143] + "]", 0);
   6029   cout("Game Code: " + this.gameCode, 0);
   6030   // Cartridge type
   6031   this.cartridgeType = this.ROM[0x147];
   6032   cout("Cartridge type #" + this.cartridgeType, 0);
   6033   //Map out ROM cartridge sub-types.
   6034   var MBCType = "";
   6035   switch (this.cartridgeType) {
   6036     case 0x00:
   6037       //ROM w/o bank switching
   6038       if (!settings[9]) {
   6039         MBCType = "ROM";
   6040         break;
   6041       }
   6042     case 0x01:
   6043       this.cMBC1 = true;
   6044       MBCType = "MBC1";
   6045       break;
   6046     case 0x02:
   6047       this.cMBC1 = true;
   6048       this.cSRAM = true;
   6049       MBCType = "MBC1 + SRAM";
   6050       break;
   6051     case 0x03:
   6052       this.cMBC1 = true;
   6053       this.cSRAM = true;
   6054       this.cBATT = true;
   6055       MBCType = "MBC1 + SRAM + BATT";
   6056       break;
   6057     case 0x05:
   6058       this.cMBC2 = true;
   6059       MBCType = "MBC2";
   6060       break;
   6061     case 0x06:
   6062       this.cMBC2 = true;
   6063       this.cBATT = true;
   6064       MBCType = "MBC2 + BATT";
   6065       break;
   6066     case 0x08:
   6067       this.cSRAM = true;
   6068       MBCType = "ROM + SRAM";
   6069       break;
   6070     case 0x09:
   6071       this.cSRAM = true;
   6072       this.cBATT = true;
   6073       MBCType = "ROM + SRAM + BATT";
   6074       break;
   6075     case 0x0B:
   6076       this.cMMMO1 = true;
   6077       MBCType = "MMMO1";
   6078       break;
   6079     case 0x0C:
   6080       this.cMMMO1 = true;
   6081       this.cSRAM = true;
   6082       MBCType = "MMMO1 + SRAM";
   6083       break;
   6084     case 0x0D:
   6085       this.cMMMO1 = true;
   6086       this.cSRAM = true;
   6087       this.cBATT = true;
   6088       MBCType = "MMMO1 + SRAM + BATT";
   6089       break;
   6090     case 0x0F:
   6091       this.cMBC3 = true;
   6092       this.cTIMER = true;
   6093       this.cBATT = true;
   6094       MBCType = "MBC3 + TIMER + BATT";
   6095       break;
   6096     case 0x10:
   6097       this.cMBC3 = true;
   6098       this.cTIMER = true;
   6099       this.cBATT = true;
   6100       this.cSRAM = true;
   6101       MBCType = "MBC3 + TIMER + BATT + SRAM";
   6102       break;
   6103     case 0x11:
   6104       this.cMBC3 = true;
   6105       MBCType = "MBC3";
   6106       break;
   6107     case 0x12:
   6108       this.cMBC3 = true;
   6109       this.cSRAM = true;
   6110       MBCType = "MBC3 + SRAM";
   6111       break;
   6112     case 0x13:
   6113       this.cMBC3 = true;
   6114       this.cSRAM = true;
   6115       this.cBATT = true;
   6116       MBCType = "MBC3 + SRAM + BATT";
   6117       break;
   6118     case 0x19:
   6119       this.cMBC5 = true;
   6120       MBCType = "MBC5";
   6121       break;
   6122     case 0x1A:
   6123       this.cMBC5 = true;
   6124       this.cSRAM = true;
   6125       MBCType = "MBC5 + SRAM";
   6126       break;
   6127     case 0x1B:
   6128       this.cMBC5 = true;
   6129       this.cSRAM = true;
   6130       this.cBATT = true;
   6131       MBCType = "MBC5 + SRAM + BATT";
   6132       break;
   6133     case 0x1C:
   6134       this.cRUMBLE = true;
   6135       MBCType = "RUMBLE";
   6136       break;
   6137     case 0x1D:
   6138       this.cRUMBLE = true;
   6139       this.cSRAM = true;
   6140       MBCType = "RUMBLE + SRAM";
   6141       break;
   6142     case 0x1E:
   6143       this.cRUMBLE = true;
   6144       this.cSRAM = true;
   6145       this.cBATT = true;
   6146       MBCType = "RUMBLE + SRAM + BATT";
   6147       break;
   6148     case 0x1F:
   6149       this.cCamera = true;
   6150       MBCType = "GameBoy Camera";
   6151       break;
   6152     case 0x22:
   6153       this.cMBC7 = true;
   6154       this.cSRAM = true;
   6155       this.cBATT = true;
   6156       MBCType = "MBC7 + SRAM + BATT";
   6157       break;
   6158     case 0xFD:
   6159       this.cTAMA5 = true;
   6160       MBCType = "TAMA5";
   6161       break;
   6162     case 0xFE:
   6163       this.cHuC3 = true;
   6164       MBCType = "HuC3";
   6165       break;
   6166     case 0xFF:
   6167       this.cHuC1 = true;
   6168       MBCType = "HuC1";
   6169       break;
   6170     default:
   6171       MBCType = "Unknown";
   6172       cout("Cartridge type is unknown.", 2);
   6173       pause();
   6174   }
   6175   cout("Cartridge Type: " + MBCType + ".", 0);
   6176   // ROM and RAM banks
   6177   this.numROMBanks = this.ROMBanks[this.ROM[0x148]];
   6178   cout(this.numROMBanks + " ROM banks.", 0);
   6179   switch (this.RAMBanks[this.ROM[0x149]]) {
   6180     case 0:
   6181       cout("No RAM banking requested for allocation or MBC is of type 2.", 0);
   6182       break;
   6183     case 2:
   6184       cout("1 RAM bank requested for allocation.", 0);
   6185       break;
   6186     case 3:
   6187       cout("4 RAM banks requested for allocation.", 0);
   6188       break;
   6189     case 4:
   6190       cout("16 RAM banks requested for allocation.", 0);
   6191       break;
   6192     default:
   6193       cout("RAM bank amount requested is unknown, will use maximum allowed by specified MBC type.", 0);
   6194   }
   6195   //Check the GB/GBC mode byte:
   6196   if (!this.usedBootROM) {
   6197     switch (this.ROM[0x143]) {
   6198       case 0x00:  //Only GB mode
   6199         this.cGBC = false;
   6200         cout("Only GB mode detected.", 0);
   6201         break;
   6202       case 0x32:  //Exception to the GBC identifying code:
   6203         if (!settings[2] && this.name + this.gameCode + this.ROM[0x143] == "Game and Watch 50") {
   6204           this.cGBC = true;
   6205           cout("Created a boot exception for Game and Watch Gallery 2 (GBC ID byte is wrong on the cartridge).", 1);
   6206         }
   6207         else {
   6208           this.cGBC = false;
   6209         }
   6210         break;
   6211       case 0x80:  //Both GB + GBC modes
   6212         this.cGBC = !settings[2];
   6213         cout("GB and GBC mode detected.", 0);
   6214         break;
   6215       case 0xC0:  //Only GBC mode
   6216         this.cGBC = true;
   6217         cout("Only GBC mode detected.", 0);
   6218         break;
   6219       default:
   6220         this.cGBC = false;
   6221         cout("Unknown GameBoy game type code #" + this.ROM[0x143] + ", defaulting to GB mode (Old games don't have a type code).", 1);
   6222     }
   6223     this.inBootstrap = false;
   6224     this.setupRAM();  //CPU/(V)RAM initialization.
   6225     this.initSkipBootstrap();
   6226     this.initializeAudioStartState(); // Line added for benchmarking.
   6227   }
   6228   else {
   6229     this.cGBC = this.usedGBCBootROM;  //Allow the GBC boot ROM to run in GBC mode...
   6230     this.setupRAM();  //CPU/(V)RAM initialization.
   6231     this.initBootstrap();
   6232   }
   6233   this.initializeModeSpecificArrays();
   6234   //License Code Lookup:
   6235   var cOldLicense = this.ROM[0x14B];
   6236   var cNewLicense = (this.ROM[0x144] & 0xFF00) | (this.ROM[0x145] & 0xFF);
   6237   if (cOldLicense != 0x33) {
   6238     //Old Style License Header
   6239     cout("Old style license code: " + cOldLicense, 0);
   6240   }
   6241   else {
   6242     //New Style License Header
   6243     cout("New style license code: " + cNewLicense, 0);
   6244   }
   6245   this.ROMImage = "";  //Memory consumption reduction.
   6246 }
   6247 GameBoyCore.prototype.disableBootROM = function () {
   6248   //Remove any traces of the boot ROM from ROM memory.
   6249   for (var index = 0; index < 0x100; ++index) {
   6250     this.memory[index] = this.ROM[index];  //Replace the GameBoy or GameBoy Color boot ROM with the game ROM.
   6251   }
   6252   if (this.usedGBCBootROM) {
   6253     //Remove any traces of the boot ROM from ROM memory.
   6254     for (index = 0x200; index < 0x900; ++index) {
   6255       this.memory[index] = this.ROM[index];  //Replace the GameBoy Color boot ROM with the game ROM.
   6256     }
   6257     if (!this.cGBC) {
   6258       //Clean up the post-boot (GB mode only) state:
   6259       this.GBCtoGBModeAdjust();
   6260     }
   6261     else {
   6262       this.recompileBootIOWriteHandling();
   6263     }
   6264   }
   6265   else {
   6266     this.recompileBootIOWriteHandling();
   6267   }
   6268 }
   6269 GameBoyCore.prototype.initializeTiming = function () {
   6270   //Emulator Timing:
   6271   this.baseCPUCyclesPerIteration = 0x80000 / 0x7D * settings[6];
   6272   this.CPUCyclesTotalRoundoff = this.baseCPUCyclesPerIteration % 4;
   6273   this.CPUCyclesTotalBase = this.CPUCyclesTotal = (this.baseCPUCyclesPerIteration - this.CPUCyclesTotalRoundoff) | 0;
   6274   this.CPUCyclesTotalCurrent = 0;
   6275 }
   6276 GameBoyCore.prototype.setupRAM = function () {
   6277   //Setup the auxilliary/switchable RAM:
   6278   if (this.cMBC2) {
   6279     this.numRAMBanks = 1 / 16;
   6280   }
   6281   else if (this.cMBC1 || this.cRUMBLE || this.cMBC3 || this.cHuC3) {
   6282     this.numRAMBanks = 4;
   6283   }
   6284   else if (this.cMBC5) {
   6285     this.numRAMBanks = 16;
   6286   }
   6287   else if (this.cSRAM) {
   6288     this.numRAMBanks = 1;
   6289   }
   6290   if (this.numRAMBanks > 0) {
   6291     if (!this.MBCRAMUtilized()) {
   6292       //For ROM and unknown MBC cartridges using the external RAM:
   6293       this.MBCRAMBanksEnabled = true;
   6294     }
   6295     //Switched RAM Used
   6296     var MBCRam = (typeof this.openMBC == "function") ? this.openMBC(this.name) : [];
   6297     if (MBCRam.length > 0) {
   6298       //Flash the SRAM into memory:
   6299       this.MBCRam = this.toTypedArray(MBCRam, "uint8");
   6300     }
   6301     else {
   6302       this.MBCRam = this.getTypedArray(this.numRAMBanks * 0x2000, 0, "uint8");
   6303     }
   6304   }
   6305   cout("Actual bytes of MBC RAM allocated: " + (this.numRAMBanks * 0x2000), 0);
   6306   this.returnFromRTCState();
   6307   //Setup the RAM for GBC mode.
   6308   if (this.cGBC) {
   6309     this.VRAM = this.getTypedArray(0x2000, 0, "uint8");
   6310     this.GBCMemory = this.getTypedArray(0x7000, 0, "uint8");
   6311   }
   6312   this.memoryReadJumpCompile();
   6313   this.memoryWriteJumpCompile();
   6314 }
   6315 GameBoyCore.prototype.MBCRAMUtilized = function () {
   6316   return this.cMBC1 || this.cMBC2 || this.cMBC3 || this.cMBC5 || this.cMBC7 || this.cRUMBLE;
   6317 }
   6318 GameBoyCore.prototype.recomputeDimension = function () {
   6319   initNewCanvas();
   6320   //Cache some dimension info:
   6321   this.onscreenWidth = this.canvas.width;
   6322   this.onscreenHeight = this.canvas.height;
   6323   // The following line was modified for benchmarking:
   6324   if (GameBoyWindow && GameBoyWindow.mozRequestAnimationFrame) {
   6325     //Firefox slowness hack:
   6326     this.canvas.width = this.onscreenWidth = (!settings[12]) ? 160 : this.canvas.width;
   6327     this.canvas.height = this.onscreenHeight = (!settings[12]) ? 144 : this.canvas.height;
   6328   }
   6329   else {
   6330     this.onscreenWidth = this.canvas.width;
   6331     this.onscreenHeight = this.canvas.height;
   6332   }
   6333   this.offscreenWidth = (!settings[12]) ? 160 : this.canvas.width;
   6334   this.offscreenHeight = (!settings[12]) ? 144 : this.canvas.height;
   6335   this.offscreenRGBCount = this.offscreenWidth * this.offscreenHeight * 4;
   6336 }
   6337 GameBoyCore.prototype.initLCD = function () {
   6338   this.recomputeDimension();
   6339   if (this.offscreenRGBCount != 92160) {
   6340     //Only create the resizer handle if we need it:
   6341     this.compileResizeFrameBufferFunction();
   6342   }
   6343   else {
   6344     //Resizer not needed:
   6345     this.resizer = null;
   6346   }
   6347   try {
   6348     this.canvasOffscreen = new GameBoyCanvas();  // Line modified for benchmarking.
   6349     this.canvasOffscreen.width = this.offscreenWidth;
   6350     this.canvasOffscreen.height = this.offscreenHeight;
   6351     this.drawContextOffscreen = this.canvasOffscreen.getContext("2d");
   6352     this.drawContextOnscreen = this.canvas.getContext("2d");
   6353     //Get a CanvasPixelArray buffer:
   6354     try {
   6355       this.canvasBuffer = this.drawContextOffscreen.createImageData(this.offscreenWidth, this.offscreenHeight);
   6356     }
   6357     catch (error) {
   6358       cout("Falling back to the getImageData initialization (Error \"" + error.message + "\").", 1);
   6359       this.canvasBuffer = this.drawContextOffscreen.getImageData(0, 0, this.offscreenWidth, this.offscreenHeight);
   6360     }
   6361     var index = this.offscreenRGBCount;
   6362     while (index > 0) {
   6363       this.canvasBuffer.data[index -= 4] = 0xF8;
   6364       this.canvasBuffer.data[index + 1] = 0xF8;
   6365       this.canvasBuffer.data[index + 2] = 0xF8;
   6366       this.canvasBuffer.data[index + 3] = 0xFF;
   6367     }
   6368     this.graphicsBlit();
   6369     this.canvas.style.visibility = "visible";
   6370     if (this.swizzledFrame == null) {
   6371       this.swizzledFrame = this.getTypedArray(69120, 0xFF, "uint8");
   6372     }
   6373     //Test the draw system and browser vblank latching:
   6374     this.drewFrame = true;                    //Copy the latest graphics to buffer.
   6375     this.requestDraw();
   6376   }
   6377   catch (error) {
   6378     throw(new Error("HTML5 Canvas support required: " + error.message + "file: " + error.fileName + ", line: " + error.lineNumber));
   6379   }
   6380 }
   6381 GameBoyCore.prototype.graphicsBlit = function () {
   6382   if (this.offscreenWidth == this.onscreenWidth && this.offscreenHeight == this.onscreenHeight) {
   6383     this.drawContextOnscreen.putImageData(this.canvasBuffer, 0, 0);
   6384   }
   6385   else {
   6386     this.drawContextOffscreen.putImageData(this.canvasBuffer, 0, 0);
   6387     this.drawContextOnscreen.drawImage(this.canvasOffscreen, 0, 0, this.onscreenWidth, this.onscreenHeight);
   6388   }
   6389 }
   6390 GameBoyCore.prototype.JoyPadEvent = function (key, down) {
   6391   if (down) {
   6392     this.JoyPad &= 0xFF ^ (1 << key);
   6393     if (!this.cGBC && (!this.usedBootROM || !this.usedGBCBootROM)) {
   6394       this.interruptsRequested |= 0x10;  //A real GBC doesn't set this!
   6395       this.remainingClocks = 0;
   6396       this.checkIRQMatching();
   6397     }
   6398   }
   6399   else {
   6400     this.JoyPad |= (1 << key);
   6401   }
   6402   this.memory[0xFF00] = (this.memory[0xFF00] & 0x30) + ((((this.memory[0xFF00] & 0x20) == 0) ? (this.JoyPad >> 4) : 0xF) & (((this.memory[0xFF00] & 0x10) == 0) ? (this.JoyPad & 0xF) : 0xF));
   6403   this.CPUStopped = false;
   6404 }
   6405 GameBoyCore.prototype.GyroEvent = function (x, y) {
   6406   x *= -100;
   6407   x += 2047;
   6408   this.highX = x >> 8;
   6409   this.lowX = x & 0xFF;
   6410   y *= -100;
   6411   y += 2047;
   6412   this.highY = y >> 8;
   6413   this.lowY = y & 0xFF;
   6414 }
   6415 GameBoyCore.prototype.initSound = function () {
   6416   this.sampleSize = 0x400000 / 1000 * settings[6];
   6417   this.machineOut = settings[13];
   6418   if (settings[0]) {
   6419     try {
   6420       var parentObj = this;
   6421       this.audioHandle = new XAudioServer(2, 0x400000 / settings[13], 0, Math.max(this.sampleSize * settings[8] / settings[13], 8192) << 1, null, settings[14]);
   6422       this.initAudioBuffer();
   6423     }
   6424     catch (error) {
   6425       cout("Audio system cannot run: " + error.message, 2);
   6426       settings[0] = false;
   6427     }
   6428   }
   6429   else if (this.audioHandle) {
   6430     //Mute the audio output, as it has an immediate silencing effect:
   6431     try {
   6432       this.audioHandle.changeVolume(0);
   6433     }
   6434     catch (error) { }
   6435   }
   6436 }
   6437 GameBoyCore.prototype.changeVolume = function () {
   6438   if (settings[0] && this.audioHandle) {
   6439     try {
   6440       this.audioHandle.changeVolume(settings[14]);
   6441     }
   6442     catch (error) { }
   6443   }
   6444 }
   6445 GameBoyCore.prototype.initAudioBuffer = function () {
   6446   this.audioIndex = 0;
   6447   this.bufferContainAmount = Math.max(this.sampleSize * settings[7] / settings[13], 4096) << 1;
   6448   this.numSamplesTotal = (this.sampleSize - (this.sampleSize % settings[13])) | 0;
   6449   this.currentBuffer = this.getTypedArray(this.numSamplesTotal, 0xF0F0, "int32");
   6450   this.secondaryBuffer = this.getTypedArray((this.numSamplesTotal << 1) / settings[13], 0, "float32");
   6451 }
   6452 GameBoyCore.prototype.intializeWhiteNoise = function () {
   6453   //Noise Sample Tables:
   6454   var randomFactor = 1;
   6455   //15-bit LSFR Cache Generation:
   6456   this.LSFR15Table = this.getTypedArray(0x80000, 0, "int8");
   6457   var LSFR = 0x7FFF;  //Seed value has all its bits set.
   6458   var LSFRShifted = 0x3FFF;
   6459   for (var index = 0; index < 0x8000; ++index) {
   6460     //Normalize the last LSFR value for usage:
   6461     randomFactor = 1 - (LSFR & 1);  //Docs say it's the inverse.
   6462     //Cache the different volume level results:
   6463     this.LSFR15Table[0x08000 | index] = randomFactor;
   6464     this.LSFR15Table[0x10000 | index] = randomFactor * 0x2;
   6465     this.LSFR15Table[0x18000 | index] = randomFactor * 0x3;
   6466     this.LSFR15Table[0x20000 | index] = randomFactor * 0x4;
   6467     this.LSFR15Table[0x28000 | index] = randomFactor * 0x5;
   6468     this.LSFR15Table[0x30000 | index] = randomFactor * 0x6;
   6469     this.LSFR15Table[0x38000 | index] = randomFactor * 0x7;
   6470     this.LSFR15Table[0x40000 | index] = randomFactor * 0x8;
   6471     this.LSFR15Table[0x48000 | index] = randomFactor * 0x9;
   6472     this.LSFR15Table[0x50000 | index] = randomFactor * 0xA;
   6473     this.LSFR15Table[0x58000 | index] = randomFactor * 0xB;
   6474     this.LSFR15Table[0x60000 | index] = randomFactor * 0xC;
   6475     this.LSFR15Table[0x68000 | index] = randomFactor * 0xD;
   6476     this.LSFR15Table[0x70000 | index] = randomFactor * 0xE;
   6477     this.LSFR15Table[0x78000 | index] = randomFactor * 0xF;
   6478     //Recompute the LSFR algorithm:
   6479     LSFRShifted = LSFR >> 1;
   6480     LSFR = LSFRShifted | (((LSFRShifted ^ LSFR) & 0x1) << 14);
   6481   }
   6482   //7-bit LSFR Cache Generation:
   6483   this.LSFR7Table = this.getTypedArray(0x800, 0, "int8");
   6484   LSFR = 0x7F;  //Seed value has all its bits set.
   6485   for (index = 0; index < 0x80; ++index) {
   6486     //Normalize the last LSFR value for usage:
   6487     randomFactor = 1 - (LSFR & 1);  //Docs say it's the inverse.
   6488     //Cache the different volume level results:
   6489     this.LSFR7Table[0x080 | index] = randomFactor;
   6490     this.LSFR7Table[0x100 | index] = randomFactor * 0x2;
   6491     this.LSFR7Table[0x180 | index] = randomFactor * 0x3;
   6492     this.LSFR7Table[0x200 | index] = randomFactor * 0x4;
   6493     this.LSFR7Table[0x280 | index] = randomFactor * 0x5;
   6494     this.LSFR7Table[0x300 | index] = randomFactor * 0x6;
   6495     this.LSFR7Table[0x380 | index] = randomFactor * 0x7;
   6496     this.LSFR7Table[0x400 | index] = randomFactor * 0x8;
   6497     this.LSFR7Table[0x480 | index] = randomFactor * 0x9;
   6498     this.LSFR7Table[0x500 | index] = randomFactor * 0xA;
   6499     this.LSFR7Table[0x580 | index] = randomFactor * 0xB;
   6500     this.LSFR7Table[0x600 | index] = randomFactor * 0xC;
   6501     this.LSFR7Table[0x680 | index] = randomFactor * 0xD;
   6502     this.LSFR7Table[0x700 | index] = randomFactor * 0xE;
   6503     this.LSFR7Table[0x780 | index] = randomFactor * 0xF;
   6504     //Recompute the LSFR algorithm:
   6505     LSFRShifted = LSFR >> 1;
   6506     LSFR = LSFRShifted | (((LSFRShifted ^ LSFR) & 0x1) << 6);
   6507   }
   6508   if (!this.noiseSampleTable && this.memory.length == 0x10000) {
   6509     //If enabling audio for the first time after a game is already running, set up the internal table reference:
   6510     this.noiseSampleTable = ((this.memory[0xFF22] & 0x8) == 0x8) ? this.LSFR7Table : this.LSFR15Table;
   6511   }
   6512 }
   6513 GameBoyCore.prototype.audioUnderrunAdjustment = function () {
   6514   if (settings[0]) {
   6515     var underrunAmount = this.bufferContainAmount - this.audioHandle.remainingBuffer();
   6516     if (underrunAmount > 0) {
   6517       this.CPUCyclesTotalCurrent += (underrunAmount >> 1) * this.machineOut;
   6518       this.recalculateIterationClockLimit();
   6519     }
   6520   }
   6521 }
   6522 GameBoyCore.prototype.initializeAudioStartState = function () {
   6523   this.channel1FrequencyTracker = 0x2000;
   6524   this.channel1DutyTracker = 0;
   6525   this.channel1CachedDuty = this.dutyLookup[2];
   6526   this.channel1totalLength = 0;
   6527   this.channel1envelopeVolume = 0;
   6528   this.channel1envelopeType = false;
   6529   this.channel1envelopeSweeps = 0;
   6530   this.channel1envelopeSweepsLast = 0;
   6531   this.channel1consecutive = true;
   6532   this.channel1frequency = 0;
   6533   this.channel1SweepFault = false;
   6534   this.channel1ShadowFrequency = 0;
   6535   this.channel1timeSweep = 1;
   6536   this.channel1lastTimeSweep = 0;
   6537   this.channel1numSweep = 0;
   6538   this.channel1frequencySweepDivider = 0;
   6539   this.channel1decreaseSweep = false;
   6540   this.channel2FrequencyTracker = 0x2000;
   6541   this.channel2DutyTracker = 0;
   6542   this.channel2CachedDuty = this.dutyLookup[2];
   6543   this.channel2totalLength = 0;
   6544   this.channel2envelopeVolume = 0;
   6545   this.channel2envelopeType = false;
   6546   this.channel2envelopeSweeps = 0;
   6547   this.channel2envelopeSweepsLast = 0;
   6548   this.channel2consecutive = true;
   6549   this.channel2frequency = 0;
   6550   this.channel3canPlay = false;
   6551   this.channel3totalLength = 0;
   6552   this.channel3patternType = 4;
   6553   this.channel3frequency = 0;
   6554   this.channel3consecutive = true;
   6555   this.channel3Counter = 0x800;
   6556   this.channel4FrequencyPeriod = 8;
   6557   this.channel4totalLength = 0;
   6558   this.channel4envelopeVolume = 0;
   6559   this.channel4currentVolume = 0;
   6560   this.channel4envelopeType = false;
   6561   this.channel4envelopeSweeps = 0;
   6562   this.channel4envelopeSweepsLast = 0;
   6563   this.channel4consecutive = true;
   6564   this.channel4BitRange = 0x7FFF;
   6565   this.noiseSampleTable = this.LSFR15Table;
   6566   this.channel4VolumeShifter = 15;
   6567   this.channel1FrequencyCounter = 0x2000;
   6568   this.channel2FrequencyCounter = 0x2000;
   6569   this.channel3Counter = 0x800;
   6570   this.channel3FrequencyPeriod = 0x800;
   6571   this.channel3lastSampleLookup = 0;
   6572   this.channel4lastSampleLookup = 0;
   6573   this.VinLeftChannelMasterVolume = 8;
   6574   this.VinRightChannelMasterVolume = 8;
   6575   this.mixerOutputCache = 0;
   6576   this.sequencerClocks = 0x2000;
   6577   this.sequencePosition = 0;
   6578   this.channel4FrequencyPeriod = 8;
   6579   this.channel4Counter = 8;
   6580   this.cachedChannel3Sample = 0;
   6581   this.cachedChannel4Sample = 0;
   6582   this.channel1Enabled = false;
   6583   this.channel2Enabled = false;
   6584   this.channel3Enabled = false;
   6585   this.channel4Enabled = false;
   6586   this.channel1canPlay = false;
   6587   this.channel2canPlay = false;
   6588   this.channel4canPlay = false;
   6589   this.channel1OutputLevelCache();
   6590   this.channel2OutputLevelCache();
   6591   this.channel3OutputLevelCache();
   6592   this.channel4OutputLevelCache();
   6593 }
   6594 GameBoyCore.prototype.outputAudio = function () {
   6595   var sampleFactor = 0;
   6596   var dirtySample = 0;
   6597   var averageL = 0;
   6598   var averageR = 0;
   6599   var destinationPosition = 0;
   6600   var divisor1 = settings[13];
   6601   var divisor2 = divisor1 * 0xF0;
   6602   for (var sourcePosition = 0; sourcePosition < this.numSamplesTotal;) {
   6603     for (sampleFactor = averageL = averageR = 0; sampleFactor < divisor1; ++sampleFactor) {
   6604       dirtySample = this.currentBuffer[sourcePosition++];
   6605       averageL += dirtySample >> 9;
   6606       averageR += dirtySample & 0x1FF;
   6607     }
   6608     this.secondaryBuffer[destinationPosition++] = averageL / divisor2 - 1;
   6609     this.secondaryBuffer[destinationPosition++] = averageR / divisor2 - 1;
   6610   }
   6611   this.audioHandle.writeAudioNoCallback(this.secondaryBuffer);
   6612 }
   6613 //Below are the audio generation functions timed against the CPU:
   6614 GameBoyCore.prototype.generateAudio = function (numSamples) {
   6615   if (this.soundMasterEnabled && !this.CPUStopped) {
   6616     for (var samplesToGenerate = 0; numSamples > 0;) {
   6617       samplesToGenerate = (numSamples < this.sequencerClocks) ? numSamples : this.sequencerClocks;
   6618       this.sequencerClocks -= samplesToGenerate;
   6619       numSamples -= samplesToGenerate;
   6620       while (--samplesToGenerate > -1) {
   6621         this.computeAudioChannels();
   6622         this.currentBuffer[this.audioIndex++] = this.mixerOutputCache;
   6623         if (this.audioIndex == this.numSamplesTotal) {
   6624           this.audioIndex = 0;
   6625           this.outputAudio();
   6626         }
   6627       }
   6628       if (this.sequencerClocks == 0) {
   6629         this.audioComputeSequencer();
   6630         this.sequencerClocks = 0x2000;
   6631       }
   6632     }
   6633   }
   6634   else {
   6635     //SILENT OUTPUT:
   6636     while (--numSamples > -1) {
   6637       this.currentBuffer[this.audioIndex++] = 0xF0F0;
   6638       if (this.audioIndex == this.numSamplesTotal) {
   6639         this.audioIndex = 0;
   6640         this.outputAudio();
   6641       }
   6642     }
   6643   }
   6644 }
   6645 //Generate audio, but don't actually output it (Used for when sound is disabled by user/browser):
   6646 GameBoyCore.prototype.generateAudioFake = function (numSamples) {
   6647   if (this.soundMasterEnabled && !this.CPUStopped) {
   6648     while (--numSamples > -1) {
   6649       this.computeAudioChannels();
   6650       if (--this.sequencerClocks == 0) {
   6651         this.audioComputeSequencer();
   6652         this.sequencerClocks = 0x2000;
   6653       }
   6654     }
   6655   }
   6656 }
   6657 GameBoyCore.prototype.audioJIT = function () {
   6658   //Audio Sample Generation Timing:
   6659   if (settings[0]) {
   6660     this.generateAudio(this.audioTicks);
   6661   }
   6662   else {
   6663     this.generateAudioFake(this.audioTicks);
   6664   }
   6665   this.audioTicks = 0;
   6666 }
   6667 GameBoyCore.prototype.audioComputeSequencer = function () {
   6668   switch (this.sequencePosition++) {
   6669     case 0:
   6670       this.clockAudioLength();
   6671       break;
   6672     case 2:
   6673       this.clockAudioLength();
   6674       this.clockAudioSweep();
   6675       break;
   6676     case 4:
   6677       this.clockAudioLength();
   6678       break;
   6679     case 6:
   6680       this.clockAudioLength();
   6681       this.clockAudioSweep();
   6682       break;
   6683     case 7:
   6684       this.clockAudioEnvelope();
   6685       this.sequencePosition = 0;
   6686   }
   6687 }
   6688 GameBoyCore.prototype.clockAudioLength = function () {
   6689   //Channel 1:
   6690   if (this.channel1totalLength > 1) {
   6691     --this.channel1totalLength;
   6692   }
   6693   else if (this.channel1totalLength == 1) {
   6694     this.channel1totalLength = 0;
   6695     this.channel1EnableCheck();
   6696     this.memory[0xFF26] &= 0xFE;  //Channel #1 On Flag Off
   6697   }
   6698   //Channel 2:
   6699   if (this.channel2totalLength > 1) {
   6700     --this.channel2totalLength;
   6701   }
   6702   else if (this.channel2totalLength == 1) {
   6703     this.channel2totalLength = 0;
   6704     this.channel2EnableCheck();
   6705     this.memory[0xFF26] &= 0xFD;  //Channel #2 On Flag Off
   6706   }
   6707   //Channel 3:
   6708   if (this.channel3totalLength > 1) {
   6709     --this.channel3totalLength;
   6710   }
   6711   else if (this.channel3totalLength == 1) {
   6712     this.channel3totalLength = 0;
   6713     this.channel3EnableCheck();
   6714     this.memory[0xFF26] &= 0xFB;  //Channel #3 On Flag Off
   6715   }
   6716   //Channel 4:
   6717   if (this.channel4totalLength > 1) {
   6718     --this.channel4totalLength;
   6719   }
   6720   else if (this.channel4totalLength == 1) {
   6721     this.channel4totalLength = 0;
   6722     this.channel4EnableCheck();
   6723     this.memory[0xFF26] &= 0xF7;  //Channel #4 On Flag Off
   6724   }
   6725 }
   6726 GameBoyCore.prototype.clockAudioSweep = function () {
   6727   //Channel 1:
   6728   if (!this.channel1SweepFault && this.channel1timeSweep > 0) {
   6729     if (--this.channel1timeSweep == 0) {
   6730       this.runAudioSweep();
   6731     }
   6732   }
   6733 }
   6734 GameBoyCore.prototype.runAudioSweep = function () {
   6735   //Channel 1:
   6736   if (this.channel1lastTimeSweep > 0) {
   6737     if (this.channel1frequencySweepDivider > 0) {
   6738       if (this.channel1numSweep > 0) {
   6739         --this.channel1numSweep;
   6740         if (this.channel1decreaseSweep) {
   6741           this.channel1ShadowFrequency -= this.channel1ShadowFrequency >> this.channel1frequencySweepDivider;
   6742           this.channel1frequency = this.channel1ShadowFrequency & 0x7FF;
   6743           this.channel1FrequencyTracker = (0x800 - this.channel1frequency) << 2;
   6744         }
   6745         else {
   6746           this.channel1ShadowFrequency += this.channel1ShadowFrequency >> this.channel1frequencySweepDivider;
   6747           this.channel1frequency = this.channel1ShadowFrequency;
   6748           if (this.channel1ShadowFrequency <= 0x7FF) {
   6749             this.channel1FrequencyTracker = (0x800 - this.channel1frequency) << 2;
   6750             //Run overflow check twice:
   6751             if ((this.channel1ShadowFrequency + (this.channel1ShadowFrequency >> this.channel1frequencySweepDivider)) > 0x7FF) {
   6752               this.channel1SweepFault = true;
   6753               this.channel1EnableCheck();
   6754               this.memory[0xFF26] &= 0xFE;  //Channel #1 On Flag Off
   6755             }
   6756           }
   6757           else {
   6758             this.channel1frequency &= 0x7FF;
   6759             this.channel1SweepFault = true;
   6760             this.channel1EnableCheck();
   6761             this.memory[0xFF26] &= 0xFE;  //Channel #1 On Flag Off
   6762           }
   6763         }
   6764       }
   6765       this.channel1timeSweep = this.channel1lastTimeSweep;
   6766     }
   6767     else {
   6768       //Channel has sweep disabled and timer becomes a length counter:
   6769       this.channel1SweepFault = true;
   6770       this.channel1EnableCheck();
   6771     }
   6772   }
   6773 }
   6774 GameBoyCore.prototype.clockAudioEnvelope = function () {
   6775   //Channel 1:
   6776   if (this.channel1envelopeSweepsLast > -1) {
   6777     if (this.channel1envelopeSweeps > 0) {
   6778       --this.channel1envelopeSweeps;
   6779     }
   6780     else {
   6781       if (!this.channel1envelopeType) {
   6782         if (this.channel1envelopeVolume > 0) {
   6783           --this.channel1envelopeVolume;
   6784           this.channel1envelopeSweeps = this.channel1envelopeSweepsLast;
   6785           this.channel1OutputLevelCache();
   6786         }
   6787         else {
   6788           this.channel1envelopeSweepsLast = -1;
   6789         }
   6790       }
   6791       else if (this.channel1envelopeVolume < 0xF) {
   6792         ++this.channel1envelopeVolume;
   6793         this.channel1envelopeSweeps = this.channel1envelopeSweepsLast;
   6794         this.channel1OutputLevelCache();
   6795       }
   6796       else {
   6797         this.channel1envelopeSweepsLast = -1;
   6798       }
   6799     }
   6800   }
   6801   //Channel 2:
   6802   if (this.channel2envelopeSweepsLast > -1) {
   6803     if (this.channel2envelopeSweeps > 0) {
   6804       --this.channel2envelopeSweeps;
   6805     }
   6806     else {
   6807       if (!this.channel2envelopeType) {
   6808         if (this.channel2envelopeVolume > 0) {
   6809           --this.channel2envelopeVolume;
   6810           this.channel2envelopeSweeps = this.channel2envelopeSweepsLast;
   6811           this.channel2OutputLevelCache();
   6812         }
   6813         else {
   6814           this.channel2envelopeSweepsLast = -1;
   6815         }
   6816       }
   6817       else if (this.channel2envelopeVolume < 0xF) {
   6818         ++this.channel2envelopeVolume;
   6819         this.channel2envelopeSweeps = this.channel2envelopeSweepsLast;
   6820         this.channel2OutputLevelCache();
   6821       }
   6822       else {
   6823         this.channel2envelopeSweepsLast = -1;
   6824       }
   6825     }
   6826   }
   6827   //Channel 4:
   6828   if (this.channel4envelopeSweepsLast > -1) {
   6829     if (this.channel4envelopeSweeps > 0) {
   6830       --this.channel4envelopeSweeps;
   6831     }
   6832     else {
   6833       if (!this.channel4envelopeType) {
   6834         if (this.channel4envelopeVolume > 0) {
   6835           this.channel4currentVolume = --this.channel4envelopeVolume << this.channel4VolumeShifter;
   6836           this.channel4envelopeSweeps = this.channel4envelopeSweepsLast;
   6837           this.channel4UpdateCache();
   6838         }
   6839         else {
   6840           this.channel4envelopeSweepsLast = -1;
   6841         }
   6842       }
   6843       else if (this.channel4envelopeVolume < 0xF) {
   6844         this.channel4currentVolume = ++this.channel4envelopeVolume << this.channel4VolumeShifter;
   6845         this.channel4envelopeSweeps = this.channel4envelopeSweepsLast;
   6846         this.channel4UpdateCache();
   6847       }
   6848       else {
   6849         this.channel4envelopeSweepsLast = -1;
   6850       }
   6851     }
   6852   }
   6853 }
   6854 GameBoyCore.prototype.computeAudioChannels = function () {
   6855   //Channel 1 counter:
   6856   if (--this.channel1FrequencyCounter == 0) {
   6857     this.channel1FrequencyCounter = this.channel1FrequencyTracker;
   6858     this.channel1DutyTracker = (this.channel1DutyTracker + 1) & 0x7;
   6859     this.channel1OutputLevelTrimaryCache();
   6860   }
   6861   //Channel 2 counter:
   6862   if (--this.channel2FrequencyCounter == 0) {
   6863     this.channel2FrequencyCounter = this.channel2FrequencyTracker;
   6864     this.channel2DutyTracker = (this.channel2DutyTracker + 1) & 0x7;
   6865     this.channel2OutputLevelTrimaryCache();
   6866   }
   6867   //Channel 3 counter:
   6868   if (--this.channel3Counter == 0) {
   6869     if (this.channel3canPlay) {
   6870       this.channel3lastSampleLookup = (this.channel3lastSampleLookup + 1) & 0x1F;
   6871     }
   6872     this.channel3Counter = this.channel3FrequencyPeriod;
   6873     this.channel3UpdateCache();
   6874   }
   6875   //Channel 4 counter:
   6876   if (--this.channel4Counter == 0) {
   6877     this.channel4lastSampleLookup = (this.channel4lastSampleLookup + 1) & this.channel4BitRange;
   6878     this.channel4Counter = this.channel4FrequencyPeriod;
   6879     this.channel4UpdateCache();
   6880   }
   6881 }
   6882 GameBoyCore.prototype.channel1EnableCheck = function () {
   6883   this.channel1Enabled = ((this.channel1consecutive || this.channel1totalLength > 0) && !this.channel1SweepFault && this.channel1canPlay);
   6884   this.channel1OutputLevelSecondaryCache();
   6885 }
   6886 GameBoyCore.prototype.channel1VolumeEnableCheck = function () {
   6887   this.channel1canPlay = (this.memory[0xFF12] > 7);
   6888   this.channel1EnableCheck();
   6889   this.channel1OutputLevelSecondaryCache();
   6890 }
   6891 GameBoyCore.prototype.channel1OutputLevelCache = function () {
   6892   this.channel1currentSampleLeft = (this.leftChannel1) ? this.channel1envelopeVolume : 0;
   6893   this.channel1currentSampleRight = (this.rightChannel1) ? this.channel1envelopeVolume : 0;
   6894   this.channel1OutputLevelSecondaryCache();
   6895 }
   6896 GameBoyCore.prototype.channel1OutputLevelSecondaryCache = function () {
   6897   if (this.channel1Enabled) {
   6898     this.channel1currentSampleLeftSecondary = this.channel1currentSampleLeft;
   6899     this.channel1currentSampleRightSecondary = this.channel1currentSampleRight;
   6900   }
   6901   else {
   6902     this.channel1currentSampleLeftSecondary = 0;
   6903     this.channel1currentSampleRightSecondary = 0;
   6904   }
   6905   this.channel1OutputLevelTrimaryCache();
   6906 }
   6907 GameBoyCore.prototype.channel1OutputLevelTrimaryCache = function () {
   6908   if (this.channel1CachedDuty[this.channel1DutyTracker]) {
   6909     this.channel1currentSampleLeftTrimary = this.channel1currentSampleLeftSecondary;
   6910     this.channel1currentSampleRightTrimary = this.channel1currentSampleRightSecondary;
   6911   }
   6912   else {
   6913     this.channel1currentSampleLeftTrimary = 0;
   6914     this.channel1currentSampleRightTrimary = 0;
   6915   }
   6916   this.mixerOutputLevelCache();
   6917 }
   6918 GameBoyCore.prototype.channel2EnableCheck = function () {
   6919   this.channel2Enabled = ((this.channel2consecutive || this.channel2totalLength > 0) && this.channel2canPlay);
   6920   this.channel2OutputLevelSecondaryCache();
   6921 }
   6922 GameBoyCore.prototype.channel2VolumeEnableCheck = function () {
   6923   this.channel2canPlay = (this.memory[0xFF17] > 7);
   6924   this.channel2EnableCheck();
   6925   this.channel2OutputLevelSecondaryCache();
   6926 }
   6927 GameBoyCore.prototype.channel2OutputLevelCache = function () {
   6928   this.channel2currentSampleLeft = (this.leftChannel2) ? this.channel2envelopeVolume : 0;
   6929   this.channel2currentSampleRight = (this.rightChannel2) ? this.channel2envelopeVolume : 0;
   6930   this.channel2OutputLevelSecondaryCache();
   6931 }
   6932 GameBoyCore.prototype.channel2OutputLevelSecondaryCache = function () {
   6933   if (this.channel2Enabled) {
   6934     this.channel2currentSampleLeftSecondary = this.channel2currentSampleLeft;
   6935     this.channel2currentSampleRightSecondary = this.channel2currentSampleRight;
   6936   }
   6937   else {
   6938     this.channel2currentSampleLeftSecondary = 0;
   6939     this.channel2currentSampleRightSecondary = 0;
   6940   }
   6941   this.channel2OutputLevelTrimaryCache();
   6942 }
   6943 GameBoyCore.prototype.channel2OutputLevelTrimaryCache = function () {
   6944   if (this.channel2CachedDuty[this.channel2DutyTracker]) {
   6945     this.channel2currentSampleLeftTrimary = this.channel2currentSampleLeftSecondary;
   6946     this.channel2currentSampleRightTrimary = this.channel2currentSampleRightSecondary;
   6947   }
   6948   else {
   6949     this.channel2currentSampleLeftTrimary = 0;
   6950     this.channel2currentSampleRightTrimary = 0;
   6951   }
   6952   this.mixerOutputLevelCache();
   6953 }
   6954 GameBoyCore.prototype.channel3EnableCheck = function () {
   6955   this.channel3Enabled = (/*this.channel3canPlay && */(this.channel3consecutive || this.channel3totalLength > 0));
   6956   this.channel3OutputLevelSecondaryCache();
   6957 }
   6958 GameBoyCore.prototype.channel3OutputLevelCache = function () {
   6959   this.channel3currentSampleLeft = (this.leftChannel3) ? this.cachedChannel3Sample : 0;
   6960   this.channel3currentSampleRight = (this.rightChannel3) ? this.cachedChannel3Sample : 0;
   6961   this.channel3OutputLevelSecondaryCache();
   6962 }
   6963 GameBoyCore.prototype.channel3OutputLevelSecondaryCache = function () {
   6964   if (this.channel3Enabled) {
   6965     this.channel3currentSampleLeftSecondary = this.channel3currentSampleLeft;
   6966     this.channel3currentSampleRightSecondary = this.channel3currentSampleRight;
   6967   }
   6968   else {
   6969     this.channel3currentSampleLeftSecondary = 0;
   6970     this.channel3currentSampleRightSecondary = 0;
   6971   }
   6972   this.mixerOutputLevelCache();
   6973 }
   6974 GameBoyCore.prototype.channel4EnableCheck = function () {
   6975   this.channel4Enabled = ((this.channel4consecutive || this.channel4totalLength > 0) && this.channel4canPlay);
   6976   this.channel4OutputLevelSecondaryCache();
   6977 }
   6978 GameBoyCore.prototype.channel4VolumeEnableCheck = function () {
   6979   this.channel4canPlay = (this.memory[0xFF21] > 7);
   6980   this.channel4EnableCheck();
   6981   this.channel4OutputLevelSecondaryCache();
   6982 }
   6983 GameBoyCore.prototype.channel4OutputLevelCache = function () {
   6984   this.channel4currentSampleLeft = (this.leftChannel4) ? this.cachedChannel4Sample : 0;
   6985   this.channel4currentSampleRight = (this.rightChannel4) ? this.cachedChannel4Sample : 0;
   6986   this.channel4OutputLevelSecondaryCache();
   6987 }
   6988 GameBoyCore.prototype.channel4OutputLevelSecondaryCache = function () {
   6989   if (this.channel4Enabled) {
   6990     this.channel4currentSampleLeftSecondary = this.channel4currentSampleLeft;
   6991     this.channel4currentSampleRightSecondary = this.channel4currentSampleRight;
   6992   }
   6993   else {
   6994     this.channel4currentSampleLeftSecondary = 0;
   6995     this.channel4currentSampleRightSecondary = 0;
   6996   }
   6997   this.mixerOutputLevelCache();
   6998 }
   6999 GameBoyCore.prototype.mixerOutputLevelCache = function () {
   7000   this.mixerOutputCache = ((((this.channel1currentSampleLeftTrimary + this.channel2currentSampleLeftTrimary + this.channel3currentSampleLeftSecondary + this.channel4currentSampleLeftSecondary) * this.VinLeftChannelMasterVolume) << 9) +
   7001   ((this.channel1currentSampleRightTrimary + this.channel2currentSampleRightTrimary + this.channel3currentSampleRightSecondary + this.channel4currentSampleRightSecondary) * this.VinRightChannelMasterVolume));
   7002 }
   7003 GameBoyCore.prototype.channel3UpdateCache = function () {
   7004   this.cachedChannel3Sample = this.channel3PCM[this.channel3lastSampleLookup] >> this.channel3patternType;
   7005   this.channel3OutputLevelCache();
   7006 }
   7007 GameBoyCore.prototype.channel3WriteRAM = function (address, data) {
   7008   if (this.channel3canPlay) {
   7009     this.audioJIT();
   7010     //address = this.channel3lastSampleLookup >> 1;
   7011   }
   7012   this.memory[0xFF30 | address] = data;
   7013   address <<= 1;
   7014   this.channel3PCM[address] = data >> 4;
   7015   this.channel3PCM[address | 1] = data & 0xF;
   7016 }
   7017 GameBoyCore.prototype.channel4UpdateCache = function () {
   7018   this.cachedChannel4Sample = this.noiseSampleTable[this.channel4currentVolume | this.channel4lastSampleLookup];
   7019   this.channel4OutputLevelCache();
   7020 }
   7021 GameBoyCore.prototype.run = function () {
   7022   //The preprocessing before the actual iteration loop:
   7023   if ((this.stopEmulator & 2) == 0) {
   7024     if ((this.stopEmulator & 1) == 1) {
   7025       if (!this.CPUStopped) {
   7026         this.stopEmulator = 0;
   7027         this.drewFrame = false;
   7028         this.audioUnderrunAdjustment();
   7029         this.clockUpdate();      //RTC clocking.
   7030         if (!this.halt) {
   7031           this.executeIteration();
   7032         }
   7033         else {            //Finish the HALT rundown execution.
   7034           this.CPUTicks = 0;
   7035           this.calculateHALTPeriod();
   7036           if (this.halt) {
   7037             this.updateCoreFull();
   7038           }
   7039           else {
   7040             this.executeIteration();
   7041           }
   7042         }
   7043         //Request the graphics target to be updated:
   7044         this.requestDraw();
   7045       }
   7046       else {
   7047         this.audioUnderrunAdjustment();
   7048         this.audioTicks += this.CPUCyclesTotal;
   7049         this.audioJIT();
   7050         this.stopEmulator |= 1;      //End current loop.
   7051       }
   7052     }
   7053     else {    //We can only get here if there was an internal error, but the loop was restarted.
   7054       cout("Iterator restarted a faulted core.", 2);
   7055       pause();
   7056     }
   7057   }
   7058 }
   7059 
   7060 GameBoyCore.prototype.executeIteration = function () {
   7061   //Iterate the interpreter loop:
   7062   var opcodeToExecute = 0;
   7063   var timedTicks = 0;
   7064   while (this.stopEmulator == 0) {
   7065     //Interrupt Arming:
   7066     switch (this.IRQEnableDelay) {
   7067       case 1:
   7068         this.IME = true;
   7069         this.checkIRQMatching();
   7070       case 2:
   7071         --this.IRQEnableDelay;
   7072     }
   7073     //Is an IRQ set to fire?:
   7074     if (this.IRQLineMatched > 0) {
   7075       //IME is true and and interrupt was matched:
   7076       this.launchIRQ();
   7077     }
   7078     //Fetch the current opcode:
   7079     opcodeToExecute = this.memoryReader[this.programCounter](this, this.programCounter);
   7080     //Increment the program counter to the next instruction:
   7081     this.programCounter = (this.programCounter + 1) & 0xFFFF;
   7082     //Check for the program counter quirk:
   7083     if (this.skipPCIncrement) {
   7084       this.programCounter = (this.programCounter - 1) & 0xFFFF;
   7085       this.skipPCIncrement = false;
   7086     }
   7087     //Get how many CPU cycles the current instruction counts for:
   7088     this.CPUTicks = this.TICKTable[opcodeToExecute];
   7089     //Execute the current instruction:
   7090     this.OPCODE[opcodeToExecute](this);
   7091     //Update the state (Inlined updateCoreFull manually here):
   7092     //Update the clocking for the LCD emulation:
   7093     this.LCDTicks += this.CPUTicks >> this.doubleSpeedShifter;  //LCD Timing
   7094     this.LCDCONTROL[this.actualScanLine](this);          //Scan Line and STAT Mode Control
   7095     //Single-speed relative timing for A/V emulation:
   7096     timedTicks = this.CPUTicks >> this.doubleSpeedShifter;    //CPU clocking can be updated from the LCD handling.
   7097     this.audioTicks += timedTicks;                //Audio Timing
   7098     this.emulatorTicks += timedTicks;              //Emulator Timing
   7099     //CPU Timers:
   7100     this.DIVTicks += this.CPUTicks;                //DIV Timing
   7101     if (this.TIMAEnabled) {                    //TIMA Timing
   7102       this.timerTicks += this.CPUTicks;
   7103       while (this.timerTicks >= this.TACClocker) {
   7104         this.timerTicks -= this.TACClocker;
   7105         if (++this.memory[0xFF05] == 0x100) {
   7106           this.memory[0xFF05] = this.memory[0xFF06];
   7107           this.interruptsRequested |= 0x4;
   7108           this.checkIRQMatching();
   7109         }
   7110       }
   7111     }
   7112     if (this.serialTimer > 0) {                    //Serial Timing
   7113       //IRQ Counter:
   7114       this.serialTimer -= this.CPUTicks;
   7115       if (this.serialTimer <= 0) {
   7116         this.interruptsRequested |= 0x8;
   7117         this.checkIRQMatching();
   7118       }
   7119       //Bit Shit Counter:
   7120       this.serialShiftTimer -= this.CPUTicks;
   7121       if (this.serialShiftTimer <= 0) {
   7122         this.serialShiftTimer = this.serialShiftTimerAllocated;
   7123         this.memory[0xFF01] = ((this.memory[0xFF01] << 1) & 0xFE) | 0x01;  //We could shift in actual link data here if we were to implement such!!!
   7124       }
   7125     }
   7126     //End of iteration routine:
   7127     if (this.emulatorTicks >= this.CPUCyclesTotal) {
   7128       this.iterationEndRoutine();
   7129     }
   7130     // Start of code added for benchmarking:
   7131     this.instructions += 1;
   7132     if (this.instructions > this.totalInstructions) {
   7133       this.iterationEndRoutine();
   7134       this.stopEmulator |= 2;
   7135       checkFinalState();
   7136     }
   7137     // End of code added for benchmarking.
   7138   }
   7139 }
   7140 GameBoyCore.prototype.iterationEndRoutine = function () {
   7141   if ((this.stopEmulator & 0x1) == 0) {
   7142     this.audioJIT();  //Make sure we at least output once per iteration.
   7143     //Update DIV Alignment (Integer overflow safety):
   7144     this.memory[0xFF04] = (this.memory[0xFF04] + (this.DIVTicks >> 8)) & 0xFF;
   7145     this.DIVTicks &= 0xFF;
   7146     //Update emulator flags:
   7147     this.stopEmulator |= 1;      //End current loop.
   7148     this.emulatorTicks -= this.CPUCyclesTotal;
   7149     this.CPUCyclesTotalCurrent += this.CPUCyclesTotalRoundoff;
   7150     this.recalculateIterationClockLimit();
   7151   }
   7152 }
   7153 GameBoyCore.prototype.handleSTOP = function () {
   7154   this.CPUStopped = true;            //Stop CPU until joypad input changes.
   7155   this.iterationEndRoutine();
   7156   if (this.emulatorTicks < 0) {
   7157     this.audioTicks -= this.emulatorTicks;
   7158     this.audioJIT();
   7159   }
   7160 }
   7161 GameBoyCore.prototype.recalculateIterationClockLimit = function () {
   7162   var endModulus = this.CPUCyclesTotalCurrent % 4;
   7163   this.CPUCyclesTotal = this.CPUCyclesTotalBase + this.CPUCyclesTotalCurrent - endModulus;
   7164   this.CPUCyclesTotalCurrent = endModulus;
   7165 }
   7166 GameBoyCore.prototype.scanLineMode2 = function () {  //OAM Search Period
   7167   if (this.STATTracker != 1) {
   7168     if (this.mode2TriggerSTAT) {
   7169       this.interruptsRequested |= 0x2;
   7170       this.checkIRQMatching();
   7171     }
   7172     this.STATTracker = 1;
   7173     this.modeSTAT = 2;
   7174   }
   7175 }
   7176 GameBoyCore.prototype.scanLineMode3 = function () {  //Scan Line Drawing Period
   7177   if (this.modeSTAT != 3) {
   7178     if (this.STATTracker == 0 && this.mode2TriggerSTAT) {
   7179       this.interruptsRequested |= 0x2;
   7180       this.checkIRQMatching();
   7181     }
   7182     this.STATTracker = 1;
   7183     this.modeSTAT = 3;
   7184   }
   7185 }
   7186 GameBoyCore.prototype.scanLineMode0 = function () {  //Horizontal Blanking Period
   7187   if (this.modeSTAT != 0) {
   7188     if (this.STATTracker != 2) {
   7189       if (this.STATTracker == 0) {
   7190         if (this.mode2TriggerSTAT) {
   7191           this.interruptsRequested |= 0x2;
   7192           this.checkIRQMatching();
   7193         }
   7194         this.modeSTAT = 3;
   7195       }
   7196       this.incrementScanLineQueue();
   7197       this.updateSpriteCount(this.actualScanLine);
   7198       this.STATTracker = 2;
   7199     }
   7200     if (this.LCDTicks >= this.spriteCount) {
   7201       if (this.hdmaRunning) {
   7202         this.executeHDMA();
   7203       }
   7204       if (this.mode0TriggerSTAT) {
   7205         this.interruptsRequested |= 0x2;
   7206         this.checkIRQMatching();
   7207       }
   7208       this.STATTracker = 3;
   7209       this.modeSTAT = 0;
   7210     }
   7211   }
   7212 }
   7213 GameBoyCore.prototype.clocksUntilLYCMatch = function () {
   7214   if (this.memory[0xFF45] != 0) {
   7215     if (this.memory[0xFF45] > this.actualScanLine) {
   7216       return 456 * (this.memory[0xFF45] - this.actualScanLine);
   7217     }
   7218     return 456 * (154 - this.actualScanLine + this.memory[0xFF45]);
   7219   }
   7220   return (456 * ((this.actualScanLine == 153 && this.memory[0xFF44] == 0) ? 154 : (153 - this.actualScanLine))) + 8;
   7221 }
   7222 GameBoyCore.prototype.clocksUntilMode0 = function () {
   7223   switch (this.modeSTAT) {
   7224     case 0:
   7225       if (this.actualScanLine == 143) {
   7226         this.updateSpriteCount(0);
   7227         return this.spriteCount + 5016;
   7228       }
   7229       this.updateSpriteCount(this.actualScanLine + 1);
   7230       return this.spriteCount + 456;
   7231     case 2:
   7232     case 3:
   7233       this.updateSpriteCount(this.actualScanLine);
   7234       return this.spriteCount;
   7235     case 1:
   7236       this.updateSpriteCount(0);
   7237       return this.spriteCount + (456 * (154 - this.actualScanLine));
   7238   }
   7239 }
   7240 GameBoyCore.prototype.updateSpriteCount = function (line) {
   7241   this.spriteCount = 252;
   7242   if (this.cGBC && this.gfxSpriteShow) {                    //Is the window enabled and are we in CGB mode?
   7243     var lineAdjusted = line + 0x10;
   7244     var yoffset = 0;
   7245     var yCap = (this.gfxSpriteNormalHeight) ? 0x8 : 0x10;
   7246     for (var OAMAddress = 0xFE00; OAMAddress < 0xFEA0 && this.spriteCount < 312; OAMAddress += 4) {
   7247       yoffset = lineAdjusted - this.memory[OAMAddress];
   7248       if (yoffset > -1 && yoffset < yCap) {
   7249         this.spriteCount += 6;
   7250       }
   7251     }
   7252   }
   7253 }
   7254 GameBoyCore.prototype.matchLYC = function () {  //LYC Register Compare
   7255   if (this.memory[0xFF44] == this.memory[0xFF45]) {
   7256     this.memory[0xFF41] |= 0x04;
   7257     if (this.LYCMatchTriggerSTAT) {
   7258       this.interruptsRequested |= 0x2;
   7259       this.checkIRQMatching();
   7260     }
   7261   }
   7262   else {
   7263     this.memory[0xFF41] &= 0x7B;
   7264   }
   7265 }
   7266 GameBoyCore.prototype.updateCore = function () {
   7267   //Update the clocking for the LCD emulation:
   7268   this.LCDTicks += this.CPUTicks >> this.doubleSpeedShifter;  //LCD Timing
   7269   this.LCDCONTROL[this.actualScanLine](this);          //Scan Line and STAT Mode Control
   7270   //Single-speed relative timing for A/V emulation:
   7271   var timedTicks = this.CPUTicks >> this.doubleSpeedShifter;  //CPU clocking can be updated from the LCD handling.
   7272   this.audioTicks += timedTicks;                //Audio Timing
   7273   this.emulatorTicks += timedTicks;              //Emulator Timing
   7274   //CPU Timers:
   7275   this.DIVTicks += this.CPUTicks;                //DIV Timing
   7276   if (this.TIMAEnabled) {                    //TIMA Timing
   7277     this.timerTicks += this.CPUTicks;
   7278     while (this.timerTicks >= this.TACClocker) {
   7279       this.timerTicks -= this.TACClocker;
   7280       if (++this.memory[0xFF05] == 0x100) {
   7281         this.memory[0xFF05] = this.memory[0xFF06];
   7282         this.interruptsRequested |= 0x4;
   7283         this.checkIRQMatching();
   7284       }
   7285     }
   7286   }
   7287   if (this.serialTimer > 0) {                    //Serial Timing
   7288     //IRQ Counter:
   7289     this.serialTimer -= this.CPUTicks;
   7290     if (this.serialTimer <= 0) {
   7291       this.interruptsRequested |= 0x8;
   7292       this.checkIRQMatching();
   7293     }
   7294     //Bit Shit Counter:
   7295     this.serialShiftTimer -= this.CPUTicks;
   7296     if (this.serialShiftTimer <= 0) {
   7297       this.serialShiftTimer = this.serialShiftTimerAllocated;
   7298       this.memory[0xFF01] = ((this.memory[0xFF01] << 1) & 0xFE) | 0x01;  //We could shift in actual link data here if we were to implement such!!!
   7299     }
   7300   }
   7301 }
   7302 GameBoyCore.prototype.updateCoreFull = function () {
   7303   //Update the state machine:
   7304   this.updateCore();
   7305   //End of iteration routine:
   7306   if (this.emulatorTicks >= this.CPUCyclesTotal) {
   7307     this.iterationEndRoutine();
   7308   }
   7309 }
   7310 GameBoyCore.prototype.initializeLCDController = function () {
   7311   //Display on hanlding:
   7312   var line = 0;
   7313   while (line < 154) {
   7314     if (line < 143) {
   7315       //We're on a normal scan line:
   7316       this.LINECONTROL[line] = function (parentObj) {
   7317         if (parentObj.LCDTicks < 80) {
   7318           parentObj.scanLineMode2();
   7319         }
   7320         else if (parentObj.LCDTicks < 252) {
   7321           parentObj.scanLineMode3();
   7322         }
   7323         else if (parentObj.LCDTicks < 456) {
   7324           parentObj.scanLineMode0();
   7325         }
   7326         else {
   7327           //We're on a new scan line:
   7328           parentObj.LCDTicks -= 456;
   7329           if (parentObj.STATTracker != 3) {
   7330             //Make sure the mode 0 handler was run at least once per scan line:
   7331             if (parentObj.STATTracker != 2) {
   7332               if (parentObj.STATTracker == 0 && parentObj.mode2TriggerSTAT) {
   7333                 parentObj.interruptsRequested |= 0x2;
   7334               }
   7335               parentObj.incrementScanLineQueue();
   7336             }
   7337             if (parentObj.hdmaRunning) {
   7338               parentObj.executeHDMA();
   7339             }
   7340             if (parentObj.mode0TriggerSTAT) {
   7341               parentObj.interruptsRequested |= 0x2;
   7342             }
   7343           }
   7344           //Update the scanline registers and assert the LYC counter:
   7345           parentObj.actualScanLine = ++parentObj.memory[0xFF44];
   7346           //Perform a LYC counter assert:
   7347           if (parentObj.actualScanLine == parentObj.memory[0xFF45]) {
   7348             parentObj.memory[0xFF41] |= 0x04;
   7349             if (parentObj.LYCMatchTriggerSTAT) {
   7350               parentObj.interruptsRequested |= 0x2;
   7351             }
   7352           }
   7353           else {
   7354             parentObj.memory[0xFF41] &= 0x7B;
   7355           }
   7356           parentObj.checkIRQMatching();
   7357           //Reset our mode contingency variables:
   7358           parentObj.STATTracker = 0;
   7359           parentObj.modeSTAT = 2;
   7360           parentObj.LINECONTROL[parentObj.actualScanLine](parentObj);  //Scan Line and STAT Mode Control.
   7361         }
   7362       }
   7363     }
   7364     else if (line == 143) {
   7365       //We're on the last visible scan line of the LCD screen:
   7366       this.LINECONTROL[143] = function (parentObj) {
   7367         if (parentObj.LCDTicks < 80) {
   7368           parentObj.scanLineMode2();
   7369         }
   7370         else if (parentObj.LCDTicks < 252) {
   7371           parentObj.scanLineMode3();
   7372         }
   7373         else if (parentObj.LCDTicks < 456) {
   7374           parentObj.scanLineMode0();
   7375         }
   7376         else {
   7377           //Starting V-Blank:
   7378           //Just finished the last visible scan line:
   7379           parentObj.LCDTicks -= 456;
   7380           if (parentObj.STATTracker != 3) {
   7381             //Make sure the mode 0 handler was run at least once per scan line:
   7382             if (parentObj.STATTracker != 2) {
   7383               if (parentObj.STATTracker == 0 && parentObj.mode2TriggerSTAT) {
   7384                 parentObj.interruptsRequested |= 0x2;
   7385               }
   7386               parentObj.incrementScanLineQueue();
   7387             }
   7388             if (parentObj.hdmaRunning) {
   7389               parentObj.executeHDMA();
   7390             }
   7391             if (parentObj.mode0TriggerSTAT) {
   7392               parentObj.interruptsRequested |= 0x2;
   7393             }
   7394           }
   7395           //Update the scanline registers and assert the LYC counter:
   7396           parentObj.actualScanLine = parentObj.memory[0xFF44] = 144;
   7397           //Perform a LYC counter assert:
   7398           if (parentObj.memory[0xFF45] == 144) {
   7399             parentObj.memory[0xFF41] |= 0x04;
   7400             if (parentObj.LYCMatchTriggerSTAT) {
   7401               parentObj.interruptsRequested |= 0x2;
   7402             }
   7403           }
   7404           else {
   7405             parentObj.memory[0xFF41] &= 0x7B;
   7406           }
   7407           //Reset our mode contingency variables:
   7408           parentObj.STATTracker = 0;
   7409           //Update our state for v-blank:
   7410           parentObj.modeSTAT = 1;
   7411           parentObj.interruptsRequested |= (parentObj.mode1TriggerSTAT) ? 0x3 : 0x1;
   7412           parentObj.checkIRQMatching();
   7413           //Attempt to blit out to our canvas:
   7414           if (parentObj.drewBlank == 0) {
   7415             //Ensure JIT framing alignment:
   7416             if (parentObj.totalLinesPassed < 144 || (parentObj.totalLinesPassed == 144 && parentObj.midScanlineOffset > -1)) {
   7417               //Make sure our gfx are up-to-date:
   7418               parentObj.graphicsJITVBlank();
   7419               //Draw the frame:
   7420               parentObj.prepareFrame();
   7421             }
   7422           }
   7423           else {
   7424             //LCD off takes at least 2 frames:
   7425             --parentObj.drewBlank;
   7426           }
   7427           parentObj.LINECONTROL[144](parentObj);  //Scan Line and STAT Mode Control.
   7428         }
   7429       }
   7430     }
   7431     else if (line < 153) {
   7432       //In VBlank
   7433       this.LINECONTROL[line] = function (parentObj) {
   7434         if (parentObj.LCDTicks >= 456) {
   7435           //We're on a new scan line:
   7436           parentObj.LCDTicks -= 456;
   7437           parentObj.actualScanLine = ++parentObj.memory[0xFF44];
   7438           //Perform a LYC counter assert:
   7439           if (parentObj.actualScanLine == parentObj.memory[0xFF45]) {
   7440             parentObj.memory[0xFF41] |= 0x04;
   7441             if (parentObj.LYCMatchTriggerSTAT) {
   7442               parentObj.interruptsRequested |= 0x2;
   7443               parentObj.checkIRQMatching();
   7444             }
   7445           }
   7446           else {
   7447             parentObj.memory[0xFF41] &= 0x7B;
   7448           }
   7449           parentObj.LINECONTROL[parentObj.actualScanLine](parentObj);  //Scan Line and STAT Mode Control.
   7450         }
   7451       }
   7452     }
   7453     else {
   7454       //VBlank Ending (We're on the last actual scan line)
   7455       this.LINECONTROL[153] = function (parentObj) {
   7456         if (parentObj.LCDTicks >= 8) {
   7457           if (parentObj.STATTracker != 4 && parentObj.memory[0xFF44] == 153) {
   7458             parentObj.memory[0xFF44] = 0;  //LY register resets to 0 early.
   7459             //Perform a LYC counter assert:
   7460             if (parentObj.memory[0xFF45] == 0) {
   7461               parentObj.memory[0xFF41] |= 0x04;
   7462               if (parentObj.LYCMatchTriggerSTAT) {
   7463                 parentObj.interruptsRequested |= 0x2;
   7464                 parentObj.checkIRQMatching();
   7465               }
   7466             }
   7467             else {
   7468               parentObj.memory[0xFF41] &= 0x7B;
   7469             }
   7470             parentObj.STATTracker = 4;
   7471           }
   7472           if (parentObj.LCDTicks >= 456) {
   7473             //We reset back to the beginning:
   7474             parentObj.LCDTicks -= 456;
   7475             parentObj.STATTracker = parentObj.actualScanLine = 0;
   7476             parentObj.LINECONTROL[0](parentObj);  //Scan Line and STAT Mode Control.
   7477           }
   7478         }
   7479       }
   7480     }
   7481     ++line;
   7482   }
   7483 }
   7484 GameBoyCore.prototype.DisplayShowOff = function () {
   7485   if (this.drewBlank == 0) {
   7486     //Output a blank screen to the output framebuffer:
   7487     this.clearFrameBuffer();
   7488     this.drewFrame = true;
   7489   }
   7490   this.drewBlank = 2;
   7491 }
   7492 GameBoyCore.prototype.executeHDMA = function () {
   7493   this.DMAWrite(1);
   7494   if (this.halt) {
   7495     if ((this.LCDTicks - this.spriteCount) < ((4 >> this.doubleSpeedShifter) | 0x20)) {
   7496       //HALT clocking correction:
   7497       this.CPUTicks = 4 + ((0x20 + this.spriteCount) << this.doubleSpeedShifter);
   7498       this.LCDTicks = this.spriteCount + ((4 >> this.doubleSpeedShifter) | 0x20);
   7499     }
   7500   }
   7501   else {
   7502     this.LCDTicks += (4 >> this.doubleSpeedShifter) | 0x20;      //LCD Timing Update For HDMA.
   7503   }
   7504   if (this.memory[0xFF55] == 0) {
   7505     this.hdmaRunning = false;
   7506     this.memory[0xFF55] = 0xFF;  //Transfer completed ("Hidden last step," since some ROMs don't imply this, but most do).
   7507   }
   7508   else {
   7509     --this.memory[0xFF55];
   7510   }
   7511 }
   7512 GameBoyCore.prototype.clockUpdate = function () {
   7513   if (this.cTIMER) {
   7514     var dateObj = new_Date(); // The line is changed for benchmarking.
   7515     var newTime = dateObj.getTime();
   7516     var timeElapsed = newTime - this.lastIteration;  //Get the numnber of milliseconds since this last executed.
   7517     this.lastIteration = newTime;
   7518     if (this.cTIMER && !this.RTCHALT) {
   7519       //Update the MBC3 RTC:
   7520       this.RTCSeconds += timeElapsed / 1000;
   7521       while (this.RTCSeconds >= 60) {  //System can stutter, so the seconds difference can get large, thus the "while".
   7522         this.RTCSeconds -= 60;
   7523         ++this.RTCMinutes;
   7524         if (this.RTCMinutes >= 60) {
   7525           this.RTCMinutes -= 60;
   7526           ++this.RTCHours;
   7527           if (this.RTCHours >= 24) {
   7528             this.RTCHours -= 24
   7529             ++this.RTCDays;
   7530             if (this.RTCDays >= 512) {
   7531               this.RTCDays -= 512;
   7532               this.RTCDayOverFlow = true;
   7533             }
   7534           }
   7535         }
   7536       }
   7537     }
   7538   }
   7539 }
   7540 GameBoyCore.prototype.prepareFrame = function () {
   7541   //Copy the internal frame buffer to the output buffer:
   7542   this.swizzleFrameBuffer();
   7543   this.drewFrame = true;
   7544 }
   7545 GameBoyCore.prototype.requestDraw = function () {
   7546   if (this.drewFrame) {
   7547     this.dispatchDraw();
   7548   }
   7549 }
   7550 GameBoyCore.prototype.dispatchDraw = function () {
   7551   var canvasRGBALength = this.offscreenRGBCount;
   7552   if (canvasRGBALength > 0) {
   7553     //We actually updated the graphics internally, so copy out:
   7554     var frameBuffer = (canvasRGBALength == 92160) ? this.swizzledFrame : this.resizeFrameBuffer();
   7555     var canvasData = this.canvasBuffer.data;
   7556     var bufferIndex = 0;
   7557     for (var canvasIndex = 0; canvasIndex < canvasRGBALength; ++canvasIndex) {
   7558       canvasData[canvasIndex++] = frameBuffer[bufferIndex++];
   7559       canvasData[canvasIndex++] = frameBuffer[bufferIndex++];
   7560       canvasData[canvasIndex++] = frameBuffer[bufferIndex++];
   7561     }
   7562     this.graphicsBlit();
   7563   }
   7564 }
   7565 GameBoyCore.prototype.swizzleFrameBuffer = function () {
   7566   //Convert our dirty 24-bit (24-bit, with internal render flags above it) framebuffer to an 8-bit buffer with separate indices for the RGB channels:
   7567   var frameBuffer = this.frameBuffer;
   7568   var swizzledFrame = this.swizzledFrame;
   7569   var bufferIndex = 0;
   7570   for (var canvasIndex = 0; canvasIndex < 69120;) {
   7571     swizzledFrame[canvasIndex++] = (frameBuffer[bufferIndex] >> 16) & 0xFF;    //Red
   7572     swizzledFrame[canvasIndex++] = (frameBuffer[bufferIndex] >> 8) & 0xFF;    //Green
   7573     swizzledFrame[canvasIndex++] = frameBuffer[bufferIndex++] & 0xFF;      //Blue
   7574   }
   7575 }
   7576 GameBoyCore.prototype.clearFrameBuffer = function () {
   7577   var bufferIndex = 0;
   7578   var frameBuffer = this.swizzledFrame;
   7579   if (this.cGBC || this.colorizedGBPalettes) {
   7580     while (bufferIndex < 69120) {
   7581       frameBuffer[bufferIndex++] = 248;
   7582     }
   7583   }
   7584   else {
   7585     while (bufferIndex < 69120) {
   7586       frameBuffer[bufferIndex++] = 239;
   7587       frameBuffer[bufferIndex++] = 255;
   7588       frameBuffer[bufferIndex++] = 222;
   7589     }
   7590   }
   7591 }
   7592 GameBoyCore.prototype.resizeFrameBuffer = function () {
   7593   //Return a reference to the generated resized framebuffer:
   7594   return this.resizer.resize(this.swizzledFrame);
   7595 }
   7596 GameBoyCore.prototype.compileResizeFrameBufferFunction = function () {
   7597   if (this.offscreenRGBCount > 0) {
   7598     this.resizer = new Resize(160, 144, this.offscreenWidth, this.offscreenHeight, false, true);
   7599   }
   7600 }
   7601 GameBoyCore.prototype.renderScanLine = function (scanlineToRender) {
   7602   this.pixelStart = scanlineToRender * 160;
   7603   if (this.bgEnabled) {
   7604     this.pixelEnd = 160;
   7605     this.BGLayerRender(scanlineToRender);
   7606     this.WindowLayerRender(scanlineToRender);
   7607   }
   7608   else {
   7609     var pixelLine = (scanlineToRender + 1) * 160;
   7610     var defaultColor = (this.cGBC || this.colorizedGBPalettes) ? 0xF8F8F8 : 0xEFFFDE;
   7611     for (var pixelPosition = (scanlineToRender * 160) + this.currentX; pixelPosition < pixelLine; pixelPosition++) {
   7612       this.frameBuffer[pixelPosition] = defaultColor;
   7613     }
   7614   }
   7615   this.SpriteLayerRender(scanlineToRender);
   7616   this.currentX = 0;
   7617   this.midScanlineOffset = -1;
   7618 }
   7619 GameBoyCore.prototype.renderMidScanLine = function () {
   7620   if (this.actualScanLine < 144 && this.modeSTAT == 3) {
   7621     //TODO: Get this accurate:
   7622     if (this.midScanlineOffset == -1) {
   7623       this.midScanlineOffset = this.backgroundX & 0x7;
   7624     }
   7625     if (this.LCDTicks >= 82) {
   7626       this.pixelEnd = this.LCDTicks - 74;
   7627       this.pixelEnd = Math.min(this.pixelEnd - this.midScanlineOffset - (this.pixelEnd % 0x8), 160);
   7628       if (this.bgEnabled) {
   7629         this.pixelStart = this.lastUnrenderedLine * 160;
   7630         this.BGLayerRender(this.lastUnrenderedLine);
   7631         this.WindowLayerRender(this.lastUnrenderedLine);
   7632         //TODO: Do midscanline JIT for sprites...
   7633       }
   7634       else {
   7635         var pixelLine = (this.lastUnrenderedLine * 160) + this.pixelEnd;
   7636         var defaultColor = (this.cGBC || this.colorizedGBPalettes) ? 0xF8F8F8 : 0xEFFFDE;
   7637         for (var pixelPosition = (this.lastUnrenderedLine * 160) + this.currentX; pixelPosition < pixelLine; pixelPosition++) {
   7638           this.frameBuffer[pixelPosition] = defaultColor;
   7639         }
   7640       }
   7641       this.currentX = this.pixelEnd;
   7642     }
   7643   }
   7644 }
   7645 GameBoyCore.prototype.initializeModeSpecificArrays = function () {
   7646   this.LCDCONTROL = (this.LCDisOn) ? this.LINECONTROL : this.DISPLAYOFFCONTROL;
   7647   if (this.cGBC) {
   7648     this.gbcOBJRawPalette = this.getTypedArray(0x40, 0, "uint8");
   7649     this.gbcBGRawPalette = this.getTypedArray(0x40, 0, "uint8");
   7650     this.gbcOBJPalette = this.getTypedArray(0x20, 0x1000000, "int32");
   7651     this.gbcBGPalette = this.getTypedArray(0x40, 0, "int32");
   7652     this.BGCHRBank2 = this.getTypedArray(0x800, 0, "uint8");
   7653     this.BGCHRCurrentBank = (this.currVRAMBank > 0) ? this.BGCHRBank2 : this.BGCHRBank1;
   7654     this.tileCache = this.generateCacheArray(0xF80);
   7655   }
   7656   else {
   7657     this.gbOBJPalette = this.getTypedArray(8, 0, "int32");
   7658     this.gbBGPalette = this.getTypedArray(4, 0, "int32");
   7659     this.BGPalette = this.gbBGPalette;
   7660     this.OBJPalette = this.gbOBJPalette;
   7661     this.tileCache = this.generateCacheArray(0x700);
   7662     this.sortBuffer = this.getTypedArray(0x100, 0, "uint8");
   7663     this.OAMAddressCache = this.getTypedArray(10, 0, "int32");
   7664   }
   7665   this.renderPathBuild();
   7666 }
   7667 GameBoyCore.prototype.GBCtoGBModeAdjust = function () {
   7668   cout("Stepping down from GBC mode.", 0);
   7669   this.VRAM = this.GBCMemory = this.BGCHRCurrentBank = this.BGCHRBank2 = null;
   7670   this.tileCache.length = 0x700;
   7671   if (settings[4]) {
   7672     this.gbBGColorizedPalette = this.getTypedArray(4, 0, "int32");
   7673     this.gbOBJColorizedPalette = this.getTypedArray(8, 0, "int32");
   7674     this.cachedBGPaletteConversion = this.getTypedArray(4, 0, "int32");
   7675     this.cachedOBJPaletteConversion = this.getTypedArray(8, 0, "int32");
   7676     this.BGPalette = this.gbBGColorizedPalette;
   7677     this.OBJPalette = this.gbOBJColorizedPalette;
   7678     this.gbOBJPalette = this.gbBGPalette = null;
   7679     this.getGBCColor();
   7680   }
   7681   else {
   7682     this.gbOBJPalette = this.getTypedArray(8, 0, "int32");
   7683     this.gbBGPalette = this.getTypedArray(4, 0, "int32");
   7684     this.BGPalette = this.gbBGPalette;
   7685     this.OBJPalette = this.gbOBJPalette;
   7686   }
   7687   this.sortBuffer = this.getTypedArray(0x100, 0, "uint8");
   7688   this.OAMAddressCache = this.getTypedArray(10, 0, "int32");
   7689   this.renderPathBuild();
   7690   this.memoryReadJumpCompile();
   7691   this.memoryWriteJumpCompile();
   7692 }
   7693 GameBoyCore.prototype.renderPathBuild = function () {
   7694   if (!this.cGBC) {
   7695     this.BGLayerRender = this.BGGBLayerRender;
   7696     this.WindowLayerRender = this.WindowGBLayerRender;
   7697     this.SpriteLayerRender = this.SpriteGBLayerRender;
   7698   }
   7699   else {
   7700     this.priorityFlaggingPathRebuild();
   7701     this.SpriteLayerRender = this.SpriteGBCLayerRender;
   7702   }
   7703 }
   7704 GameBoyCore.prototype.priorityFlaggingPathRebuild = function () {
   7705   if (this.BGPriorityEnabled) {
   7706     this.BGLayerRender = this.BGGBCLayerRender;
   7707     this.WindowLayerRender = this.WindowGBCLayerRender;
   7708   }
   7709   else {
   7710     this.BGLayerRender = this.BGGBCLayerRenderNoPriorityFlagging;
   7711     this.WindowLayerRender = this.WindowGBCLayerRenderNoPriorityFlagging;
   7712   }
   7713 }
   7714 GameBoyCore.prototype.initializeReferencesFromSaveState = function () {
   7715   this.LCDCONTROL = (this.LCDisOn) ? this.LINECONTROL : this.DISPLAYOFFCONTROL;
   7716   var tileIndex = 0;
   7717   if (!this.cGBC) {
   7718     if (this.colorizedGBPalettes) {
   7719       this.BGPalette = this.gbBGColorizedPalette;
   7720       this.OBJPalette = this.gbOBJColorizedPalette;
   7721       this.updateGBBGPalette = this.updateGBColorizedBGPalette;
   7722       this.updateGBOBJPalette = this.updateGBColorizedOBJPalette;
   7723 
   7724     }
   7725     else {
   7726       this.BGPalette = this.gbBGPalette;
   7727       this.OBJPalette = this.gbOBJPalette;
   7728     }
   7729     this.tileCache = this.generateCacheArray(0x700);
   7730     for (tileIndex = 0x8000; tileIndex < 0x9000; tileIndex += 2) {
   7731       this.generateGBOAMTileLine(tileIndex);
   7732     }
   7733     for (tileIndex = 0x9000; tileIndex < 0x9800; tileIndex += 2) {
   7734       this.generateGBTileLine(tileIndex);
   7735     }
   7736     this.sortBuffer = this.getTypedArray(0x100, 0, "uint8");
   7737     this.OAMAddressCache = this.getTypedArray(10, 0, "int32");
   7738   }
   7739   else {
   7740     this.BGCHRCurrentBank = (this.currVRAMBank > 0) ? this.BGCHRBank2 : this.BGCHRBank1;
   7741     this.tileCache = this.generateCacheArray(0xF80);
   7742     for (; tileIndex < 0x1800; tileIndex += 0x10) {
   7743       this.generateGBCTileBank1(tileIndex);
   7744       this.generateGBCTileBank2(tileIndex);
   7745     }
   7746   }
   7747   this.renderPathBuild();
   7748 }
   7749 GameBoyCore.prototype.RGBTint = function (value) {
   7750   //Adjustment for the GBC's tinting (According to Gambatte):
   7751   var r = value & 0x1F;
   7752   var g = (value >> 5) & 0x1F;
   7753   var b = (value >> 10) & 0x1F;
   7754   return ((r * 13 + g * 2 + b) >> 1) << 16 | (g * 3 + b) << 9 | (r * 3 + g * 2 + b * 11) >> 1;
   7755 }
   7756 GameBoyCore.prototype.getGBCColor = function () {
   7757   //GBC Colorization of DMG ROMs:
   7758   //BG
   7759   for (var counter = 0; counter < 4; counter++) {
   7760     var adjustedIndex = counter << 1;
   7761     //BG
   7762     this.cachedBGPaletteConversion[counter] = this.RGBTint((this.gbcBGRawPalette[adjustedIndex | 1] << 8) | this.gbcBGRawPalette[adjustedIndex]);
   7763     //OBJ 1
   7764     this.cachedOBJPaletteConversion[counter] = this.RGBTint((this.gbcOBJRawPalette[adjustedIndex | 1] << 8) | this.gbcOBJRawPalette[adjustedIndex]);
   7765   }
   7766   //OBJ 2
   7767   for (counter = 4; counter < 8; counter++) {
   7768     adjustedIndex = counter << 1;
   7769     this.cachedOBJPaletteConversion[counter] = this.RGBTint((this.gbcOBJRawPalette[adjustedIndex | 1] << 8) | this.gbcOBJRawPalette[adjustedIndex]);
   7770   }
   7771   //Update the palette entries:
   7772   this.updateGBBGPalette = this.updateGBColorizedBGPalette;
   7773   this.updateGBOBJPalette = this.updateGBColorizedOBJPalette;
   7774   this.updateGBBGPalette(this.memory[0xFF47]);
   7775   this.updateGBOBJPalette(0, this.memory[0xFF48]);
   7776   this.updateGBOBJPalette(1, this.memory[0xFF49]);
   7777   this.colorizedGBPalettes = true;
   7778 }
   7779 GameBoyCore.prototype.updateGBRegularBGPalette = function (data) {
   7780   this.gbBGPalette[0] = this.colors[data & 0x03] | 0x2000000;
   7781   this.gbBGPalette[1] = this.colors[(data >> 2) & 0x03];
   7782   this.gbBGPalette[2] = this.colors[(data >> 4) & 0x03];
   7783   this.gbBGPalette[3] = this.colors[data >> 6];
   7784 }
   7785 GameBoyCore.prototype.updateGBColorizedBGPalette = function (data) {
   7786   //GB colorization:
   7787   this.gbBGColorizedPalette[0] = this.cachedBGPaletteConversion[data & 0x03] | 0x2000000;
   7788   this.gbBGColorizedPalette[1] = this.cachedBGPaletteConversion[(data >> 2) & 0x03];
   7789   this.gbBGColorizedPalette[2] = this.cachedBGPaletteConversion[(data >> 4) & 0x03];
   7790   this.gbBGColorizedPalette[3] = this.cachedBGPaletteConversion[data >> 6];
   7791 }
   7792 GameBoyCore.prototype.updateGBRegularOBJPalette = function (index, data) {
   7793   this.gbOBJPalette[index | 1] = this.colors[(data >> 2) & 0x03];
   7794   this.gbOBJPalette[index | 2] = this.colors[(data >> 4) & 0x03];
   7795   this.gbOBJPalette[index | 3] = this.colors[data >> 6];
   7796 }
   7797 GameBoyCore.prototype.updateGBColorizedOBJPalette = function (index, data) {
   7798   //GB colorization:
   7799   this.gbOBJColorizedPalette[index | 1] = this.cachedOBJPaletteConversion[index | ((data >> 2) & 0x03)];
   7800   this.gbOBJColorizedPalette[index | 2] = this.cachedOBJPaletteConversion[index | ((data >> 4) & 0x03)];
   7801   this.gbOBJColorizedPalette[index | 3] = this.cachedOBJPaletteConversion[index | (data >> 6)];
   7802 }
   7803 GameBoyCore.prototype.updateGBCBGPalette = function (index, data) {
   7804   if (this.gbcBGRawPalette[index] != data) {
   7805     this.midScanLineJIT();
   7806     //Update the color palette for BG tiles since it changed:
   7807     this.gbcBGRawPalette[index] = data;
   7808     if ((index & 0x06) == 0) {
   7809       //Palette 0 (Special tile Priority stuff)
   7810       data = 0x2000000 | this.RGBTint((this.gbcBGRawPalette[index | 1] << 8) | this.gbcBGRawPalette[index & 0x3E]);
   7811       index >>= 1;
   7812       this.gbcBGPalette[index] = data;
   7813       this.gbcBGPalette[0x20 | index] = 0x1000000 | data;
   7814     }
   7815     else {
   7816       //Regular Palettes (No special crap)
   7817       data = this.RGBTint((this.gbcBGRawPalette[index | 1] << 8) | this.gbcBGRawPalette[index & 0x3E]);
   7818       index >>= 1;
   7819       this.gbcBGPalette[index] = data;
   7820       this.gbcBGPalette[0x20 | index] = 0x1000000 | data;
   7821     }
   7822   }
   7823 }
   7824 GameBoyCore.prototype.updateGBCOBJPalette = function (index, data) {
   7825   if (this.gbcOBJRawPalette[index] != data) {
   7826     //Update the color palette for OBJ tiles since it changed:
   7827     this.gbcOBJRawPalette[index] = data;
   7828     if ((index & 0x06) > 0) {
   7829       //Regular Palettes (No special crap)
   7830       this.midScanLineJIT();
   7831       this.gbcOBJPalette[index >> 1] = 0x1000000 | this.RGBTint((this.gbcOBJRawPalette[index | 1] << 8) | this.gbcOBJRawPalette[index & 0x3E]);
   7832     }
   7833   }
   7834 }
   7835 GameBoyCore.prototype.BGGBLayerRender = function (scanlineToRender) {
   7836   var scrollYAdjusted = (this.backgroundY + scanlineToRender) & 0xFF;            //The line of the BG we're at.
   7837   var tileYLine = (scrollYAdjusted & 7) << 3;
   7838   var tileYDown = this.gfxBackgroundCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2);  //The row of cached tiles we're fetching from.
   7839   var scrollXAdjusted = (this.backgroundX + this.currentX) & 0xFF;            //The scroll amount of the BG.
   7840   var pixelPosition = this.pixelStart + this.currentX;                  //Current pixel we're working on.
   7841   var pixelPositionEnd = this.pixelStart + ((this.gfxWindowDisplay && (scanlineToRender - this.windowY) >= 0) ? Math.min(Math.max(this.windowX, 0) + this.currentX, this.pixelEnd) : this.pixelEnd);  //Make sure we do at most 160 pixels a scanline.
   7842   var tileNumber = tileYDown + (scrollXAdjusted >> 3);
   7843   var chrCode = this.BGCHRBank1[tileNumber];
   7844   if (chrCode < this.gfxBackgroundBankOffset) {
   7845     chrCode |= 0x100;
   7846   }
   7847   var tile = this.tileCache[chrCode];
   7848   for (var texel = (scrollXAdjusted & 0x7); texel < 8 && pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
   7849     this.frameBuffer[pixelPosition++] = this.BGPalette[tile[tileYLine | texel++]];
   7850   }
   7851   var scrollXAdjustedAligned = Math.min(pixelPositionEnd - pixelPosition, 0x100 - scrollXAdjusted) >> 3;
   7852   scrollXAdjusted += scrollXAdjustedAligned << 3;
   7853   scrollXAdjustedAligned += tileNumber;
   7854   while (tileNumber < scrollXAdjustedAligned) {
   7855     chrCode = this.BGCHRBank1[++tileNumber];
   7856     if (chrCode < this.gfxBackgroundBankOffset) {
   7857       chrCode |= 0x100;
   7858     }
   7859     tile = this.tileCache[chrCode];
   7860     texel = tileYLine;
   7861     this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7862     this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7863     this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7864     this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7865     this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7866     this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7867     this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7868     this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel]];
   7869   }
   7870   if (pixelPosition < pixelPositionEnd) {
   7871     if (scrollXAdjusted < 0x100) {
   7872       chrCode = this.BGCHRBank1[++tileNumber];
   7873       if (chrCode < this.gfxBackgroundBankOffset) {
   7874         chrCode |= 0x100;
   7875       }
   7876       tile = this.tileCache[chrCode];
   7877       for (texel = tileYLine - 1; pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
   7878         this.frameBuffer[pixelPosition++] = this.BGPalette[tile[++texel]];
   7879       }
   7880     }
   7881     scrollXAdjustedAligned = ((pixelPositionEnd - pixelPosition) >> 3) + tileYDown;
   7882     while (tileYDown < scrollXAdjustedAligned) {
   7883       chrCode = this.BGCHRBank1[tileYDown++];
   7884       if (chrCode < this.gfxBackgroundBankOffset) {
   7885         chrCode |= 0x100;
   7886       }
   7887       tile = this.tileCache[chrCode];
   7888       texel = tileYLine;
   7889       this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7890       this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7891       this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7892       this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7893       this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7894       this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7895       this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   7896       this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel]];
   7897     }
   7898     if (pixelPosition < pixelPositionEnd) {
   7899       chrCode = this.BGCHRBank1[tileYDown];
   7900       if (chrCode < this.gfxBackgroundBankOffset) {
   7901         chrCode |= 0x100;
   7902       }
   7903       tile = this.tileCache[chrCode];
   7904       switch (pixelPositionEnd - pixelPosition) {
   7905         case 7:
   7906           this.frameBuffer[pixelPosition + 6] = this.BGPalette[tile[tileYLine | 6]];
   7907         case 6:
   7908           this.frameBuffer[pixelPosition + 5] = this.BGPalette[tile[tileYLine | 5]];
   7909         case 5:
   7910           this.frameBuffer[pixelPosition + 4] = this.BGPalette[tile[tileYLine | 4]];
   7911         case 4:
   7912           this.frameBuffer[pixelPosition + 3] = this.BGPalette[tile[tileYLine | 3]];
   7913         case 3:
   7914           this.frameBuffer[pixelPosition + 2] = this.BGPalette[tile[tileYLine | 2]];
   7915         case 2:
   7916           this.frameBuffer[pixelPosition + 1] = this.BGPalette[tile[tileYLine | 1]];
   7917         case 1:
   7918           this.frameBuffer[pixelPosition] = this.BGPalette[tile[tileYLine]];
   7919       }
   7920     }
   7921   }
   7922 }
   7923 GameBoyCore.prototype.BGGBCLayerRender = function (scanlineToRender) {
   7924   var scrollYAdjusted = (this.backgroundY + scanlineToRender) & 0xFF;            //The line of the BG we're at.
   7925   var tileYLine = (scrollYAdjusted & 7) << 3;
   7926   var tileYDown = this.gfxBackgroundCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2);  //The row of cached tiles we're fetching from.
   7927   var scrollXAdjusted = (this.backgroundX + this.currentX) & 0xFF;            //The scroll amount of the BG.
   7928   var pixelPosition = this.pixelStart + this.currentX;                  //Current pixel we're working on.
   7929   var pixelPositionEnd = this.pixelStart + ((this.gfxWindowDisplay && (scanlineToRender - this.windowY) >= 0) ? Math.min(Math.max(this.windowX, 0) + this.currentX, this.pixelEnd) : this.pixelEnd);  //Make sure we do at most 160 pixels a scanline.
   7930   var tileNumber = tileYDown + (scrollXAdjusted >> 3);
   7931   var chrCode = this.BGCHRBank1[tileNumber];
   7932   if (chrCode < this.gfxBackgroundBankOffset) {
   7933     chrCode |= 0x100;
   7934   }
   7935   var attrCode = this.BGCHRBank2[tileNumber];
   7936   var tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   7937   var palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
   7938   for (var texel = (scrollXAdjusted & 0x7); texel < 8 && pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
   7939     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[tileYLine | texel++]];
   7940   }
   7941   var scrollXAdjustedAligned = Math.min(pixelPositionEnd - pixelPosition, 0x100 - scrollXAdjusted) >> 3;
   7942   scrollXAdjusted += scrollXAdjustedAligned << 3;
   7943   scrollXAdjustedAligned += tileNumber;
   7944   while (tileNumber < scrollXAdjustedAligned) {
   7945     chrCode = this.BGCHRBank1[++tileNumber];
   7946     if (chrCode < this.gfxBackgroundBankOffset) {
   7947       chrCode |= 0x100;
   7948     }
   7949     attrCode = this.BGCHRBank2[tileNumber];
   7950     tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   7951     palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
   7952     texel = tileYLine;
   7953     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7954     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7955     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7956     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7957     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7958     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7959     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7960     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
   7961   }
   7962   if (pixelPosition < pixelPositionEnd) {
   7963     if (scrollXAdjusted < 0x100) {
   7964       chrCode = this.BGCHRBank1[++tileNumber];
   7965       if (chrCode < this.gfxBackgroundBankOffset) {
   7966         chrCode |= 0x100;
   7967       }
   7968       attrCode = this.BGCHRBank2[tileNumber];
   7969       tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   7970       palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
   7971       for (texel = tileYLine - 1; pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
   7972         this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[++texel]];
   7973       }
   7974     }
   7975     scrollXAdjustedAligned = ((pixelPositionEnd - pixelPosition) >> 3) + tileYDown;
   7976     while (tileYDown < scrollXAdjustedAligned) {
   7977       chrCode = this.BGCHRBank1[tileYDown];
   7978       if (chrCode < this.gfxBackgroundBankOffset) {
   7979         chrCode |= 0x100;
   7980       }
   7981       attrCode = this.BGCHRBank2[tileYDown++];
   7982       tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   7983       palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
   7984       texel = tileYLine;
   7985       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7986       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7987       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7988       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7989       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7990       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7991       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   7992       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
   7993     }
   7994     if (pixelPosition < pixelPositionEnd) {
   7995       chrCode = this.BGCHRBank1[tileYDown];
   7996       if (chrCode < this.gfxBackgroundBankOffset) {
   7997         chrCode |= 0x100;
   7998       }
   7999       attrCode = this.BGCHRBank2[tileYDown];
   8000       tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8001       palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
   8002       switch (pixelPositionEnd - pixelPosition) {
   8003         case 7:
   8004           this.frameBuffer[pixelPosition + 6] = this.gbcBGPalette[palette | tile[tileYLine | 6]];
   8005         case 6:
   8006           this.frameBuffer[pixelPosition + 5] = this.gbcBGPalette[palette | tile[tileYLine | 5]];
   8007         case 5:
   8008           this.frameBuffer[pixelPosition + 4] = this.gbcBGPalette[palette | tile[tileYLine | 4]];
   8009         case 4:
   8010           this.frameBuffer[pixelPosition + 3] = this.gbcBGPalette[palette | tile[tileYLine | 3]];
   8011         case 3:
   8012           this.frameBuffer[pixelPosition + 2] = this.gbcBGPalette[palette | tile[tileYLine | 2]];
   8013         case 2:
   8014           this.frameBuffer[pixelPosition + 1] = this.gbcBGPalette[palette | tile[tileYLine | 1]];
   8015         case 1:
   8016           this.frameBuffer[pixelPosition] = this.gbcBGPalette[palette | tile[tileYLine]];
   8017       }
   8018     }
   8019   }
   8020 }
   8021 GameBoyCore.prototype.BGGBCLayerRenderNoPriorityFlagging = function (scanlineToRender) {
   8022   var scrollYAdjusted = (this.backgroundY + scanlineToRender) & 0xFF;            //The line of the BG we're at.
   8023   var tileYLine = (scrollYAdjusted & 7) << 3;
   8024   var tileYDown = this.gfxBackgroundCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2);  //The row of cached tiles we're fetching from.
   8025   var scrollXAdjusted = (this.backgroundX + this.currentX) & 0xFF;            //The scroll amount of the BG.
   8026   var pixelPosition = this.pixelStart + this.currentX;                  //Current pixel we're working on.
   8027   var pixelPositionEnd = this.pixelStart + ((this.gfxWindowDisplay && (scanlineToRender - this.windowY) >= 0) ? Math.min(Math.max(this.windowX, 0) + this.currentX, this.pixelEnd) : this.pixelEnd);  //Make sure we do at most 160 pixels a scanline.
   8028   var tileNumber = tileYDown + (scrollXAdjusted >> 3);
   8029   var chrCode = this.BGCHRBank1[tileNumber];
   8030   if (chrCode < this.gfxBackgroundBankOffset) {
   8031     chrCode |= 0x100;
   8032   }
   8033   var attrCode = this.BGCHRBank2[tileNumber];
   8034   var tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8035   var palette = (attrCode & 0x7) << 2;
   8036   for (var texel = (scrollXAdjusted & 0x7); texel < 8 && pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
   8037     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[tileYLine | texel++]];
   8038   }
   8039   var scrollXAdjustedAligned = Math.min(pixelPositionEnd - pixelPosition, 0x100 - scrollXAdjusted) >> 3;
   8040   scrollXAdjusted += scrollXAdjustedAligned << 3;
   8041   scrollXAdjustedAligned += tileNumber;
   8042   while (tileNumber < scrollXAdjustedAligned) {
   8043     chrCode = this.BGCHRBank1[++tileNumber];
   8044     if (chrCode < this.gfxBackgroundBankOffset) {
   8045       chrCode |= 0x100;
   8046     }
   8047     attrCode = this.BGCHRBank2[tileNumber];
   8048     tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8049     palette = (attrCode & 0x7) << 2;
   8050     texel = tileYLine;
   8051     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8052     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8053     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8054     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8055     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8056     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8057     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8058     this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
   8059   }
   8060   if (pixelPosition < pixelPositionEnd) {
   8061     if (scrollXAdjusted < 0x100) {
   8062       chrCode = this.BGCHRBank1[++tileNumber];
   8063       if (chrCode < this.gfxBackgroundBankOffset) {
   8064         chrCode |= 0x100;
   8065       }
   8066       attrCode = this.BGCHRBank2[tileNumber];
   8067       tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8068       palette = (attrCode & 0x7) << 2;
   8069       for (texel = tileYLine - 1; pixelPosition < pixelPositionEnd && scrollXAdjusted < 0x100; ++scrollXAdjusted) {
   8070         this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[++texel]];
   8071       }
   8072     }
   8073     scrollXAdjustedAligned = ((pixelPositionEnd - pixelPosition) >> 3) + tileYDown;
   8074     while (tileYDown < scrollXAdjustedAligned) {
   8075       chrCode = this.BGCHRBank1[tileYDown];
   8076       if (chrCode < this.gfxBackgroundBankOffset) {
   8077         chrCode |= 0x100;
   8078       }
   8079       attrCode = this.BGCHRBank2[tileYDown++];
   8080       tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8081       palette = (attrCode & 0x7) << 2;
   8082       texel = tileYLine;
   8083       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8084       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8085       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8086       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8087       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8088       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8089       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8090       this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
   8091     }
   8092     if (pixelPosition < pixelPositionEnd) {
   8093       chrCode = this.BGCHRBank1[tileYDown];
   8094       if (chrCode < this.gfxBackgroundBankOffset) {
   8095         chrCode |= 0x100;
   8096       }
   8097       attrCode = this.BGCHRBank2[tileYDown];
   8098       tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8099       palette = (attrCode & 0x7) << 2;
   8100       switch (pixelPositionEnd - pixelPosition) {
   8101         case 7:
   8102           this.frameBuffer[pixelPosition + 6] = this.gbcBGPalette[palette | tile[tileYLine | 6]];
   8103         case 6:
   8104           this.frameBuffer[pixelPosition + 5] = this.gbcBGPalette[palette | tile[tileYLine | 5]];
   8105         case 5:
   8106           this.frameBuffer[pixelPosition + 4] = this.gbcBGPalette[palette | tile[tileYLine | 4]];
   8107         case 4:
   8108           this.frameBuffer[pixelPosition + 3] = this.gbcBGPalette[palette | tile[tileYLine | 3]];
   8109         case 3:
   8110           this.frameBuffer[pixelPosition + 2] = this.gbcBGPalette[palette | tile[tileYLine | 2]];
   8111         case 2:
   8112           this.frameBuffer[pixelPosition + 1] = this.gbcBGPalette[palette | tile[tileYLine | 1]];
   8113         case 1:
   8114           this.frameBuffer[pixelPosition] = this.gbcBGPalette[palette | tile[tileYLine]];
   8115       }
   8116     }
   8117   }
   8118 }
   8119 GameBoyCore.prototype.WindowGBLayerRender = function (scanlineToRender) {
   8120   if (this.gfxWindowDisplay) {                  //Is the window enabled?
   8121     var scrollYAdjusted = scanlineToRender - this.windowY;    //The line of the BG we're at.
   8122     if (scrollYAdjusted >= 0) {
   8123       var scrollXRangeAdjusted = (this.windowX > 0) ? (this.windowX + this.currentX) : this.currentX;
   8124       var pixelPosition = this.pixelStart + scrollXRangeAdjusted;
   8125       var pixelPositionEnd = this.pixelStart + this.pixelEnd;
   8126       if (pixelPosition < pixelPositionEnd) {
   8127         var tileYLine = (scrollYAdjusted & 0x7) << 3;
   8128         var tileNumber = (this.gfxWindowCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2)) + (this.currentX >> 3);
   8129         var chrCode = this.BGCHRBank1[tileNumber];
   8130         if (chrCode < this.gfxBackgroundBankOffset) {
   8131           chrCode |= 0x100;
   8132         }
   8133         var tile = this.tileCache[chrCode];
   8134         var texel = (scrollXRangeAdjusted - this.windowX) & 0x7;
   8135         scrollXRangeAdjusted = Math.min(8, texel + pixelPositionEnd - pixelPosition);
   8136         while (texel < scrollXRangeAdjusted) {
   8137           this.frameBuffer[pixelPosition++] = this.BGPalette[tile[tileYLine | texel++]];
   8138         }
   8139         scrollXRangeAdjusted = tileNumber + ((pixelPositionEnd - pixelPosition) >> 3);
   8140         while (tileNumber < scrollXRangeAdjusted) {
   8141           chrCode = this.BGCHRBank1[++tileNumber];
   8142           if (chrCode < this.gfxBackgroundBankOffset) {
   8143             chrCode |= 0x100;
   8144           }
   8145           tile = this.tileCache[chrCode];
   8146           texel = tileYLine;
   8147           this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   8148           this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   8149           this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   8150           this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   8151           this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   8152           this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   8153           this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel++]];
   8154           this.frameBuffer[pixelPosition++] = this.BGPalette[tile[texel]];
   8155         }
   8156         if (pixelPosition < pixelPositionEnd) {
   8157           chrCode = this.BGCHRBank1[++tileNumber];
   8158           if (chrCode < this.gfxBackgroundBankOffset) {
   8159             chrCode |= 0x100;
   8160           }
   8161           tile = this.tileCache[chrCode];
   8162           switch (pixelPositionEnd - pixelPosition) {
   8163             case 7:
   8164               this.frameBuffer[pixelPosition + 6] = this.BGPalette[tile[tileYLine | 6]];
   8165             case 6:
   8166               this.frameBuffer[pixelPosition + 5] = this.BGPalette[tile[tileYLine | 5]];
   8167             case 5:
   8168               this.frameBuffer[pixelPosition + 4] = this.BGPalette[tile[tileYLine | 4]];
   8169             case 4:
   8170               this.frameBuffer[pixelPosition + 3] = this.BGPalette[tile[tileYLine | 3]];
   8171             case 3:
   8172               this.frameBuffer[pixelPosition + 2] = this.BGPalette[tile[tileYLine | 2]];
   8173             case 2:
   8174               this.frameBuffer[pixelPosition + 1] = this.BGPalette[tile[tileYLine | 1]];
   8175             case 1:
   8176               this.frameBuffer[pixelPosition] = this.BGPalette[tile[tileYLine]];
   8177           }
   8178         }
   8179       }
   8180     }
   8181   }
   8182 }
   8183 GameBoyCore.prototype.WindowGBCLayerRender = function (scanlineToRender) {
   8184   if (this.gfxWindowDisplay) {                  //Is the window enabled?
   8185     var scrollYAdjusted = scanlineToRender - this.windowY;    //The line of the BG we're at.
   8186     if (scrollYAdjusted >= 0) {
   8187       var scrollXRangeAdjusted = (this.windowX > 0) ? (this.windowX + this.currentX) : this.currentX;
   8188       var pixelPosition = this.pixelStart + scrollXRangeAdjusted;
   8189       var pixelPositionEnd = this.pixelStart + this.pixelEnd;
   8190       if (pixelPosition < pixelPositionEnd) {
   8191         var tileYLine = (scrollYAdjusted & 0x7) << 3;
   8192         var tileNumber = (this.gfxWindowCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2)) + (this.currentX >> 3);
   8193         var chrCode = this.BGCHRBank1[tileNumber];
   8194         if (chrCode < this.gfxBackgroundBankOffset) {
   8195           chrCode |= 0x100;
   8196         }
   8197         var attrCode = this.BGCHRBank2[tileNumber];
   8198         var tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8199         var palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
   8200         var texel = (scrollXRangeAdjusted - this.windowX) & 0x7;
   8201         scrollXRangeAdjusted = Math.min(8, texel + pixelPositionEnd - pixelPosition);
   8202         while (texel < scrollXRangeAdjusted) {
   8203           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[tileYLine | texel++]];
   8204         }
   8205         scrollXRangeAdjusted = tileNumber + ((pixelPositionEnd - pixelPosition) >> 3);
   8206         while (tileNumber < scrollXRangeAdjusted) {
   8207           chrCode = this.BGCHRBank1[++tileNumber];
   8208           if (chrCode < this.gfxBackgroundBankOffset) {
   8209             chrCode |= 0x100;
   8210           }
   8211           attrCode = this.BGCHRBank2[tileNumber];
   8212           tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8213           palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
   8214           texel = tileYLine;
   8215           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8216           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8217           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8218           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8219           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8220           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8221           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8222           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
   8223         }
   8224         if (pixelPosition < pixelPositionEnd) {
   8225           chrCode = this.BGCHRBank1[++tileNumber];
   8226           if (chrCode < this.gfxBackgroundBankOffset) {
   8227             chrCode |= 0x100;
   8228           }
   8229           attrCode = this.BGCHRBank2[tileNumber];
   8230           tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8231           palette = ((attrCode & 0x7) << 2) | ((attrCode & 0x80) >> 2);
   8232           switch (pixelPositionEnd - pixelPosition) {
   8233             case 7:
   8234               this.frameBuffer[pixelPosition + 6] = this.gbcBGPalette[palette | tile[tileYLine | 6]];
   8235             case 6:
   8236               this.frameBuffer[pixelPosition + 5] = this.gbcBGPalette[palette | tile[tileYLine | 5]];
   8237             case 5:
   8238               this.frameBuffer[pixelPosition + 4] = this.gbcBGPalette[palette | tile[tileYLine | 4]];
   8239             case 4:
   8240               this.frameBuffer[pixelPosition + 3] = this.gbcBGPalette[palette | tile[tileYLine | 3]];
   8241             case 3:
   8242               this.frameBuffer[pixelPosition + 2] = this.gbcBGPalette[palette | tile[tileYLine | 2]];
   8243             case 2:
   8244               this.frameBuffer[pixelPosition + 1] = this.gbcBGPalette[palette | tile[tileYLine | 1]];
   8245             case 1:
   8246               this.frameBuffer[pixelPosition] = this.gbcBGPalette[palette | tile[tileYLine]];
   8247           }
   8248         }
   8249       }
   8250     }
   8251   }
   8252 }
   8253 GameBoyCore.prototype.WindowGBCLayerRenderNoPriorityFlagging = function (scanlineToRender) {
   8254   if (this.gfxWindowDisplay) {                  //Is the window enabled?
   8255     var scrollYAdjusted = scanlineToRender - this.windowY;    //The line of the BG we're at.
   8256     if (scrollYAdjusted >= 0) {
   8257       var scrollXRangeAdjusted = (this.windowX > 0) ? (this.windowX + this.currentX) : this.currentX;
   8258       var pixelPosition = this.pixelStart + scrollXRangeAdjusted;
   8259       var pixelPositionEnd = this.pixelStart + this.pixelEnd;
   8260       if (pixelPosition < pixelPositionEnd) {
   8261         var tileYLine = (scrollYAdjusted & 0x7) << 3;
   8262         var tileNumber = (this.gfxWindowCHRBankPosition | ((scrollYAdjusted & 0xF8) << 2)) + (this.currentX >> 3);
   8263         var chrCode = this.BGCHRBank1[tileNumber];
   8264         if (chrCode < this.gfxBackgroundBankOffset) {
   8265           chrCode |= 0x100;
   8266         }
   8267         var attrCode = this.BGCHRBank2[tileNumber];
   8268         var tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8269         var palette = (attrCode & 0x7) << 2;
   8270         var texel = (scrollXRangeAdjusted - this.windowX) & 0x7;
   8271         scrollXRangeAdjusted = Math.min(8, texel + pixelPositionEnd - pixelPosition);
   8272         while (texel < scrollXRangeAdjusted) {
   8273           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[tileYLine | texel++]];
   8274         }
   8275         scrollXRangeAdjusted = tileNumber + ((pixelPositionEnd - pixelPosition) >> 3);
   8276         while (tileNumber < scrollXRangeAdjusted) {
   8277           chrCode = this.BGCHRBank1[++tileNumber];
   8278           if (chrCode < this.gfxBackgroundBankOffset) {
   8279             chrCode |= 0x100;
   8280           }
   8281           attrCode = this.BGCHRBank2[tileNumber];
   8282           tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8283           palette = (attrCode & 0x7) << 2;
   8284           texel = tileYLine;
   8285           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8286           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8287           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8288           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8289           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8290           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8291           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel++]];
   8292           this.frameBuffer[pixelPosition++] = this.gbcBGPalette[palette | tile[texel]];
   8293         }
   8294         if (pixelPosition < pixelPositionEnd) {
   8295           chrCode = this.BGCHRBank1[++tileNumber];
   8296           if (chrCode < this.gfxBackgroundBankOffset) {
   8297             chrCode |= 0x100;
   8298           }
   8299           attrCode = this.BGCHRBank2[tileNumber];
   8300           tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | chrCode];
   8301           palette = (attrCode & 0x7) << 2;
   8302           switch (pixelPositionEnd - pixelPosition) {
   8303             case 7:
   8304               this.frameBuffer[pixelPosition + 6] = this.gbcBGPalette[palette | tile[tileYLine | 6]];
   8305             case 6:
   8306               this.frameBuffer[pixelPosition + 5] = this.gbcBGPalette[palette | tile[tileYLine | 5]];
   8307             case 5:
   8308               this.frameBuffer[pixelPosition + 4] = this.gbcBGPalette[palette | tile[tileYLine | 4]];
   8309             case 4:
   8310               this.frameBuffer[pixelPosition + 3] = this.gbcBGPalette[palette | tile[tileYLine | 3]];
   8311             case 3:
   8312               this.frameBuffer[pixelPosition + 2] = this.gbcBGPalette[palette | tile[tileYLine | 2]];
   8313             case 2:
   8314               this.frameBuffer[pixelPosition + 1] = this.gbcBGPalette[palette | tile[tileYLine | 1]];
   8315             case 1:
   8316               this.frameBuffer[pixelPosition] = this.gbcBGPalette[palette | tile[tileYLine]];
   8317           }
   8318         }
   8319       }
   8320     }
   8321   }
   8322 }
   8323 GameBoyCore.prototype.SpriteGBLayerRender = function (scanlineToRender) {
   8324   if (this.gfxSpriteShow) {                    //Are sprites enabled?
   8325     var lineAdjusted = scanlineToRender + 0x10;
   8326     var OAMAddress = 0xFE00;
   8327     var yoffset = 0;
   8328     var xcoord = 1;
   8329     var xCoordStart = 0;
   8330     var xCoordEnd = 0;
   8331     var attrCode = 0;
   8332     var palette = 0;
   8333     var tile = null;
   8334     var data = 0;
   8335     var spriteCount = 0;
   8336     var length = 0;
   8337     var currentPixel = 0;
   8338     var linePixel = 0;
   8339     //Clear our x-coord sort buffer:
   8340     while (xcoord < 168) {
   8341       this.sortBuffer[xcoord++] = 0xFF;
   8342     }
   8343     if (this.gfxSpriteNormalHeight) {
   8344       //Draw the visible sprites:
   8345       for (var length = this.findLowestSpriteDrawable(lineAdjusted, 0x7); spriteCount < length; ++spriteCount) {
   8346         OAMAddress = this.OAMAddressCache[spriteCount];
   8347         yoffset = (lineAdjusted - this.memory[OAMAddress]) << 3;
   8348         attrCode = this.memory[OAMAddress | 3];
   8349         palette = (attrCode & 0x10) >> 2;
   8350         tile = this.tileCache[((attrCode & 0x60) << 4) | this.memory[OAMAddress | 0x2]];
   8351         linePixel = xCoordStart = this.memory[OAMAddress | 1];
   8352         xCoordEnd = Math.min(168 - linePixel, 8);
   8353         xcoord = (linePixel > 7) ? 0 : (8 - linePixel);
   8354         for (currentPixel = this.pixelStart + ((linePixel > 8) ? (linePixel - 8) : 0); xcoord < xCoordEnd; ++xcoord, ++currentPixel, ++linePixel) {
   8355           if (this.sortBuffer[linePixel] > xCoordStart) {
   8356             if (this.frameBuffer[currentPixel] >= 0x2000000) {
   8357               data = tile[yoffset | xcoord];
   8358               if (data > 0) {
   8359                 this.frameBuffer[currentPixel] = this.OBJPalette[palette | data];
   8360                 this.sortBuffer[linePixel] = xCoordStart;
   8361               }
   8362             }
   8363             else if (this.frameBuffer[currentPixel] < 0x1000000) {
   8364               data = tile[yoffset | xcoord];
   8365               if (data > 0 && attrCode < 0x80) {
   8366                 this.frameBuffer[currentPixel] = this.OBJPalette[palette | data];
   8367                 this.sortBuffer[linePixel] = xCoordStart;
   8368               }
   8369             }
   8370           }
   8371         }
   8372       }
   8373     }
   8374     else {
   8375       //Draw the visible sprites:
   8376       for (var length = this.findLowestSpriteDrawable(lineAdjusted, 0xF); spriteCount < length; ++spriteCount) {
   8377         OAMAddress = this.OAMAddressCache[spriteCount];
   8378         yoffset = (lineAdjusted - this.memory[OAMAddress]) << 3;
   8379         attrCode = this.memory[OAMAddress | 3];
   8380         palette = (attrCode & 0x10) >> 2;
   8381         if ((attrCode & 0x40) == (0x40 & yoffset)) {
   8382           tile = this.tileCache[((attrCode & 0x60) << 4) | (this.memory[OAMAddress | 0x2] & 0xFE)];
   8383         }
   8384         else {
   8385           tile = this.tileCache[((attrCode & 0x60) << 4) | this.memory[OAMAddress | 0x2] | 1];
   8386         }
   8387         yoffset &= 0x3F;
   8388         linePixel = xCoordStart = this.memory[OAMAddress | 1];
   8389         xCoordEnd = Math.min(168 - linePixel, 8);
   8390         xcoord = (linePixel > 7) ? 0 : (8 - linePixel);
   8391         for (currentPixel = this.pixelStart + ((linePixel > 8) ? (linePixel - 8) : 0); xcoord < xCoordEnd; ++xcoord, ++currentPixel, ++linePixel) {
   8392           if (this.sortBuffer[linePixel] > xCoordStart) {
   8393             if (this.frameBuffer[currentPixel] >= 0x2000000) {
   8394               data = tile[yoffset | xcoord];
   8395               if (data > 0) {
   8396                 this.frameBuffer[currentPixel] = this.OBJPalette[palette | data];
   8397                 this.sortBuffer[linePixel] = xCoordStart;
   8398               }
   8399             }
   8400             else if (this.frameBuffer[currentPixel] < 0x1000000) {
   8401               data = tile[yoffset | xcoord];
   8402               if (data > 0 && attrCode < 0x80) {
   8403                 this.frameBuffer[currentPixel] = this.OBJPalette[palette | data];
   8404                 this.sortBuffer[linePixel] = xCoordStart;
   8405               }
   8406             }
   8407           }
   8408         }
   8409       }
   8410     }
   8411   }
   8412 }
   8413 GameBoyCore.prototype.findLowestSpriteDrawable = function (scanlineToRender, drawableRange) {
   8414   var address = 0xFE00;
   8415   var spriteCount = 0;
   8416   var diff = 0;
   8417   while (address < 0xFEA0 && spriteCount < 10) {
   8418     diff = scanlineToRender - this.memory[address];
   8419     if ((diff & drawableRange) == diff) {
   8420       this.OAMAddressCache[spriteCount++] = address;
   8421     }
   8422     address += 4;
   8423   }
   8424   return spriteCount;
   8425 }
   8426 GameBoyCore.prototype.SpriteGBCLayerRender = function (scanlineToRender) {
   8427   if (this.gfxSpriteShow) {                    //Are sprites enabled?
   8428     var OAMAddress = 0xFE00;
   8429     var lineAdjusted = scanlineToRender + 0x10;
   8430     var yoffset = 0;
   8431     var xcoord = 0;
   8432     var endX = 0;
   8433     var xCounter = 0;
   8434     var attrCode = 0;
   8435     var palette = 0;
   8436     var tile = null;
   8437     var data = 0;
   8438     var currentPixel = 0;
   8439     var spriteCount = 0;
   8440     if (this.gfxSpriteNormalHeight) {
   8441       for (; OAMAddress < 0xFEA0 && spriteCount < 10; OAMAddress += 4) {
   8442         yoffset = lineAdjusted - this.memory[OAMAddress];
   8443         if ((yoffset & 0x7) == yoffset) {
   8444           xcoord = this.memory[OAMAddress | 1] - 8;
   8445           endX = Math.min(160, xcoord + 8);
   8446           attrCode = this.memory[OAMAddress | 3];
   8447           palette = (attrCode & 7) << 2;
   8448           tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | this.memory[OAMAddress | 2]];
   8449           xCounter = (xcoord > 0) ? xcoord : 0;
   8450           xcoord -= yoffset << 3;
   8451           for (currentPixel = this.pixelStart + xCounter; xCounter < endX; ++xCounter, ++currentPixel) {
   8452             if (this.frameBuffer[currentPixel] >= 0x2000000) {
   8453               data = tile[xCounter - xcoord];
   8454               if (data > 0) {
   8455                 this.frameBuffer[currentPixel] = this.gbcOBJPalette[palette | data];
   8456               }
   8457             }
   8458             else if (this.frameBuffer[currentPixel] < 0x1000000) {
   8459               data = tile[xCounter - xcoord];
   8460               if (data > 0 && attrCode < 0x80) {    //Don't optimize for attrCode, as LICM-capable JITs should optimize its checks.
   8461                 this.frameBuffer[currentPixel] = this.gbcOBJPalette[palette | data];
   8462               }
   8463             }
   8464           }
   8465           ++spriteCount;
   8466         }
   8467       }
   8468     }
   8469     else {
   8470       for (; OAMAddress < 0xFEA0 && spriteCount < 10; OAMAddress += 4) {
   8471         yoffset = lineAdjusted - this.memory[OAMAddress];
   8472         if ((yoffset & 0xF) == yoffset) {
   8473           xcoord = this.memory[OAMAddress | 1] - 8;
   8474           endX = Math.min(160, xcoord + 8);
   8475           attrCode = this.memory[OAMAddress | 3];
   8476           palette = (attrCode & 7) << 2;
   8477           if ((attrCode & 0x40) == (0x40 & (yoffset << 3))) {
   8478             tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | (this.memory[OAMAddress | 0x2] & 0xFE)];
   8479           }
   8480           else {
   8481             tile = this.tileCache[((attrCode & 0x08) << 8) | ((attrCode & 0x60) << 4) | this.memory[OAMAddress | 0x2] | 1];
   8482           }
   8483           xCounter = (xcoord > 0) ? xcoord : 0;
   8484           xcoord -= (yoffset & 0x7) << 3;
   8485           for (currentPixel = this.pixelStart + xCounter; xCounter < endX; ++xCounter, ++currentPixel) {
   8486             if (this.frameBuffer[currentPixel] >= 0x2000000) {
   8487               data = tile[xCounter - xcoord];
   8488               if (data > 0) {
   8489                 this.frameBuffer[currentPixel] = this.gbcOBJPalette[palette | data];
   8490               }
   8491             }
   8492             else if (this.frameBuffer[currentPixel] < 0x1000000) {
   8493               data = tile[xCounter - xcoord];
   8494               if (data > 0 && attrCode < 0x80) {    //Don't optimize for attrCode, as LICM-capable JITs should optimize its checks.
   8495                 this.frameBuffer[currentPixel] = this.gbcOBJPalette[palette | data];
   8496               }
   8497             }
   8498           }
   8499           ++spriteCount;
   8500         }
   8501       }
   8502     }
   8503   }
   8504 }
   8505 //Generate only a single tile line for the GB tile cache mode:
   8506 GameBoyCore.prototype.generateGBTileLine = function (address) {
   8507   var lineCopy = (this.memory[0x1 | address] << 8) | this.memory[0x9FFE & address];
   8508   var tileBlock = this.tileCache[(address & 0x1FF0) >> 4];
   8509   address = (address & 0xE) << 2;
   8510   tileBlock[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
   8511   tileBlock[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
   8512   tileBlock[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
   8513   tileBlock[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
   8514   tileBlock[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
   8515   tileBlock[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
   8516   tileBlock[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
   8517   tileBlock[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
   8518 }
   8519 //Generate only a single tile line for the GBC tile cache mode (Bank 1):
   8520 GameBoyCore.prototype.generateGBCTileLineBank1 = function (address) {
   8521   var lineCopy = (this.memory[0x1 | address] << 8) | this.memory[0x9FFE & address];
   8522   address &= 0x1FFE;
   8523   var tileBlock1 = this.tileCache[address >> 4];
   8524   var tileBlock2 = this.tileCache[0x200 | (address >> 4)];
   8525   var tileBlock3 = this.tileCache[0x400 | (address >> 4)];
   8526   var tileBlock4 = this.tileCache[0x600 | (address >> 4)];
   8527   address = (address & 0xE) << 2;
   8528   var addressFlipped = 0x38 - address;
   8529   tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
   8530   tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
   8531   tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
   8532   tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
   8533   tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
   8534   tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
   8535   tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
   8536   tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
   8537 }
   8538 //Generate all the flip combinations for a full GBC VRAM bank 1 tile:
   8539 GameBoyCore.prototype.generateGBCTileBank1 = function (vramAddress) {
   8540   var address = vramAddress >> 4;
   8541   var tileBlock1 = this.tileCache[address];
   8542   var tileBlock2 = this.tileCache[0x200 | address];
   8543   var tileBlock3 = this.tileCache[0x400 | address];
   8544   var tileBlock4 = this.tileCache[0x600 | address];
   8545   var lineCopy = 0;
   8546   vramAddress |= 0x8000;
   8547   address = 0;
   8548   var addressFlipped = 56;
   8549   do {
   8550     lineCopy = (this.memory[0x1 | vramAddress] << 8) | this.memory[vramAddress];
   8551     tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
   8552     tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
   8553     tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
   8554     tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
   8555     tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
   8556     tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
   8557     tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
   8558     tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
   8559     address += 8;
   8560     addressFlipped -= 8;
   8561     vramAddress += 2;
   8562   } while (addressFlipped > -1);
   8563 }
   8564 //Generate only a single tile line for the GBC tile cache mode (Bank 2):
   8565 GameBoyCore.prototype.generateGBCTileLineBank2 = function (address) {
   8566   var lineCopy = (this.VRAM[0x1 | address] << 8) | this.VRAM[0x1FFE & address];
   8567   var tileBlock1 = this.tileCache[0x800 | (address >> 4)];
   8568   var tileBlock2 = this.tileCache[0xA00 | (address >> 4)];
   8569   var tileBlock3 = this.tileCache[0xC00 | (address >> 4)];
   8570   var tileBlock4 = this.tileCache[0xE00 | (address >> 4)];
   8571   address = (address & 0xE) << 2;
   8572   var addressFlipped = 0x38 - address;
   8573   tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
   8574   tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
   8575   tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
   8576   tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
   8577   tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
   8578   tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
   8579   tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
   8580   tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
   8581 }
   8582 //Generate all the flip combinations for a full GBC VRAM bank 2 tile:
   8583 GameBoyCore.prototype.generateGBCTileBank2 = function (vramAddress) {
   8584   var address = vramAddress >> 4;
   8585   var tileBlock1 = this.tileCache[0x800 | address];
   8586   var tileBlock2 = this.tileCache[0xA00 | address];
   8587   var tileBlock3 = this.tileCache[0xC00 | address];
   8588   var tileBlock4 = this.tileCache[0xE00 | address];
   8589   var lineCopy = 0;
   8590   address = 0;
   8591   var addressFlipped = 56;
   8592   do {
   8593     lineCopy = (this.VRAM[0x1 | vramAddress] << 8) | this.VRAM[vramAddress];
   8594     tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
   8595     tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
   8596     tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
   8597     tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
   8598     tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
   8599     tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
   8600     tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
   8601     tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
   8602     address += 8;
   8603     addressFlipped -= 8;
   8604     vramAddress += 2;
   8605   } while (addressFlipped > -1);
   8606 }
   8607 //Generate only a single tile line for the GB tile cache mode (OAM accessible range):
   8608 GameBoyCore.prototype.generateGBOAMTileLine = function (address) {
   8609   var lineCopy = (this.memory[0x1 | address] << 8) | this.memory[0x9FFE & address];
   8610   address &= 0x1FFE;
   8611   var tileBlock1 = this.tileCache[address >> 4];
   8612   var tileBlock2 = this.tileCache[0x200 | (address >> 4)];
   8613   var tileBlock3 = this.tileCache[0x400 | (address >> 4)];
   8614   var tileBlock4 = this.tileCache[0x600 | (address >> 4)];
   8615   address = (address & 0xE) << 2;
   8616   var addressFlipped = 0x38 - address;
   8617   tileBlock4[addressFlipped] = tileBlock2[address] = tileBlock3[addressFlipped | 7] = tileBlock1[address | 7] = ((lineCopy & 0x100) >> 7) | (lineCopy & 0x1);
   8618   tileBlock4[addressFlipped | 1] = tileBlock2[address | 1] = tileBlock3[addressFlipped | 6] = tileBlock1[address | 6] = ((lineCopy & 0x200) >> 8) | ((lineCopy & 0x2) >> 1);
   8619   tileBlock4[addressFlipped | 2] = tileBlock2[address | 2] = tileBlock3[addressFlipped | 5] = tileBlock1[address | 5] = ((lineCopy & 0x400) >> 9) | ((lineCopy & 0x4) >> 2);
   8620   tileBlock4[addressFlipped | 3] = tileBlock2[address | 3] = tileBlock3[addressFlipped | 4] = tileBlock1[address | 4] = ((lineCopy & 0x800) >> 10) | ((lineCopy & 0x8) >> 3);
   8621   tileBlock4[addressFlipped | 4] = tileBlock2[address | 4] = tileBlock3[addressFlipped | 3] = tileBlock1[address | 3] = ((lineCopy & 0x1000) >> 11) | ((lineCopy & 0x10) >> 4);
   8622   tileBlock4[addressFlipped | 5] = tileBlock2[address | 5] = tileBlock3[addressFlipped | 2] = tileBlock1[address | 2] = ((lineCopy & 0x2000) >> 12) | ((lineCopy & 0x20) >> 5);
   8623   tileBlock4[addressFlipped | 6] = tileBlock2[address | 6] = tileBlock3[addressFlipped | 1] = tileBlock1[address | 1] = ((lineCopy & 0x4000) >> 13) | ((lineCopy & 0x40) >> 6);
   8624   tileBlock4[addressFlipped | 7] = tileBlock2[address | 7] = tileBlock3[addressFlipped] = tileBlock1[address] = ((lineCopy & 0x8000) >> 14) | ((lineCopy & 0x80) >> 7);
   8625 }
   8626 GameBoyCore.prototype.graphicsJIT = function () {
   8627   if (this.LCDisOn) {
   8628     this.totalLinesPassed = 0;      //Mark frame for ensuring a JIT pass for the next framebuffer output.
   8629     this.graphicsJITScanlineGroup();
   8630   }
   8631 }
   8632 GameBoyCore.prototype.graphicsJITVBlank = function () {
   8633   //JIT the graphics to v-blank framing:
   8634   this.totalLinesPassed += this.queuedScanLines;
   8635   this.graphicsJITScanlineGroup();
   8636 }
   8637 GameBoyCore.prototype.graphicsJITScanlineGroup = function () {
   8638   //Normal rendering JIT, where we try to do groups of scanlines at once:
   8639   while (this.queuedScanLines > 0) {
   8640     this.renderScanLine(this.lastUnrenderedLine);
   8641     if (this.lastUnrenderedLine < 143) {
   8642       ++this.lastUnrenderedLine;
   8643     }
   8644     else {
   8645       this.lastUnrenderedLine = 0;
   8646     }
   8647     --this.queuedScanLines;
   8648   }
   8649 }
   8650 GameBoyCore.prototype.incrementScanLineQueue = function () {
   8651   if (this.queuedScanLines < 144) {
   8652     ++this.queuedScanLines;
   8653   }
   8654   else {
   8655     this.currentX = 0;
   8656     this.midScanlineOffset = -1;
   8657     if (this.lastUnrenderedLine < 143) {
   8658       ++this.lastUnrenderedLine;
   8659     }
   8660     else {
   8661       this.lastUnrenderedLine = 0;
   8662     }
   8663   }
   8664 }
   8665 GameBoyCore.prototype.midScanLineJIT = function () {
   8666   this.graphicsJIT();
   8667   this.renderMidScanLine();
   8668 }
   8669 //Check for the highest priority IRQ to fire:
   8670 GameBoyCore.prototype.launchIRQ = function () {
   8671   var bitShift = 0;
   8672   var testbit = 1;
   8673   do {
   8674     //Check to see if an interrupt is enabled AND requested.
   8675     if ((testbit & this.IRQLineMatched) == testbit) {
   8676       this.IME = false;            //Reset the interrupt enabling.
   8677       this.interruptsRequested -= testbit;  //Reset the interrupt request.
   8678       this.IRQLineMatched = 0;        //Reset the IRQ assertion.
   8679       //Interrupts have a certain clock cycle length:
   8680       this.CPUTicks = 20;
   8681       //Set the stack pointer to the current program counter value:
   8682       this.stackPointer = (this.stackPointer - 1) & 0xFFFF;
   8683       this.memoryWriter[this.stackPointer](this, this.stackPointer, this.programCounter >> 8);
   8684       this.stackPointer = (this.stackPointer - 1) & 0xFFFF;
   8685       this.memoryWriter[this.stackPointer](this, this.stackPointer, this.programCounter & 0xFF);
   8686       //Set the program counter to the interrupt's address:
   8687       this.programCounter = 0x40 | (bitShift << 3);
   8688       //Clock the core for mid-instruction updates:
   8689       this.updateCore();
   8690       return;                  //We only want the highest priority interrupt.
   8691     }
   8692     testbit = 1 << ++bitShift;
   8693   } while (bitShift < 5);
   8694 }
   8695 /*
   8696   Check for IRQs to be fired while not in HALT:
   8697 */
   8698 GameBoyCore.prototype.checkIRQMatching = function () {
   8699   if (this.IME) {
   8700     this.IRQLineMatched = this.interruptsEnabled & this.interruptsRequested & 0x1F;
   8701   }
   8702 }
   8703 /*
   8704   Handle the HALT opcode by predicting all IRQ cases correctly,
   8705   then selecting the next closest IRQ firing from the prediction to
   8706   clock up to. This prevents hacky looping that doesn't predict, but
   8707   instead just clocks through the core update procedure by one which
   8708   is very slow. Not many emulators do this because they have to cover
   8709   all the IRQ prediction cases and they usually get them wrong.
   8710 */
   8711 GameBoyCore.prototype.calculateHALTPeriod = function () {
   8712   //Initialize our variables and start our prediction:
   8713   if (!this.halt) {
   8714     this.halt = true;
   8715     var currentClocks = -1;
   8716     var temp_var = 0;
   8717     if (this.LCDisOn) {
   8718       //If the LCD is enabled, then predict the LCD IRQs enabled:
   8719       if ((this.interruptsEnabled & 0x1) == 0x1) {
   8720         currentClocks = ((456 * (((this.modeSTAT == 1) ? 298 : 144) - this.actualScanLine)) - this.LCDTicks) << this.doubleSpeedShifter;
   8721       }
   8722       if ((this.interruptsEnabled & 0x2) == 0x2) {
   8723         if (this.mode0TriggerSTAT) {
   8724           temp_var = (this.clocksUntilMode0() - this.LCDTicks) << this.doubleSpeedShifter;
   8725           if (temp_var <= currentClocks || currentClocks == -1) {
   8726             currentClocks = temp_var;
   8727           }
   8728         }
   8729         if (this.mode1TriggerSTAT && (this.interruptsEnabled & 0x1) == 0) {
   8730           temp_var = ((456 * (((this.modeSTAT == 1) ? 298 : 144) - this.actualScanLine)) - this.LCDTicks) << this.doubleSpeedShifter;
   8731           if (temp_var <= currentClocks || currentClocks == -1) {
   8732             currentClocks = temp_var;
   8733           }
   8734         }
   8735         if (this.mode2TriggerSTAT) {
   8736           temp_var = (((this.actualScanLine >= 143) ? (456 * (154 - this.actualScanLine)) : 456) - this.LCDTicks) << this.doubleSpeedShifter;
   8737           if (temp_var <= currentClocks || currentClocks == -1) {
   8738             currentClocks = temp_var;
   8739           }
   8740         }
   8741         if (this.LYCMatchTriggerSTAT && this.memory[0xFF45] <= 153) {
   8742           temp_var = (this.clocksUntilLYCMatch() - this.LCDTicks) << this.doubleSpeedShifter;
   8743           if (temp_var <= currentClocks || currentClocks == -1) {
   8744             currentClocks = temp_var;
   8745           }
   8746         }
   8747       }
   8748     }
   8749     if (this.TIMAEnabled && (this.interruptsEnabled & 0x4) == 0x4) {
   8750       //CPU timer IRQ prediction:
   8751       temp_var = ((0x100 - this.memory[0xFF05]) * this.TACClocker) - this.timerTicks;
   8752       if (temp_var <= currentClocks || currentClocks == -1) {
   8753         currentClocks = temp_var;
   8754       }
   8755     }
   8756     if (this.serialTimer > 0 && (this.interruptsEnabled & 0x8) == 0x8) {
   8757       //Serial IRQ prediction:
   8758       if (this.serialTimer <= currentClocks || currentClocks == -1) {
   8759         currentClocks = this.serialTimer;
   8760       }
   8761     }
   8762   }
   8763   else {
   8764     var currentClocks = this.remainingClocks;
   8765   }
   8766   var maxClocks = (this.CPUCyclesTotal - this.emulatorTicks) << this.doubleSpeedShifter;
   8767   if (currentClocks >= 0) {
   8768     if (currentClocks <= maxClocks) {
   8769       //Exit out of HALT normally:
   8770       this.CPUTicks = Math.max(currentClocks, this.CPUTicks);
   8771       this.updateCoreFull();
   8772       this.halt = false;
   8773       this.CPUTicks = 0;
   8774     }
   8775     else {
   8776       //Still in HALT, clock only up to the clocks specified per iteration:
   8777       this.CPUTicks = Math.max(maxClocks, this.CPUTicks);
   8778       this.remainingClocks = currentClocks - this.CPUTicks;
   8779     }
   8780   }
   8781   else {
   8782     //Still in HALT, clock only up to the clocks specified per iteration:
   8783     //Will stay in HALT forever (Stuck in HALT forever), but the APU and LCD are still clocked, so don't pause:
   8784     this.CPUTicks += maxClocks;
   8785   }
   8786 }
   8787 //Memory Reading:
   8788 GameBoyCore.prototype.memoryRead = function (address) {
   8789   //Act as a wrapper for reading the returns from the compiled jumps to memory.
   8790   return this.memoryReader[address](this, address);  //This seems to be faster than the usual if/else.
   8791 }
   8792 GameBoyCore.prototype.memoryHighRead = function (address) {
   8793   //Act as a wrapper for reading the returns from the compiled jumps to memory.
   8794   return this.memoryHighReader[address](this, address);  //This seems to be faster than the usual if/else.
   8795 }
   8796 GameBoyCore.prototype.memoryReadJumpCompile = function () {
   8797   //Faster in some browsers, since we are doing less conditionals overall by implementing them in advance.
   8798   for (var index = 0x0000; index <= 0xFFFF; index++) {
   8799     if (index < 0x4000) {
   8800       this.memoryReader[index] = this.memoryReadNormal;
   8801     }
   8802     else if (index < 0x8000) {
   8803       this.memoryReader[index] = this.memoryReadROM;
   8804     }
   8805     else if (index < 0x9800) {
   8806       this.memoryReader[index] = (this.cGBC) ? this.VRAMDATAReadCGBCPU : this.VRAMDATAReadDMGCPU;
   8807     }
   8808     else if (index < 0xA000) {
   8809       this.memoryReader[index] = (this.cGBC) ? this.VRAMCHRReadCGBCPU : this.VRAMCHRReadDMGCPU;
   8810     }
   8811     else if (index >= 0xA000 && index < 0xC000) {
   8812       if ((this.numRAMBanks == 1 / 16 && index < 0xA200) || this.numRAMBanks >= 1) {
   8813         if (this.cMBC7) {
   8814           this.memoryReader[index] = this.memoryReadMBC7;
   8815         }
   8816         else if (!this.cMBC3) {
   8817           this.memoryReader[index] = this.memoryReadMBC;
   8818         }
   8819         else {
   8820           //MBC3 RTC + RAM:
   8821           this.memoryReader[index] = this.memoryReadMBC3;
   8822         }
   8823       }
   8824       else {
   8825         this.memoryReader[index] = this.memoryReadBAD;
   8826       }
   8827     }
   8828     else if (index >= 0xC000 && index < 0xE000) {
   8829       if (!this.cGBC || index < 0xD000) {
   8830         this.memoryReader[index] = this.memoryReadNormal;
   8831       }
   8832       else {
   8833         this.memoryReader[index] = this.memoryReadGBCMemory;
   8834       }
   8835     }
   8836     else if (index >= 0xE000 && index < 0xFE00) {
   8837       if (!this.cGBC || index < 0xF000) {
   8838         this.memoryReader[index] = this.memoryReadECHONormal;
   8839       }
   8840       else {
   8841         this.memoryReader[index] = this.memoryReadECHOGBCMemory;
   8842       }
   8843     }
   8844     else if (index < 0xFEA0) {
   8845       this.memoryReader[index] = this.memoryReadOAM;
   8846     }
   8847     else if (this.cGBC && index >= 0xFEA0 && index < 0xFF00) {
   8848       this.memoryReader[index] = this.memoryReadNormal;
   8849     }
   8850     else if (index >= 0xFF00) {
   8851       switch (index) {
   8852         case 0xFF00:
   8853           //JOYPAD:
   8854           this.memoryHighReader[0] = this.memoryReader[0xFF00] = function (parentObj, address) {
   8855             return 0xC0 | parentObj.memory[0xFF00];  //Top nibble returns as set.
   8856           }
   8857           break;
   8858         case 0xFF01:
   8859           //SB
   8860           this.memoryHighReader[0x01] = this.memoryReader[0xFF01] = function (parentObj, address) {
   8861             return (parentObj.memory[0xFF02] < 0x80) ? parentObj.memory[0xFF01] : 0xFF;
   8862           }
   8863           break;
   8864         case 0xFF02:
   8865           //SC
   8866           if (this.cGBC) {
   8867             this.memoryHighReader[0x02] = this.memoryReader[0xFF02] = function (parentObj, address) {
   8868               return ((parentObj.serialTimer <= 0) ? 0x7C : 0xFC) | parentObj.memory[0xFF02];
   8869             }
   8870           }
   8871           else {
   8872             this.memoryHighReader[0x02] = this.memoryReader[0xFF02] = function (parentObj, address) {
   8873               return ((parentObj.serialTimer <= 0) ? 0x7E : 0xFE) | parentObj.memory[0xFF02];
   8874             }
   8875           }
   8876           break;
   8877         case 0xFF04:
   8878           //DIV
   8879           this.memoryHighReader[0x04] = this.memoryReader[0xFF04] = function (parentObj, address) {
   8880             parentObj.memory[0xFF04] = (parentObj.memory[0xFF04] + (parentObj.DIVTicks >> 8)) & 0xFF;
   8881             parentObj.DIVTicks &= 0xFF;
   8882             return parentObj.memory[0xFF04];
   8883 
   8884           }
   8885           break;
   8886         case 0xFF07:
   8887           this.memoryHighReader[0x07] = this.memoryReader[0xFF07] = function (parentObj, address) {
   8888             return 0xF8 | parentObj.memory[0xFF07];
   8889           }
   8890           break;
   8891         case 0xFF0F:
   8892           //IF
   8893           this.memoryHighReader[0x0F] = this.memoryReader[0xFF0F] = function (parentObj, address) {
   8894             return 0xE0 | parentObj.interruptsRequested;
   8895           }
   8896           break;
   8897         case 0xFF10:
   8898           this.memoryHighReader[0x10] = this.memoryReader[0xFF10] = function (parentObj, address) {
   8899             return 0x80 | parentObj.memory[0xFF10];
   8900           }
   8901           break;
   8902         case 0xFF11:
   8903           this.memoryHighReader[0x11] = this.memoryReader[0xFF11] = function (parentObj, address) {
   8904             return 0x3F | parentObj.memory[0xFF11];
   8905           }
   8906           break;
   8907         case 0xFF13:
   8908           this.memoryHighReader[0x13] = this.memoryReader[0xFF13] = this.memoryReadBAD;
   8909           break;
   8910         case 0xFF14:
   8911           this.memoryHighReader[0x14] = this.memoryReader[0xFF14] = function (parentObj, address) {
   8912             return 0xBF | parentObj.memory[0xFF14];
   8913           }
   8914           break;
   8915         case 0xFF16:
   8916           this.memoryHighReader[0x16] = this.memoryReader[0xFF16] = function (parentObj, address) {
   8917             return 0x3F | parentObj.memory[0xFF16];
   8918           }
   8919           break;
   8920         case 0xFF18:
   8921           this.memoryHighReader[0x18] = this.memoryReader[0xFF18] = this.memoryReadBAD;
   8922           break;
   8923         case 0xFF19:
   8924           this.memoryHighReader[0x19] = this.memoryReader[0xFF19] = function (parentObj, address) {
   8925             return 0xBF | parentObj.memory[0xFF19];
   8926           }
   8927           break;
   8928         case 0xFF1A:
   8929           this.memoryHighReader[0x1A] = this.memoryReader[0xFF1A] = function (parentObj, address) {
   8930             return 0x7F | parentObj.memory[0xFF1A];
   8931           }
   8932           break;
   8933         case 0xFF1B:
   8934           this.memoryHighReader[0x1B] = this.memoryReader[0xFF1B] = this.memoryReadBAD;
   8935           break;
   8936         case 0xFF1C:
   8937           this.memoryHighReader[0x1C] = this.memoryReader[0xFF1C] = function (parentObj, address) {
   8938             return 0x9F | parentObj.memory[0xFF1C];
   8939           }
   8940           break;
   8941         case 0xFF1D:
   8942           this.memoryHighReader[0x1D] = this.memoryReader[0xFF1D] = function (parentObj, address) {
   8943             return 0xFF;
   8944           }
   8945           break;
   8946         case 0xFF1E:
   8947           this.memoryHighReader[0x1E] = this.memoryReader[0xFF1E] = function (parentObj, address) {
   8948             return 0xBF | parentObj.memory[0xFF1E];
   8949           }
   8950           break;
   8951         case 0xFF1F:
   8952         case 0xFF20:
   8953           this.memoryHighReader[index & 0xFF] = this.memoryReader[index] = this.memoryReadBAD;
   8954           break;
   8955         case 0xFF23:
   8956           this.memoryHighReader[0x23] = this.memoryReader[0xFF23] = function (parentObj, address) {
   8957             return 0xBF | parentObj.memory[0xFF23];
   8958           }
   8959           break;
   8960         case 0xFF26:
   8961           this.memoryHighReader[0x26] = this.memoryReader[0xFF26] = function (parentObj, address) {
   8962             parentObj.audioJIT();
   8963             return 0x70 | parentObj.memory[0xFF26];
   8964           }
   8965           break;
   8966         case 0xFF27:
   8967         case 0xFF28:
   8968         case 0xFF29:
   8969         case 0xFF2A:
   8970         case 0xFF2B:
   8971         case 0xFF2C:
   8972         case 0xFF2D:
   8973         case 0xFF2E:
   8974         case 0xFF2F:
   8975           this.memoryHighReader[index & 0xFF] = this.memoryReader[index] = this.memoryReadBAD;
   8976           break;
   8977         case 0xFF30:
   8978         case 0xFF31:
   8979         case 0xFF32:
   8980         case 0xFF33:
   8981         case 0xFF34:
   8982         case 0xFF35:
   8983         case 0xFF36:
   8984         case 0xFF37:
   8985         case 0xFF38:
   8986         case 0xFF39:
   8987         case 0xFF3A:
   8988         case 0xFF3B:
   8989         case 0xFF3C:
   8990         case 0xFF3D:
   8991         case 0xFF3E:
   8992         case 0xFF3F:
   8993           this.memoryReader[index] = function (parentObj, address) {
   8994             return (parentObj.channel3canPlay) ? parentObj.memory[0xFF00 | (parentObj.channel3lastSampleLookup >> 1)] : parentObj.memory[address];
   8995           }
   8996           this.memoryHighReader[index & 0xFF] = function (parentObj, address) {
   8997             return (parentObj.channel3canPlay) ? parentObj.memory[0xFF00 | (parentObj.channel3lastSampleLookup >> 1)] : parentObj.memory[0xFF00 | address];
   8998           }
   8999           break;
   9000         case 0xFF41:
   9001           this.memoryHighReader[0x41] = this.memoryReader[0xFF41] = function (parentObj, address) {
   9002             return 0x80 | parentObj.memory[0xFF41] | parentObj.modeSTAT;
   9003           }
   9004           break;
   9005         case 0xFF42:
   9006           this.memoryHighReader[0x42] = this.memoryReader[0xFF42] = function (parentObj, address) {
   9007             return parentObj.backgroundY;
   9008           }
   9009           break;
   9010         case 0xFF43:
   9011           this.memoryHighReader[0x43] = this.memoryReader[0xFF43] = function (parentObj, address) {
   9012             return parentObj.backgroundX;
   9013           }
   9014           break;
   9015         case 0xFF44:
   9016           this.memoryHighReader[0x44] = this.memoryReader[0xFF44] = function (parentObj, address) {
   9017             return ((parentObj.LCDisOn) ? parentObj.memory[0xFF44] : 0);
   9018           }
   9019           break;
   9020         case 0xFF4A:
   9021           //WY
   9022           this.memoryHighReader[0x4A] = this.memoryReader[0xFF4A] = function (parentObj, address) {
   9023             return parentObj.windowY;
   9024           }
   9025           break;
   9026         case 0xFF4F:
   9027           this.memoryHighReader[0x4F] = this.memoryReader[0xFF4F] = function (parentObj, address) {
   9028             return parentObj.currVRAMBank;
   9029           }
   9030           break;
   9031         case 0xFF55:
   9032           if (this.cGBC) {
   9033             this.memoryHighReader[0x55] = this.memoryReader[0xFF55] = function (parentObj, address) {
   9034               if (!parentObj.LCDisOn && parentObj.hdmaRunning) {  //Undocumented behavior alert: HDMA becomes GDMA when LCD is off (Worms Armageddon Fix).
   9035                 //DMA
   9036                 parentObj.DMAWrite((parentObj.memory[0xFF55] & 0x7F) + 1);
   9037                 parentObj.memory[0xFF55] = 0xFF;  //Transfer completed.
   9038                 parentObj.hdmaRunning = false;
   9039               }
   9040               return parentObj.memory[0xFF55];
   9041             }
   9042           }
   9043           else {
   9044             this.memoryReader[0xFF55] = this.memoryReadNormal;
   9045             this.memoryHighReader[0x55] = this.memoryHighReadNormal;
   9046           }
   9047           break;
   9048         case 0xFF56:
   9049           if (this.cGBC) {
   9050             this.memoryHighReader[0x56] = this.memoryReader[0xFF56] = function (parentObj, address) {
   9051               //Return IR "not connected" status:
   9052               return 0x3C | ((parentObj.memory[0xFF56] >= 0xC0) ? (0x2 | (parentObj.memory[0xFF56] & 0xC1)) : (parentObj.memory[0xFF56] & 0xC3));
   9053             }
   9054           }
   9055           else {
   9056             this.memoryReader[0xFF56] = this.memoryReadNormal;
   9057             this.memoryHighReader[0x56] = this.memoryHighReadNormal;
   9058           }
   9059           break;
   9060         case 0xFF6C:
   9061           if (this.cGBC) {
   9062             this.memoryHighReader[0x6C] = this.memoryReader[0xFF6C] = function (parentObj, address) {
   9063               return 0xFE | parentObj.memory[0xFF6C];
   9064             }
   9065           }
   9066           else {
   9067             this.memoryHighReader[0x6C] = this.memoryReader[0xFF6C] = this.memoryReadBAD;
   9068           }
   9069           break;
   9070         case 0xFF70:
   9071           if (this.cGBC) {
   9072             //SVBK
   9073             this.memoryHighReader[0x70] = this.memoryReader[0xFF70] = function (parentObj, address) {
   9074               return 0x40 | parentObj.memory[0xFF70];
   9075             }
   9076           }
   9077           else {
   9078             this.memoryHighReader[0x70] = this.memoryReader[0xFF70] = this.memoryReadBAD;
   9079           }
   9080           break;
   9081         case 0xFF75:
   9082           this.memoryHighReader[0x75] = this.memoryReader[0xFF75] = function (parentObj, address) {
   9083             return 0x8F | parentObj.memory[0xFF75];
   9084           }
   9085           break;
   9086         case 0xFF76:
   9087         case 0xFF77:
   9088           this.memoryHighReader[index & 0xFF] = this.memoryReader[index] = function (parentObj, address) {
   9089             return 0;
   9090           }
   9091           break;
   9092         case 0xFFFF:
   9093           //IE
   9094           this.memoryHighReader[0xFF] = this.memoryReader[0xFFFF] = function (parentObj, address) {
   9095             return parentObj.interruptsEnabled;
   9096           }
   9097           break;
   9098         default:
   9099           this.memoryReader[index] = this.memoryReadNormal;
   9100           this.memoryHighReader[index & 0xFF] = this.memoryHighReadNormal;
   9101       }
   9102     }
   9103     else {
   9104       this.memoryReader[index] = this.memoryReadBAD;
   9105     }
   9106   }
   9107 }
   9108 GameBoyCore.prototype.memoryReadNormal = function (parentObj, address) {
   9109   return parentObj.memory[address];
   9110 }
   9111 GameBoyCore.prototype.memoryHighReadNormal = function (parentObj, address) {
   9112   return parentObj.memory[0xFF00 | address];
   9113 }
   9114 GameBoyCore.prototype.memoryReadROM = function (parentObj, address) {
   9115   return parentObj.ROM[parentObj.currentROMBank + address];
   9116 }
   9117 GameBoyCore.prototype.memoryReadMBC = function (parentObj, address) {
   9118   //Switchable RAM
   9119   if (parentObj.MBCRAMBanksEnabled || settings[10]) {
   9120     return parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition];
   9121   }
   9122   //cout("Reading from disabled RAM.", 1);
   9123   return 0xFF;
   9124 }
   9125 GameBoyCore.prototype.memoryReadMBC7 = function (parentObj, address) {
   9126   //Switchable RAM
   9127   if (parentObj.MBCRAMBanksEnabled || settings[10]) {
   9128     switch (address) {
   9129       case 0xA000:
   9130       case 0xA060:
   9131       case 0xA070:
   9132         return 0;
   9133       case 0xA080:
   9134         //TODO: Gyro Control Register
   9135         return 0;
   9136       case 0xA050:
   9137         //Y High Byte
   9138         return parentObj.highY;
   9139       case 0xA040:
   9140         //Y Low Byte
   9141         return parentObj.lowY;
   9142       case 0xA030:
   9143         //X High Byte
   9144         return parentObj.highX;
   9145       case 0xA020:
   9146         //X Low Byte:
   9147         return parentObj.lowX;
   9148       default:
   9149         return parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition];
   9150     }
   9151   }
   9152   //cout("Reading from disabled RAM.", 1);
   9153   return 0xFF;
   9154 }
   9155 GameBoyCore.prototype.memoryReadMBC3 = function (parentObj, address) {
   9156   //Switchable RAM
   9157   if (parentObj.MBCRAMBanksEnabled || settings[10]) {
   9158     switch (parentObj.currMBCRAMBank) {
   9159       case 0x00:
   9160       case 0x01:
   9161       case 0x02:
   9162       case 0x03:
   9163         return parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition];
   9164         break;
   9165       case 0x08:
   9166         return parentObj.latchedSeconds;
   9167         break;
   9168       case 0x09:
   9169         return parentObj.latchedMinutes;
   9170         break;
   9171       case 0x0A:
   9172         return parentObj.latchedHours;
   9173         break;
   9174       case 0x0B:
   9175         return parentObj.latchedLDays;
   9176         break;
   9177       case 0x0C:
   9178         return (((parentObj.RTCDayOverFlow) ? 0x80 : 0) + ((parentObj.RTCHALT) ? 0x40 : 0)) + parentObj.latchedHDays;
   9179     }
   9180   }
   9181   //cout("Reading from invalid or disabled RAM.", 1);
   9182   return 0xFF;
   9183 }
   9184 GameBoyCore.prototype.memoryReadGBCMemory = function (parentObj, address) {
   9185   return parentObj.GBCMemory[address + parentObj.gbcRamBankPosition];
   9186 }
   9187 GameBoyCore.prototype.memoryReadOAM = function (parentObj, address) {
   9188   return (parentObj.modeSTAT > 1) ?  0xFF : parentObj.memory[address];
   9189 }
   9190 GameBoyCore.prototype.memoryReadECHOGBCMemory = function (parentObj, address) {
   9191   return parentObj.GBCMemory[address + parentObj.gbcRamBankPositionECHO];
   9192 }
   9193 GameBoyCore.prototype.memoryReadECHONormal = function (parentObj, address) {
   9194   return parentObj.memory[address - 0x2000];
   9195 }
   9196 GameBoyCore.prototype.memoryReadBAD = function (parentObj, address) {
   9197   return 0xFF;
   9198 }
   9199 GameBoyCore.prototype.VRAMDATAReadCGBCPU = function (parentObj, address) {
   9200   //CPU Side Reading The VRAM (Optimized for GameBoy Color)
   9201   return (parentObj.modeSTAT > 2) ? 0xFF : ((parentObj.currVRAMBank == 0) ? parentObj.memory[address] : parentObj.VRAM[address & 0x1FFF]);
   9202 }
   9203 GameBoyCore.prototype.VRAMDATAReadDMGCPU = function (parentObj, address) {
   9204   //CPU Side Reading The VRAM (Optimized for classic GameBoy)
   9205   return (parentObj.modeSTAT > 2) ? 0xFF : parentObj.memory[address];
   9206 }
   9207 GameBoyCore.prototype.VRAMCHRReadCGBCPU = function (parentObj, address) {
   9208   //CPU Side Reading the Character Data Map:
   9209   return (parentObj.modeSTAT > 2) ? 0xFF : parentObj.BGCHRCurrentBank[address & 0x7FF];
   9210 }
   9211 GameBoyCore.prototype.VRAMCHRReadDMGCPU = function (parentObj, address) {
   9212   //CPU Side Reading the Character Data Map:
   9213   return (parentObj.modeSTAT > 2) ? 0xFF : parentObj.BGCHRBank1[address & 0x7FF];
   9214 }
   9215 GameBoyCore.prototype.setCurrentMBC1ROMBank = function () {
   9216   //Read the cartridge ROM data from RAM memory:
   9217   switch (this.ROMBank1offs) {
   9218     case 0x00:
   9219     case 0x20:
   9220     case 0x40:
   9221     case 0x60:
   9222       //Bank calls for 0x00, 0x20, 0x40, and 0x60 are really for 0x01, 0x21, 0x41, and 0x61.
   9223       this.currentROMBank = (this.ROMBank1offs % this.ROMBankEdge) << 14;
   9224       break;
   9225     default:
   9226       this.currentROMBank = ((this.ROMBank1offs % this.ROMBankEdge) - 1) << 14;
   9227   }
   9228 }
   9229 GameBoyCore.prototype.setCurrentMBC2AND3ROMBank = function () {
   9230   //Read the cartridge ROM data from RAM memory:
   9231   //Only map bank 0 to bank 1 here (MBC2 is like MBC1, but can only do 16 banks, so only the bank 0 quirk appears for MBC2):
   9232   this.currentROMBank = Math.max((this.ROMBank1offs % this.ROMBankEdge) - 1, 0) << 14;
   9233 }
   9234 GameBoyCore.prototype.setCurrentMBC5ROMBank = function () {
   9235   //Read the cartridge ROM data from RAM memory:
   9236   this.currentROMBank = ((this.ROMBank1offs % this.ROMBankEdge) - 1) << 14;
   9237 }
   9238 //Memory Writing:
   9239 GameBoyCore.prototype.memoryWrite = function (address, data) {
   9240   //Act as a wrapper for writing by compiled jumps to specific memory writing functions.
   9241   this.memoryWriter[address](this, address, data);
   9242 }
   9243 //0xFFXX fast path:
   9244 GameBoyCore.prototype.memoryHighWrite = function (address, data) {
   9245   //Act as a wrapper for writing by compiled jumps to specific memory writing functions.
   9246   this.memoryHighWriter[address](this, address, data);
   9247 }
   9248 GameBoyCore.prototype.memoryWriteJumpCompile = function () {
   9249   //Faster in some browsers, since we are doing less conditionals overall by implementing them in advance.
   9250   for (var index = 0x0000; index <= 0xFFFF; index++) {
   9251     if (index < 0x8000) {
   9252       if (this.cMBC1) {
   9253         if (index < 0x2000) {
   9254           this.memoryWriter[index] = this.MBCWriteEnable;
   9255         }
   9256         else if (index < 0x4000) {
   9257           this.memoryWriter[index] = this.MBC1WriteROMBank;
   9258         }
   9259         else if (index < 0x6000) {
   9260           this.memoryWriter[index] = this.MBC1WriteRAMBank;
   9261         }
   9262         else {
   9263           this.memoryWriter[index] = this.MBC1WriteType;
   9264         }
   9265       }
   9266       else if (this.cMBC2) {
   9267         if (index < 0x1000) {
   9268           this.memoryWriter[index] = this.MBCWriteEnable;
   9269         }
   9270         else if (index >= 0x2100 && index < 0x2200) {
   9271           this.memoryWriter[index] = this.MBC2WriteROMBank;
   9272         }
   9273         else {
   9274           this.memoryWriter[index] = this.cartIgnoreWrite;
   9275         }
   9276       }
   9277       else if (this.cMBC3) {
   9278         if (index < 0x2000) {
   9279           this.memoryWriter[index] = this.MBCWriteEnable;
   9280         }
   9281         else if (index < 0x4000) {
   9282           this.memoryWriter[index] = this.MBC3WriteROMBank;
   9283         }
   9284         else if (index < 0x6000) {
   9285           this.memoryWriter[index] = this.MBC3WriteRAMBank;
   9286         }
   9287         else {
   9288           this.memoryWriter[index] = this.MBC3WriteRTCLatch;
   9289         }
   9290       }
   9291       else if (this.cMBC5 || this.cRUMBLE || this.cMBC7) {
   9292         if (index < 0x2000) {
   9293           this.memoryWriter[index] = this.MBCWriteEnable;
   9294         }
   9295         else if (index < 0x3000) {
   9296           this.memoryWriter[index] = this.MBC5WriteROMBankLow;
   9297         }
   9298         else if (index < 0x4000) {
   9299           this.memoryWriter[index] = this.MBC5WriteROMBankHigh;
   9300         }
   9301         else if (index < 0x6000) {
   9302           this.memoryWriter[index] = (this.cRUMBLE) ? this.RUMBLEWriteRAMBank : this.MBC5WriteRAMBank;
   9303         }
   9304         else {
   9305           this.memoryWriter[index] = this.cartIgnoreWrite;
   9306         }
   9307       }
   9308       else if (this.cHuC3) {
   9309         if (index < 0x2000) {
   9310           this.memoryWriter[index] = this.MBCWriteEnable;
   9311         }
   9312         else if (index < 0x4000) {
   9313           this.memoryWriter[index] = this.MBC3WriteROMBank;
   9314         }
   9315         else if (index < 0x6000) {
   9316           this.memoryWriter[index] = this.HuC3WriteRAMBank;
   9317         }
   9318         else {
   9319           this.memoryWriter[index] = this.cartIgnoreWrite;
   9320         }
   9321       }
   9322       else {
   9323         this.memoryWriter[index] = this.cartIgnoreWrite;
   9324       }
   9325     }
   9326     else if (index < 0x9000) {
   9327       this.memoryWriter[index] = (this.cGBC) ? this.VRAMGBCDATAWrite : this.VRAMGBDATAWrite;
   9328     }
   9329     else if (index < 0x9800) {
   9330       this.memoryWriter[index] = (this.cGBC) ? this.VRAMGBCDATAWrite : this.VRAMGBDATAUpperWrite;
   9331     }
   9332     else if (index < 0xA000) {
   9333       this.memoryWriter[index] = (this.cGBC) ? this.VRAMGBCCHRMAPWrite : this.VRAMGBCHRMAPWrite;
   9334     }
   9335     else if (index < 0xC000) {
   9336       if ((this.numRAMBanks == 1 / 16 && index < 0xA200) || this.numRAMBanks >= 1) {
   9337         if (!this.cMBC3) {
   9338           this.memoryWriter[index] = this.memoryWriteMBCRAM;
   9339         }
   9340         else {
   9341           //MBC3 RTC + RAM:
   9342           this.memoryWriter[index] = this.memoryWriteMBC3RAM;
   9343         }
   9344       }
   9345       else {
   9346         this.memoryWriter[index] = this.cartIgnoreWrite;
   9347       }
   9348     }
   9349     else if (index < 0xE000) {
   9350       if (this.cGBC && index >= 0xD000) {
   9351         this.memoryWriter[index] = this.memoryWriteGBCRAM;
   9352       }
   9353       else {
   9354         this.memoryWriter[index] = this.memoryWriteNormal;
   9355       }
   9356     }
   9357     else if (index < 0xFE00) {
   9358       if (this.cGBC && index >= 0xF000) {
   9359         this.memoryWriter[index] = this.memoryWriteECHOGBCRAM;
   9360       }
   9361       else {
   9362         this.memoryWriter[index] = this.memoryWriteECHONormal;
   9363       }
   9364     }
   9365     else if (index <= 0xFEA0) {
   9366       this.memoryWriter[index] = this.memoryWriteOAMRAM;
   9367     }
   9368     else if (index < 0xFF00) {
   9369       if (this.cGBC) {                      //Only GBC has access to this RAM.
   9370         this.memoryWriter[index] = this.memoryWriteNormal;
   9371       }
   9372       else {
   9373         this.memoryWriter[index] = this.cartIgnoreWrite;
   9374       }
   9375     }
   9376     else {
   9377       //Start the I/O initialization by filling in the slots as normal memory:
   9378       this.memoryWriter[index] = this.memoryWriteNormal;
   9379       this.memoryHighWriter[index & 0xFF] = this.memoryHighWriteNormal;
   9380     }
   9381   }
   9382   this.registerWriteJumpCompile();        //Compile the I/O write functions separately...
   9383 }
   9384 GameBoyCore.prototype.MBCWriteEnable = function (parentObj, address, data) {
   9385   //MBC RAM Bank Enable/Disable:
   9386   parentObj.MBCRAMBanksEnabled = ((data & 0x0F) == 0x0A);  //If lower nibble is 0x0A, then enable, otherwise disable.
   9387 }
   9388 GameBoyCore.prototype.MBC1WriteROMBank = function (parentObj, address, data) {
   9389   //MBC1 ROM bank switching:
   9390   parentObj.ROMBank1offs = (parentObj.ROMBank1offs & 0x60) | (data & 0x1F);
   9391   parentObj.setCurrentMBC1ROMBank();
   9392 }
   9393 GameBoyCore.prototype.MBC1WriteRAMBank = function (parentObj, address, data) {
   9394   //MBC1 RAM bank switching
   9395   if (parentObj.MBC1Mode) {
   9396     //4/32 Mode
   9397     parentObj.currMBCRAMBank = data & 0x03;
   9398     parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
   9399   }
   9400   else {
   9401     //16/8 Mode
   9402     parentObj.ROMBank1offs = ((data & 0x03) << 5) | (parentObj.ROMBank1offs & 0x1F);
   9403     parentObj.setCurrentMBC1ROMBank();
   9404   }
   9405 }
   9406 GameBoyCore.prototype.MBC1WriteType = function (parentObj, address, data) {
   9407   //MBC1 mode setting:
   9408   parentObj.MBC1Mode = ((data & 0x1) == 0x1);
   9409   if (parentObj.MBC1Mode) {
   9410     parentObj.ROMBank1offs &= 0x1F;
   9411     parentObj.setCurrentMBC1ROMBank();
   9412   }
   9413   else {
   9414     parentObj.currMBCRAMBank = 0;
   9415     parentObj.currMBCRAMBankPosition = -0xA000;
   9416   }
   9417 }
   9418 GameBoyCore.prototype.MBC2WriteROMBank = function (parentObj, address, data) {
   9419   //MBC2 ROM bank switching:
   9420   parentObj.ROMBank1offs = data & 0x0F;
   9421   parentObj.setCurrentMBC2AND3ROMBank();
   9422 }
   9423 GameBoyCore.prototype.MBC3WriteROMBank = function (parentObj, address, data) {
   9424   //MBC3 ROM bank switching:
   9425   parentObj.ROMBank1offs = data & 0x7F;
   9426   parentObj.setCurrentMBC2AND3ROMBank();
   9427 }
   9428 GameBoyCore.prototype.MBC3WriteRAMBank = function (parentObj, address, data) {
   9429   parentObj.currMBCRAMBank = data;
   9430   if (data < 4) {
   9431     //MBC3 RAM bank switching
   9432     parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
   9433   }
   9434 }
   9435 GameBoyCore.prototype.MBC3WriteRTCLatch = function (parentObj, address, data) {
   9436   if (data == 0) {
   9437     parentObj.RTCisLatched = false;
   9438   }
   9439   else if (!parentObj.RTCisLatched) {
   9440     //Copy over the current RTC time for reading.
   9441     parentObj.RTCisLatched = true;
   9442     parentObj.latchedSeconds = parentObj.RTCSeconds | 0;
   9443     parentObj.latchedMinutes = parentObj.RTCMinutes;
   9444     parentObj.latchedHours = parentObj.RTCHours;
   9445     parentObj.latchedLDays = (parentObj.RTCDays & 0xFF);
   9446     parentObj.latchedHDays = parentObj.RTCDays >> 8;
   9447   }
   9448 }
   9449 GameBoyCore.prototype.MBC5WriteROMBankLow = function (parentObj, address, data) {
   9450   //MBC5 ROM bank switching:
   9451   parentObj.ROMBank1offs = (parentObj.ROMBank1offs & 0x100) | data;
   9452   parentObj.setCurrentMBC5ROMBank();
   9453 }
   9454 GameBoyCore.prototype.MBC5WriteROMBankHigh = function (parentObj, address, data) {
   9455   //MBC5 ROM bank switching (by least significant bit):
   9456   parentObj.ROMBank1offs  = ((data & 0x01) << 8) | (parentObj.ROMBank1offs & 0xFF);
   9457   parentObj.setCurrentMBC5ROMBank();
   9458 }
   9459 GameBoyCore.prototype.MBC5WriteRAMBank = function (parentObj, address, data) {
   9460   //MBC5 RAM bank switching
   9461   parentObj.currMBCRAMBank = data & 0xF;
   9462   parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
   9463 }
   9464 GameBoyCore.prototype.RUMBLEWriteRAMBank = function (parentObj, address, data) {
   9465   //MBC5 RAM bank switching
   9466   //Like MBC5, but bit 3 of the lower nibble is used for rumbling and bit 2 is ignored.
   9467   parentObj.currMBCRAMBank = data & 0x03;
   9468   parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
   9469 }
   9470 GameBoyCore.prototype.HuC3WriteRAMBank = function (parentObj, address, data) {
   9471   //HuC3 RAM bank switching
   9472   parentObj.currMBCRAMBank = data & 0x03;
   9473   parentObj.currMBCRAMBankPosition = (parentObj.currMBCRAMBank << 13) - 0xA000;
   9474 }
   9475 GameBoyCore.prototype.cartIgnoreWrite = function (parentObj, address, data) {
   9476   //We might have encountered illegal RAM writing or such, so just do nothing...
   9477 }
   9478 GameBoyCore.prototype.memoryWriteNormal = function (parentObj, address, data) {
   9479   parentObj.memory[address] = data;
   9480 }
   9481 GameBoyCore.prototype.memoryHighWriteNormal = function (parentObj, address, data) {
   9482   parentObj.memory[0xFF00 | address] = data;
   9483 }
   9484 GameBoyCore.prototype.memoryWriteMBCRAM = function (parentObj, address, data) {
   9485   if (parentObj.MBCRAMBanksEnabled || settings[10]) {
   9486     parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition] = data;
   9487   }
   9488 }
   9489 GameBoyCore.prototype.memoryWriteMBC3RAM = function (parentObj, address, data) {
   9490   if (parentObj.MBCRAMBanksEnabled || settings[10]) {
   9491     switch (parentObj.currMBCRAMBank) {
   9492       case 0x00:
   9493       case 0x01:
   9494       case 0x02:
   9495       case 0x03:
   9496         parentObj.MBCRam[address + parentObj.currMBCRAMBankPosition] = data;
   9497         break;
   9498       case 0x08:
   9499         if (data < 60) {
   9500           parentObj.RTCSeconds = data;
   9501         }
   9502         else {
   9503           cout("(Bank #" + parentObj.currMBCRAMBank + ") RTC write out of range: " + data, 1);
   9504         }
   9505         break;
   9506       case 0x09:
   9507         if (data < 60) {
   9508           parentObj.RTCMinutes = data;
   9509         }
   9510         else {
   9511           cout("(Bank #" + parentObj.currMBCRAMBank + ") RTC write out of range: " + data, 1);
   9512         }
   9513         break;
   9514       case 0x0A:
   9515         if (data < 24) {
   9516           parentObj.RTCHours = data;
   9517         }
   9518         else {
   9519           cout("(Bank #" + parentObj.currMBCRAMBank + ") RTC write out of range: " + data, 1);
   9520         }
   9521         break;
   9522       case 0x0B:
   9523         parentObj.RTCDays = (data & 0xFF) | (parentObj.RTCDays & 0x100);
   9524         break;
   9525       case 0x0C:
   9526         parentObj.RTCDayOverFlow = (data > 0x7F);
   9527         parentObj.RTCHalt = (data & 0x40) == 0x40;
   9528         parentObj.RTCDays = ((data & 0x1) << 8) | (parentObj.RTCDays & 0xFF);
   9529         break;
   9530       default:
   9531         cout("Invalid MBC3 bank address selected: " + parentObj.currMBCRAMBank, 0);
   9532     }
   9533   }
   9534 }
   9535 GameBoyCore.prototype.memoryWriteGBCRAM = function (parentObj, address, data) {
   9536   parentObj.GBCMemory[address + parentObj.gbcRamBankPosition] = data;
   9537 }
   9538 GameBoyCore.prototype.memoryWriteOAMRAM = function (parentObj, address, data) {
   9539   if (parentObj.modeSTAT < 2) {    //OAM RAM cannot be written to in mode 2 & 3
   9540     if (parentObj.memory[address] != data) {
   9541       parentObj.graphicsJIT();
   9542       parentObj.memory[address] = data;
   9543     }
   9544   }
   9545 }
   9546 GameBoyCore.prototype.memoryWriteECHOGBCRAM = function (parentObj, address, data) {
   9547   parentObj.GBCMemory[address + parentObj.gbcRamBankPositionECHO] = data;
   9548 }
   9549 GameBoyCore.prototype.memoryWriteECHONormal = function (parentObj, address, data) {
   9550   parentObj.memory[address - 0x2000] = data;
   9551 }
   9552 GameBoyCore.prototype.VRAMGBDATAWrite = function (parentObj, address, data) {
   9553   if (parentObj.modeSTAT < 3) {  //VRAM cannot be written to during mode 3
   9554     if (parentObj.memory[address] != data) {
   9555       //JIT the graphics render queue:
   9556       parentObj.graphicsJIT();
   9557       parentObj.memory[address] = data;
   9558       parentObj.generateGBOAMTileLine(address);
   9559     }
   9560   }
   9561 }
   9562 GameBoyCore.prototype.VRAMGBDATAUpperWrite = function (parentObj, address, data) {
   9563   if (parentObj.modeSTAT < 3) {  //VRAM cannot be written to during mode 3
   9564     if (parentObj.memory[address] != data) {
   9565       //JIT the graphics render queue:
   9566       parentObj.graphicsJIT();
   9567       parentObj.memory[address] = data;
   9568       parentObj.generateGBTileLine(address);
   9569     }
   9570   }
   9571 }
   9572 GameBoyCore.prototype.VRAMGBCDATAWrite = function (parentObj, address, data) {
   9573   if (parentObj.modeSTAT < 3) {  //VRAM cannot be written to during mode 3
   9574     if (parentObj.currVRAMBank == 0) {
   9575       if (parentObj.memory[address] != data) {
   9576         //JIT the graphics render queue:
   9577         parentObj.graphicsJIT();
   9578         parentObj.memory[address] = data;
   9579         parentObj.generateGBCTileLineBank1(address);
   9580       }
   9581     }
   9582     else {
   9583       address &= 0x1FFF;
   9584       if (parentObj.VRAM[address] != data) {
   9585         //JIT the graphics render queue:
   9586         parentObj.graphicsJIT();
   9587         parentObj.VRAM[address] = data;
   9588         parentObj.generateGBCTileLineBank2(address);
   9589       }
   9590     }
   9591   }
   9592 }
   9593 GameBoyCore.prototype.VRAMGBCHRMAPWrite = function (parentObj, address, data) {
   9594   if (parentObj.modeSTAT < 3) {  //VRAM cannot be written to during mode 3
   9595     address &= 0x7FF;
   9596     if (parentObj.BGCHRBank1[address] != data) {
   9597       //JIT the graphics render queue:
   9598       parentObj.graphicsJIT();
   9599       parentObj.BGCHRBank1[address] = data;
   9600     }
   9601   }
   9602 }
   9603 GameBoyCore.prototype.VRAMGBCCHRMAPWrite = function (parentObj, address, data) {
   9604   if (parentObj.modeSTAT < 3) {  //VRAM cannot be written to during mode 3
   9605     address &= 0x7FF;
   9606     if (parentObj.BGCHRCurrentBank[address] != data) {
   9607       //JIT the graphics render queue:
   9608       parentObj.graphicsJIT();
   9609       parentObj.BGCHRCurrentBank[address] = data;
   9610     }
   9611   }
   9612 }
   9613 GameBoyCore.prototype.DMAWrite = function (tilesToTransfer) {
   9614   if (!this.halt) {
   9615     //Clock the CPU for the DMA transfer (CPU is halted during the transfer):
   9616     this.CPUTicks += 4 | ((tilesToTransfer << 5) << this.doubleSpeedShifter);
   9617   }
   9618   //Source address of the transfer:
   9619   var source = (this.memory[0xFF51] << 8) | this.memory[0xFF52];
   9620   //Destination address in the VRAM memory range:
   9621   var destination = (this.memory[0xFF53] << 8) | this.memory[0xFF54];
   9622   //Creating some references:
   9623   var memoryReader = this.memoryReader;
   9624   //JIT the graphics render queue:
   9625   this.graphicsJIT();
   9626   var memory = this.memory;
   9627   //Determining which bank we're working on so we can optimize:
   9628   if (this.currVRAMBank == 0) {
   9629     //DMA transfer for VRAM bank 0:
   9630     do {
   9631       if (destination < 0x1800) {
   9632         memory[0x8000 | destination] = memoryReader[source](this, source++);
   9633         memory[0x8001 | destination] = memoryReader[source](this, source++);
   9634         memory[0x8002 | destination] = memoryReader[source](this, source++);
   9635         memory[0x8003 | destination] = memoryReader[source](this, source++);
   9636         memory[0x8004 | destination] = memoryReader[source](this, source++);
   9637         memory[0x8005 | destination] = memoryReader[source](this, source++);
   9638         memory[0x8006 | destination] = memoryReader[source](this, source++);
   9639         memory[0x8007 | destination] = memoryReader[source](this, source++);
   9640         memory[0x8008 | destination] = memoryReader[source](this, source++);
   9641         memory[0x8009 | destination] = memoryReader[source](this, source++);
   9642         memory[0x800A | destination] = memoryReader[source](this, source++);
   9643         memory[0x800B | destination] = memoryReader[source](this, source++);
   9644         memory[0x800C | destination] = memoryReader[source](this, source++);
   9645         memory[0x800D | destination] = memoryReader[source](this, source++);
   9646         memory[0x800E | destination] = memoryReader[source](this, source++);
   9647         memory[0x800F | destination] = memoryReader[source](this, source++);
   9648         this.generateGBCTileBank1(destination);
   9649         destination += 0x10;
   9650       }
   9651       else {
   9652         destination &= 0x7F0;
   9653         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9654         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9655         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9656         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9657         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9658         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9659         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9660         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9661         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9662         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9663         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9664         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9665         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9666         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9667         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9668         this.BGCHRBank1[destination++] = memoryReader[source](this, source++);
   9669         destination = (destination + 0x1800) & 0x1FF0;
   9670       }
   9671       source &= 0xFFF0;
   9672       --tilesToTransfer;
   9673     } while (tilesToTransfer > 0);
   9674   }
   9675   else {
   9676     var VRAM = this.VRAM;
   9677     //DMA transfer for VRAM bank 1:
   9678     do {
   9679       if (destination < 0x1800) {
   9680         VRAM[destination] = memoryReader[source](this, source++);
   9681         VRAM[destination | 0x1] = memoryReader[source](this, source++);
   9682         VRAM[destination | 0x2] = memoryReader[source](this, source++);
   9683         VRAM[destination | 0x3] = memoryReader[source](this, source++);
   9684         VRAM[destination | 0x4] = memoryReader[source](this, source++);
   9685         VRAM[destination | 0x5] = memoryReader[source](this, source++);
   9686         VRAM[destination | 0x6] = memoryReader[source](this, source++);
   9687         VRAM[destination | 0x7] = memoryReader[source](this, source++);
   9688         VRAM[destination | 0x8] = memoryReader[source](this, source++);
   9689         VRAM[destination | 0x9] = memoryReader[source](this, source++);
   9690         VRAM[destination | 0xA] = memoryReader[source](this, source++);
   9691         VRAM[destination | 0xB] = memoryReader[source](this, source++);
   9692         VRAM[destination | 0xC] = memoryReader[source](this, source++);
   9693         VRAM[destination | 0xD] = memoryReader[source](this, source++);
   9694         VRAM[destination | 0xE] = memoryReader[source](this, source++);
   9695         VRAM[destination | 0xF] = memoryReader[source](this, source++);
   9696         this.generateGBCTileBank2(destination);
   9697         destination += 0x10;
   9698       }
   9699       else {
   9700         destination &= 0x7F0;
   9701         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9702         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9703         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9704         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9705         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9706         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9707         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9708         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9709         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9710         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9711         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9712         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9713         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9714         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9715         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9716         this.BGCHRBank2[destination++] = memoryReader[source](this, source++);
   9717         destination = (destination + 0x1800) & 0x1FF0;
   9718       }
   9719       source &= 0xFFF0;
   9720       --tilesToTransfer;
   9721     } while (tilesToTransfer > 0);
   9722   }
   9723   //Update the HDMA registers to their next addresses:
   9724   memory[0xFF51] = source >> 8;
   9725   memory[0xFF52] = source & 0xF0;
   9726   memory[0xFF53] = destination >> 8;
   9727   memory[0xFF54] = destination & 0xF0;
   9728 }
   9729 GameBoyCore.prototype.registerWriteJumpCompile = function () {
   9730   //I/O Registers (GB + GBC):
   9731   //JoyPad
   9732   this.memoryHighWriter[0] = this.memoryWriter[0xFF00] = function (parentObj, address, data) {
   9733     parentObj.memory[0xFF00] = (data & 0x30) | ((((data & 0x20) == 0) ? (parentObj.JoyPad >> 4) : 0xF) & (((data & 0x10) == 0) ? (parentObj.JoyPad & 0xF) : 0xF));
   9734   }
   9735   //SB (Serial Transfer Data)
   9736   this.memoryHighWriter[0x1] = this.memoryWriter[0xFF01] = function (parentObj, address, data) {
   9737     if (parentObj.memory[0xFF02] < 0x80) {  //Cannot write while a serial transfer is active.
   9738       parentObj.memory[0xFF01] = data;
   9739     }
   9740   }
   9741   //DIV
   9742   this.memoryHighWriter[0x4] = this.memoryWriter[0xFF04] = function (parentObj, address, data) {
   9743     parentObj.DIVTicks &= 0xFF;  //Update DIV for realignment.
   9744     parentObj.memory[0xFF04] = 0;
   9745   }
   9746   //TIMA
   9747   this.memoryHighWriter[0x5] = this.memoryWriter[0xFF05] = function (parentObj, address, data) {
   9748     parentObj.memory[0xFF05] = data;
   9749   }
   9750   //TMA
   9751   this.memoryHighWriter[0x6] = this.memoryWriter[0xFF06] = function (parentObj, address, data) {
   9752     parentObj.memory[0xFF06] = data;
   9753   }
   9754   //TAC
   9755   this.memoryHighWriter[0x7] = this.memoryWriter[0xFF07] = function (parentObj, address, data) {
   9756     parentObj.memory[0xFF07] = data & 0x07;
   9757     parentObj.TIMAEnabled = (data & 0x04) == 0x04;
   9758     parentObj.TACClocker = Math.pow(4, ((data & 0x3) != 0) ? (data & 0x3) : 4) << 2;  //TODO: Find a way to not make a conditional in here...
   9759   }
   9760   //IF (Interrupt Request)
   9761   this.memoryHighWriter[0xF] = this.memoryWriter[0xFF0F] = function (parentObj, address, data) {
   9762     parentObj.interruptsRequested = data;
   9763     parentObj.checkIRQMatching();
   9764   }
   9765   this.memoryHighWriter[0x10] = this.memoryWriter[0xFF10] = function (parentObj, address, data) {
   9766     if (parentObj.soundMasterEnabled) {
   9767       parentObj.audioJIT();
   9768       if (parentObj.channel1decreaseSweep && (data & 0x08) == 0) {
   9769         if (parentObj.channel1numSweep != parentObj.channel1frequencySweepDivider) {
   9770           parentObj.channel1SweepFault = true;
   9771         }
   9772       }
   9773       parentObj.channel1lastTimeSweep = (data & 0x70) >> 4;
   9774       parentObj.channel1frequencySweepDivider = data & 0x07;
   9775       parentObj.channel1decreaseSweep = ((data & 0x08) == 0x08);
   9776       parentObj.memory[0xFF10] = data;
   9777       parentObj.channel1EnableCheck();
   9778     }
   9779   }
   9780   this.memoryHighWriter[0x11] = this.memoryWriter[0xFF11] = function (parentObj, address, data) {
   9781     if (parentObj.soundMasterEnabled || !parentObj.cGBC) {
   9782       if (parentObj.soundMasterEnabled) {
   9783         parentObj.audioJIT();
   9784       }
   9785       else {
   9786         data &= 0x3F;
   9787       }
   9788       parentObj.channel1CachedDuty = parentObj.dutyLookup[data >> 6];
   9789       parentObj.channel1totalLength = 0x40 - (data & 0x3F);
   9790       parentObj.memory[0xFF11] = data & 0xC0;
   9791       parentObj.channel1EnableCheck();
   9792     }
   9793   }
   9794   this.memoryHighWriter[0x12] = this.memoryWriter[0xFF12] = function (parentObj, address, data) {
   9795     if (parentObj.soundMasterEnabled) {
   9796       parentObj.audioJIT();
   9797       if (parentObj.channel1Enabled && parentObj.channel1envelopeSweeps == 0) {
   9798         //Zombie Volume PAPU Bug:
   9799         if (((parentObj.memory[0xFF12] ^ data) & 0x8) == 0x8) {
   9800           if ((parentObj.memory[0xFF12] & 0x8) == 0) {
   9801             if ((parentObj.memory[0xFF12] & 0x7) == 0x7) {
   9802               parentObj.channel1envelopeVolume += 2;
   9803             }
   9804             else {
   9805               ++parentObj.channel1envelopeVolume;
   9806             }
   9807           }
   9808           parentObj.channel1envelopeVolume = (16 - parentObj.channel1envelopeVolume) & 0xF;
   9809         }
   9810         else if ((parentObj.memory[0xFF12] & 0xF) == 0x8) {
   9811           parentObj.channel1envelopeVolume = (1 + parentObj.channel1envelopeVolume) & 0xF;
   9812         }
   9813         parentObj.channel1OutputLevelCache();
   9814       }
   9815       parentObj.channel1envelopeType = ((data & 0x08) == 0x08);
   9816       parentObj.memory[0xFF12] = data;
   9817       parentObj.channel1VolumeEnableCheck();
   9818     }
   9819   }
   9820   this.memoryHighWriter[0x13] = this.memoryWriter[0xFF13] = function (parentObj, address, data) {
   9821     if (parentObj.soundMasterEnabled) {
   9822       parentObj.audioJIT();
   9823       parentObj.channel1frequency = (parentObj.channel1frequency & 0x700) | data;
   9824       parentObj.channel1FrequencyTracker = (0x800 - parentObj.channel1frequency) << 2;
   9825       parentObj.memory[0xFF13] = data;
   9826     }
   9827   }
   9828   this.memoryHighWriter[0x14] = this.memoryWriter[0xFF14] = function (parentObj, address, data) {
   9829     if (parentObj.soundMasterEnabled) {
   9830       parentObj.audioJIT();
   9831       parentObj.channel1consecutive = ((data & 0x40) == 0x0);
   9832       parentObj.channel1frequency = ((data & 0x7) << 8) | (parentObj.channel1frequency & 0xFF);
   9833       parentObj.channel1FrequencyTracker = (0x800 - parentObj.channel1frequency) << 2;
   9834       if (data > 0x7F) {
   9835         //Reload 0xFF10:
   9836         parentObj.channel1timeSweep = parentObj.channel1lastTimeSweep;
   9837         parentObj.channel1numSweep = parentObj.channel1frequencySweepDivider;
   9838         //Reload 0xFF12:
   9839         var nr12 = parentObj.memory[0xFF12];
   9840         parentObj.channel1envelopeVolume = nr12 >> 4;
   9841         parentObj.channel1OutputLevelCache();
   9842         parentObj.channel1envelopeSweepsLast = (nr12 & 0x7) - 1;
   9843         if (parentObj.channel1totalLength == 0) {
   9844           parentObj.channel1totalLength = 0x40;
   9845         }
   9846         if (parentObj.channel1lastTimeSweep > 0 || parentObj.channel1frequencySweepDivider > 0) {
   9847           parentObj.memory[0xFF26] |= 0x1;
   9848         }
   9849         else {
   9850           parentObj.memory[0xFF26] &= 0xFE;
   9851         }
   9852         if ((data & 0x40) == 0x40) {
   9853           parentObj.memory[0xFF26] |= 0x1;
   9854         }
   9855         parentObj.channel1ShadowFrequency = parentObj.channel1frequency;
   9856         //Reset frequency overflow check + frequency sweep type check:
   9857         parentObj.channel1SweepFault = false;
   9858         //Supposed to run immediately:
   9859         parentObj.runAudioSweep();
   9860       }
   9861       parentObj.channel1EnableCheck();
   9862       parentObj.memory[0xFF14] = data & 0x40;
   9863     }
   9864   }
   9865   this.memoryHighWriter[0x16] = this.memoryWriter[0xFF16] = function (parentObj, address, data) {
   9866     if (parentObj.soundMasterEnabled || !parentObj.cGBC) {
   9867       if (parentObj.soundMasterEnabled) {
   9868         parentObj.audioJIT();
   9869       }
   9870       else {
   9871         data &= 0x3F;
   9872       }
   9873       parentObj.channel2CachedDuty = parentObj.dutyLookup[data >> 6];
   9874       parentObj.channel2totalLength = 0x40 - (data & 0x3F);
   9875       parentObj.memory[0xFF16] = data & 0xC0;
   9876       parentObj.channel2EnableCheck();
   9877     }
   9878   }
   9879   this.memoryHighWriter[0x17] = this.memoryWriter[0xFF17] = function (parentObj, address, data) {
   9880     if (parentObj.soundMasterEnabled) {
   9881       parentObj.audioJIT();
   9882       if (parentObj.channel2Enabled && parentObj.channel2envelopeSweeps == 0) {
   9883         //Zombie Volume PAPU Bug:
   9884         if (((parentObj.memory[0xFF17] ^ data) & 0x8) == 0x8) {
   9885           if ((parentObj.memory[0xFF17] & 0x8) == 0) {
   9886             if ((parentObj.memory[0xFF17] & 0x7) == 0x7) {
   9887               parentObj.channel2envelopeVolume += 2;
   9888             }
   9889             else {
   9890               ++parentObj.channel2envelopeVolume;
   9891             }
   9892           }
   9893           parentObj.channel2envelopeVolume = (16 - parentObj.channel2envelopeVolume) & 0xF;
   9894         }
   9895         else if ((parentObj.memory[0xFF17] & 0xF) == 0x8) {
   9896           parentObj.channel2envelopeVolume = (1 + parentObj.channel2envelopeVolume) & 0xF;
   9897         }
   9898         parentObj.channel2OutputLevelCache();
   9899       }
   9900       parentObj.channel2envelopeType = ((data & 0x08) == 0x08);
   9901       parentObj.memory[0xFF17] = data;
   9902       parentObj.channel2VolumeEnableCheck();
   9903     }
   9904   }
   9905   this.memoryHighWriter[0x18] = this.memoryWriter[0xFF18] = function (parentObj, address, data) {
   9906     if (parentObj.soundMasterEnabled) {
   9907       parentObj.audioJIT();
   9908       parentObj.channel2frequency = (parentObj.channel2frequency & 0x700) | data;
   9909       parentObj.channel2FrequencyTracker = (0x800 - parentObj.channel2frequency) << 2;
   9910       parentObj.memory[0xFF18] = data;
   9911     }
   9912   }
   9913   this.memoryHighWriter[0x19] = this.memoryWriter[0xFF19] = function (parentObj, address, data) {
   9914     if (parentObj.soundMasterEnabled) {
   9915       parentObj.audioJIT();
   9916       if (data > 0x7F) {
   9917         //Reload 0xFF17:
   9918         var nr22 = parentObj.memory[0xFF17];
   9919         parentObj.channel2envelopeVolume = nr22 >> 4;
   9920         parentObj.channel2OutputLevelCache();
   9921         parentObj.channel2envelopeSweepsLast = (nr22 & 0x7) - 1;
   9922         if (parentObj.channel2totalLength == 0) {
   9923           parentObj.channel2totalLength = 0x40;
   9924         }
   9925         if ((data & 0x40) == 0x40) {
   9926           parentObj.memory[0xFF26] |= 0x2;
   9927         }
   9928       }
   9929       parentObj.channel2consecutive = ((data & 0x40) == 0x0);
   9930       parentObj.channel2frequency = ((data & 0x7) << 8) | (parentObj.channel2frequency & 0xFF);
   9931       parentObj.channel2FrequencyTracker = (0x800 - parentObj.channel2frequency) << 2;
   9932       parentObj.memory[0xFF19] = data & 0x40;
   9933       parentObj.channel2EnableCheck();
   9934     }
   9935   }
   9936   this.memoryHighWriter[0x1A] = this.memoryWriter[0xFF1A] = function (parentObj, address, data) {
   9937     if (parentObj.soundMasterEnabled) {
   9938       parentObj.audioJIT();
   9939       if (!parentObj.channel3canPlay && data >= 0x80) {
   9940         parentObj.channel3lastSampleLookup = 0;
   9941         parentObj.channel3UpdateCache();
   9942       }
   9943       parentObj.channel3canPlay = (data > 0x7F);
   9944       if (parentObj.channel3canPlay && parentObj.memory[0xFF1A] > 0x7F && !parentObj.channel3consecutive) {
   9945         parentObj.memory[0xFF26] |= 0x4;
   9946       }
   9947       parentObj.memory[0xFF1A] = data & 0x80;
   9948       //parentObj.channel3EnableCheck();
   9949     }
   9950   }
   9951   this.memoryHighWriter[0x1B] = this.memoryWriter[0xFF1B] = function (parentObj, address, data) {
   9952     if (parentObj.soundMasterEnabled || !parentObj.cGBC) {
   9953       if (parentObj.soundMasterEnabled) {
   9954         parentObj.audioJIT();
   9955       }
   9956       parentObj.channel3totalLength = 0x100 - data;
   9957       parentObj.memory[0xFF1B] = data;
   9958       parentObj.channel3EnableCheck();
   9959     }
   9960   }
   9961   this.memoryHighWriter[0x1C] = this.memoryWriter[0xFF1C] = function (parentObj, address, data) {
   9962     if (parentObj.soundMasterEnabled) {
   9963       parentObj.audioJIT();
   9964       data &= 0x60;
   9965       parentObj.memory[0xFF1C] = data;
   9966       parentObj.channel3patternType = (data == 0) ? 4 : ((data >> 5) - 1);
   9967     }
   9968   }
   9969   this.memoryHighWriter[0x1D] = this.memoryWriter[0xFF1D] = function (parentObj, address, data) {
   9970     if (parentObj.soundMasterEnabled) {
   9971       parentObj.audioJIT();
   9972       parentObj.channel3frequency = (parentObj.channel3frequency & 0x700) | data;
   9973       parentObj.channel3FrequencyPeriod = (0x800 - parentObj.channel3frequency) << 1;
   9974       parentObj.memory[0xFF1D] = data;
   9975     }
   9976   }
   9977   this.memoryHighWriter[0x1E] = this.memoryWriter[0xFF1E] = function (parentObj, address, data) {
   9978     if (parentObj.soundMasterEnabled) {
   9979       parentObj.audioJIT();
   9980       if (data > 0x7F) {
   9981         if (parentObj.channel3totalLength == 0) {
   9982           parentObj.channel3totalLength = 0x100;
   9983         }
   9984         parentObj.channel3lastSampleLookup = 0;
   9985         if ((data & 0x40) == 0x40) {
   9986           parentObj.memory[0xFF26] |= 0x4;
   9987         }
   9988       }
   9989       parentObj.channel3consecutive = ((data & 0x40) == 0x0);
   9990       parentObj.channel3frequency = ((data & 0x7) << 8) | (parentObj.channel3frequency & 0xFF);
   9991       parentObj.channel3FrequencyPeriod = (0x800 - parentObj.channel3frequency) << 1;
   9992       parentObj.memory[0xFF1E] = data & 0x40;
   9993       parentObj.channel3EnableCheck();
   9994     }
   9995   }
   9996   this.memoryHighWriter[0x20] = this.memoryWriter[0xFF20] = function (parentObj, address, data) {
   9997     if (parentObj.soundMasterEnabled || !parentObj.cGBC) {
   9998       if (parentObj.soundMasterEnabled) {
   9999         parentObj.audioJIT();
   10000       }
   10001       parentObj.channel4totalLength = 0x40 - (data & 0x3F);
   10002       parentObj.memory[0xFF20] = data | 0xC0;
   10003       parentObj.channel4EnableCheck();
   10004     }
   10005   }
   10006   this.memoryHighWriter[0x21] = this.memoryWriter[0xFF21] = function (parentObj, address, data) {
   10007     if (parentObj.soundMasterEnabled) {
   10008       parentObj.audioJIT();
   10009       if (parentObj.channel4Enabled && parentObj.channel4envelopeSweeps == 0) {
   10010         //Zombie Volume PAPU Bug:
   10011         if (((parentObj.memory[0xFF21] ^ data) & 0x8) == 0x8) {
   10012           if ((parentObj.memory[0xFF21] & 0x8) == 0) {
   10013             if ((parentObj.memory[0xFF21] & 0x7) == 0x7) {
   10014               parentObj.channel4envelopeVolume += 2;
   10015             }
   10016             else {
   10017               ++parentObj.channel4envelopeVolume;
   10018             }
   10019           }
   10020           parentObj.channel4envelopeVolume = (16 - parentObj.channel4envelopeVolume) & 0xF;
   10021         }
   10022         else if ((parentObj.memory[0xFF21] & 0xF) == 0x8) {
   10023           parentObj.channel4envelopeVolume = (1 + parentObj.channel4envelopeVolume) & 0xF;
   10024         }
   10025         parentObj.channel4currentVolume = parentObj.channel4envelopeVolume << parentObj.channel4VolumeShifter;
   10026       }
   10027       parentObj.channel4envelopeType = ((data & 0x08) == 0x08);
   10028       parentObj.memory[0xFF21] = data;
   10029       parentObj.channel4UpdateCache();
   10030       parentObj.channel4VolumeEnableCheck();
   10031     }
   10032   }
   10033   this.memoryHighWriter[0x22] = this.memoryWriter[0xFF22] = function (parentObj, address, data) {
   10034     if (parentObj.soundMasterEnabled) {
   10035       parentObj.audioJIT();
   10036       parentObj.channel4FrequencyPeriod = Math.max((data & 0x7) << 4, 8) << (data >> 4);
   10037       var bitWidth = (data & 0x8);
   10038       if ((bitWidth == 0x8 && parentObj.channel4BitRange == 0x7FFF) || (bitWidth == 0 && parentObj.channel4BitRange == 0x7F)) {
   10039         parentObj.channel4lastSampleLookup = 0;
   10040         parentObj.channel4BitRange = (bitWidth == 0x8) ? 0x7F : 0x7FFF;
   10041         parentObj.channel4VolumeShifter = (bitWidth == 0x8) ? 7 : 15;
   10042         parentObj.channel4currentVolume = parentObj.channel4envelopeVolume << parentObj.channel4VolumeShifter;
   10043         parentObj.noiseSampleTable = (bitWidth == 0x8) ? parentObj.LSFR7Table : parentObj.LSFR15Table;
   10044       }
   10045       parentObj.memory[0xFF22] = data;
   10046       parentObj.channel4UpdateCache();
   10047     }
   10048   }
   10049   this.memoryHighWriter[0x23] = this.memoryWriter[0xFF23] = function (parentObj, address, data) {
   10050     if (parentObj.soundMasterEnabled) {
   10051       parentObj.audioJIT();
   10052       parentObj.memory[0xFF23] = data;
   10053       parentObj.channel4consecutive = ((data & 0x40) == 0x0);
   10054       if (data > 0x7F) {
   10055         var nr42 = parentObj.memory[0xFF21];
   10056         parentObj.channel4envelopeVolume = nr42 >> 4;
   10057         parentObj.channel4currentVolume = parentObj.channel4envelopeVolume << parentObj.channel4VolumeShifter;
   10058         parentObj.channel4envelopeSweepsLast = (nr42 & 0x7) - 1;
   10059         if (parentObj.channel4totalLength == 0) {
   10060           parentObj.channel4totalLength = 0x40;
   10061         }
   10062         if ((data & 0x40) == 0x40) {
   10063           parentObj.memory[0xFF26] |= 0x8;
   10064         }
   10065       }
   10066       parentObj.channel4EnableCheck();
   10067     }
   10068   }
   10069   this.memoryHighWriter[0x24] = this.memoryWriter[0xFF24] = function (parentObj, address, data) {
   10070     if (parentObj.soundMasterEnabled && parentObj.memory[0xFF24] != data) {
   10071       parentObj.audioJIT();
   10072       parentObj.memory[0xFF24] = data;
   10073       parentObj.VinLeftChannelMasterVolume = ((data >> 4) & 0x07) + 1;
   10074       parentObj.VinRightChannelMasterVolume = (data & 0x07) + 1;
   10075       parentObj.mixerOutputLevelCache();
   10076     }
   10077   }
   10078   this.memoryHighWriter[0x25] = this.memoryWriter[0xFF25] = function (parentObj, address, data) {
   10079     if (parentObj.soundMasterEnabled && parentObj.memory[0xFF25] != data) {
   10080       parentObj.audioJIT();
   10081       parentObj.memory[0xFF25] = data;
   10082       parentObj.rightChannel1 = ((data & 0x01) == 0x01);
   10083       parentObj.rightChannel2 = ((data & 0x02) == 0x02);
   10084       parentObj.rightChannel3 = ((data & 0x04) == 0x04);
   10085       parentObj.rightChannel4 = ((data & 0x08) == 0x08);
   10086       parentObj.leftChannel1 = ((data & 0x10) == 0x10);
   10087       parentObj.leftChannel2 = ((data & 0x20) == 0x20);
   10088       parentObj.leftChannel3 = ((data & 0x40) == 0x40);
   10089       parentObj.leftChannel4 = (data > 0x7F);
   10090       parentObj.channel1OutputLevelCache();
   10091       parentObj.channel2OutputLevelCache();
   10092       parentObj.channel3OutputLevelCache();
   10093       parentObj.channel4OutputLevelCache();
   10094     }
   10095   }
   10096   this.memoryHighWriter[0x26] = this.memoryWriter[0xFF26] = function (parentObj, address, data) {
   10097     parentObj.audioJIT();
   10098     if (!parentObj.soundMasterEnabled && data > 0x7F) {
   10099       parentObj.memory[0xFF26] = 0x80;
   10100       parentObj.soundMasterEnabled = true;
   10101       parentObj.initializeAudioStartState();
   10102     }
   10103     else if (parentObj.soundMasterEnabled && data < 0x80) {
   10104       parentObj.memory[0xFF26] = 0;
   10105       parentObj.soundMasterEnabled = false;
   10106       //GBDev wiki says the registers are written with zeros on power off:
   10107       for (var index = 0xFF10; index < 0xFF26; index++) {
   10108         parentObj.memoryWriter[index](parentObj, index, 0);
   10109       }
   10110     }
   10111   }
   10112   //0xFF27 to 0xFF2F don't do anything...
   10113   this.memoryHighWriter[0x27] = this.memoryWriter[0xFF27] = this.cartIgnoreWrite;
   10114   this.memoryHighWriter[0x28] = this.memoryWriter[0xFF28] = this.cartIgnoreWrite;
   10115   this.memoryHighWriter[0x29] = this.memoryWriter[0xFF29] = this.cartIgnoreWrite;
   10116   this.memoryHighWriter[0x2A] = this.memoryWriter[0xFF2A] = this.cartIgnoreWrite;
   10117   this.memoryHighWriter[0x2B] = this.memoryWriter[0xFF2B] = this.cartIgnoreWrite;
   10118   this.memoryHighWriter[0x2C] = this.memoryWriter[0xFF2C] = this.cartIgnoreWrite;
   10119   this.memoryHighWriter[0x2D] = this.memoryWriter[0xFF2D] = this.cartIgnoreWrite;
   10120   this.memoryHighWriter[0x2E] = this.memoryWriter[0xFF2E] = this.cartIgnoreWrite;
   10121   this.memoryHighWriter[0x2F] = this.memoryWriter[0xFF2F] = this.cartIgnoreWrite;
   10122   //WAVE PCM RAM:
   10123   this.memoryHighWriter[0x30] = this.memoryWriter[0xFF30] = function (parentObj, address, data) {
   10124     parentObj.channel3WriteRAM(0, data);
   10125   }
   10126   this.memoryHighWriter[0x31] = this.memoryWriter[0xFF31] = function (parentObj, address, data) {
   10127     parentObj.channel3WriteRAM(0x1, data);
   10128   }
   10129   this.memoryHighWriter[0x32] = this.memoryWriter[0xFF32] = function (parentObj, address, data) {
   10130     parentObj.channel3WriteRAM(0x2, data);
   10131   }
   10132   this.memoryHighWriter[0x33] = this.memoryWriter[0xFF33] = function (parentObj, address, data) {
   10133     parentObj.channel3WriteRAM(0x3, data);
   10134   }
   10135   this.memoryHighWriter[0x34] = this.memoryWriter[0xFF34] = function (parentObj, address, data) {
   10136     parentObj.channel3WriteRAM(0x4, data);
   10137   }
   10138   this.memoryHighWriter[0x35] = this.memoryWriter[0xFF35] = function (parentObj, address, data) {
   10139     parentObj.channel3WriteRAM(0x5, data);
   10140   }
   10141   this.memoryHighWriter[0x36] = this.memoryWriter[0xFF36] = function (parentObj, address, data) {
   10142     parentObj.channel3WriteRAM(0x6, data);
   10143   }
   10144   this.memoryHighWriter[0x37] = this.memoryWriter[0xFF37] = function (parentObj, address, data) {
   10145     parentObj.channel3WriteRAM(0x7, data);
   10146   }
   10147   this.memoryHighWriter[0x38] = this.memoryWriter[0xFF38] = function (parentObj, address, data) {
   10148     parentObj.channel3WriteRAM(0x8, data);
   10149   }
   10150   this.memoryHighWriter[0x39] = this.memoryWriter[0xFF39] = function (parentObj, address, data) {
   10151     parentObj.channel3WriteRAM(0x9, data);
   10152   }
   10153   this.memoryHighWriter[0x3A] = this.memoryWriter[0xFF3A] = function (parentObj, address, data) {
   10154     parentObj.channel3WriteRAM(0xA, data);
   10155   }
   10156   this.memoryHighWriter[0x3B] = this.memoryWriter[0xFF3B] = function (parentObj, address, data) {
   10157     parentObj.channel3WriteRAM(0xB, data);
   10158   }
   10159   this.memoryHighWriter[0x3C] = this.memoryWriter[0xFF3C] = function (parentObj, address, data) {
   10160     parentObj.channel3WriteRAM(0xC, data);
   10161   }
   10162   this.memoryHighWriter[0x3D] = this.memoryWriter[0xFF3D] = function (parentObj, address, data) {
   10163     parentObj.channel3WriteRAM(0xD, data);
   10164   }
   10165   this.memoryHighWriter[0x3E] = this.memoryWriter[0xFF3E] = function (parentObj, address, data) {
   10166     parentObj.channel3WriteRAM(0xE, data);
   10167   }
   10168   this.memoryHighWriter[0x3F] = this.memoryWriter[0xFF3F] = function (parentObj, address, data) {
   10169     parentObj.channel3WriteRAM(0xF, data);
   10170   }
   10171   //SCY
   10172   this.memoryHighWriter[0x42] = this.memoryWriter[0xFF42] = function (parentObj, address, data) {
   10173     if (parentObj.backgroundY != data) {
   10174       parentObj.midScanLineJIT();
   10175       parentObj.backgroundY = data;
   10176     }
   10177   }
   10178   //SCX
   10179   this.memoryHighWriter[0x43] = this.memoryWriter[0xFF43] = function (parentObj, address, data) {
   10180     if (parentObj.backgroundX != data) {
   10181       parentObj.midScanLineJIT();
   10182       parentObj.backgroundX = data;
   10183     }
   10184   }
   10185   //LY
   10186   this.memoryHighWriter[0x44] = this.memoryWriter[0xFF44] = function (parentObj, address, data) {
   10187     //Read Only:
   10188     if (parentObj.LCDisOn) {
   10189       //Gambatte says to do this:
   10190       parentObj.modeSTAT = 2;
   10191       parentObj.midScanlineOffset = -1;
   10192       parentObj.totalLinesPassed = parentObj.currentX = parentObj.queuedScanLines = parentObj.lastUnrenderedLine = parentObj.LCDTicks = parentObj.STATTracker = parentObj.actualScanLine = parentObj.memory[0xFF44] = 0;
   10193     }
   10194   }
   10195   //LYC
   10196   this.memoryHighWriter[0x45] = this.memoryWriter[0xFF45] = function (parentObj, address, data) {
   10197     if (parentObj.memory[0xFF45] != data) {
   10198       parentObj.memory[0xFF45] = data;
   10199       if (parentObj.LCDisOn) {
   10200         parentObj.matchLYC();  //Get the compare of the first scan line.
   10201       }
   10202     }
   10203   }
   10204   //WY
   10205   this.memoryHighWriter[0x4A] = this.memoryWriter[0xFF4A] = function (parentObj, address, data) {
   10206     if (parentObj.windowY != data) {
   10207       parentObj.midScanLineJIT();
   10208       parentObj.windowY = data;
   10209     }
   10210   }
   10211   //WX
   10212   this.memoryHighWriter[0x4B] = this.memoryWriter[0xFF4B] = function (parentObj, address, data) {
   10213     if (parentObj.memory[0xFF4B] != data) {
   10214       parentObj.midScanLineJIT();
   10215       parentObj.memory[0xFF4B] = data;
   10216       parentObj.windowX = data - 7;
   10217     }
   10218   }
   10219   this.memoryHighWriter[0x72] = this.memoryWriter[0xFF72] = function (parentObj, address, data) {
   10220     parentObj.memory[0xFF72] = data;
   10221   }
   10222   this.memoryHighWriter[0x73] = this.memoryWriter[0xFF73] = function (parentObj, address, data) {
   10223     parentObj.memory[0xFF73] = data;
   10224   }
   10225   this.memoryHighWriter[0x75] = this.memoryWriter[0xFF75] = function (parentObj, address, data) {
   10226     parentObj.memory[0xFF75] = data;
   10227   }
   10228   this.memoryHighWriter[0x76] = this.memoryWriter[0xFF76] = this.cartIgnoreWrite;
   10229   this.memoryHighWriter[0x77] = this.memoryWriter[0xFF77] = this.cartIgnoreWrite;
   10230   //IE (Interrupt Enable)
   10231   this.memoryHighWriter[0xFF] = this.memoryWriter[0xFFFF] = function (parentObj, address, data) {
   10232     parentObj.interruptsEnabled = data;
   10233     parentObj.checkIRQMatching();
   10234   }
   10235   this.recompileModelSpecificIOWriteHandling();
   10236   this.recompileBootIOWriteHandling();
   10237 }
   10238 GameBoyCore.prototype.recompileModelSpecificIOWriteHandling = function () {
   10239   if (this.cGBC) {
   10240     //GameBoy Color Specific I/O:
   10241     //SC (Serial Transfer Control Register)
   10242     this.memoryHighWriter[0x2] = this.memoryWriter[0xFF02] = function (parentObj, address, data) {
   10243       if (((data & 0x1) == 0x1)) {
   10244         //Internal clock:
   10245         parentObj.memory[0xFF02] = (data & 0x7F);
   10246         parentObj.serialTimer = ((data & 0x2) == 0) ? 4096 : 128;  //Set the Serial IRQ counter.
   10247         parentObj.serialShiftTimer = parentObj.serialShiftTimerAllocated = ((data & 0x2) == 0) ? 512 : 16;  //Set the transfer data shift counter.
   10248       }
   10249       else {
   10250         //External clock:
   10251         parentObj.memory[0xFF02] = data;
   10252         parentObj.serialShiftTimer = parentObj.serialShiftTimerAllocated = parentObj.serialTimer = 0;  //Zero the timers, since we're emulating as if nothing is connected.
   10253       }
   10254     }
   10255     this.memoryHighWriter[0x40] = this.memoryWriter[0xFF40] = function (parentObj, address, data) {
   10256       if (parentObj.memory[0xFF40] != data) {
   10257         parentObj.midScanLineJIT();
   10258         var temp_var = (data > 0x7F);
   10259         if (temp_var != parentObj.LCDisOn) {
   10260           //When the display mode changes...
   10261           parentObj.LCDisOn = temp_var;
   10262           parentObj.memory[0xFF41] &= 0x78;
   10263           parentObj.midScanlineOffset = -1;
   10264           parentObj.totalLinesPassed = parentObj.currentX = parentObj.queuedScanLines = parentObj.lastUnrenderedLine = parentObj.STATTracker = parentObj.LCDTicks = parentObj.actualScanLine = parentObj.memory[0xFF44] = 0;
   10265           if (parentObj.LCDisOn) {
   10266             parentObj.modeSTAT = 2;
   10267             parentObj.matchLYC();  //Get the compare of the first scan line.
   10268             parentObj.LCDCONTROL = parentObj.LINECONTROL;
   10269           }
   10270           else {
   10271             parentObj.modeSTAT = 0;
   10272             parentObj.LCDCONTROL = parentObj.DISPLAYOFFCONTROL;
   10273             parentObj.DisplayShowOff();
   10274           }
   10275           parentObj.interruptsRequested &= 0xFD;
   10276         }
   10277         parentObj.gfxWindowCHRBankPosition = ((data & 0x40) == 0x40) ? 0x400 : 0;
   10278         parentObj.gfxWindowDisplay = ((data & 0x20) == 0x20);
   10279         parentObj.gfxBackgroundBankOffset = ((data & 0x10) == 0x10) ? 0 : 0x80;
   10280         parentObj.gfxBackgroundCHRBankPosition = ((data & 0x08) == 0x08) ? 0x400 : 0;
   10281         parentObj.gfxSpriteNormalHeight = ((data & 0x04) == 0);
   10282         parentObj.gfxSpriteShow = ((data & 0x02) == 0x02);
   10283         parentObj.BGPriorityEnabled = ((data & 0x01) == 0x01);
   10284         parentObj.priorityFlaggingPathRebuild();  //Special case the priority flagging as an optimization.
   10285         parentObj.memory[0xFF40] = data;
   10286       }
   10287     }
   10288     this.memoryHighWriter[0x41] = this.memoryWriter[0xFF41] = function (parentObj, address, data) {
   10289       parentObj.LYCMatchTriggerSTAT = ((data & 0x40) == 0x40);
   10290       parentObj.mode2TriggerSTAT = ((data & 0x20) == 0x20);
   10291       parentObj.mode1TriggerSTAT = ((data & 0x10) == 0x10);
   10292       parentObj.mode0TriggerSTAT = ((data & 0x08) == 0x08);
   10293       parentObj.memory[0xFF41] = data & 0x78;
   10294     }
   10295     this.memoryHighWriter[0x46] = this.memoryWriter[0xFF46] = function (parentObj, address, data) {
   10296       parentObj.memory[0xFF46] = data;
   10297       if (data < 0xE0) {
   10298         data <<= 8;
   10299         address = 0xFE00;
   10300         var stat = parentObj.modeSTAT;
   10301         parentObj.modeSTAT = 0;
   10302         var newData = 0;
   10303         do {
   10304           newData = parentObj.memoryReader[data](parentObj, data++);
   10305           if (newData != parentObj.memory[address]) {
   10306             //JIT the graphics render queue:
   10307             parentObj.modeSTAT = stat;
   10308             parentObj.graphicsJIT();
   10309             parentObj.modeSTAT = 0;
   10310             parentObj.memory[address++] = newData;
   10311             break;
   10312           }
   10313         } while (++address < 0xFEA0);
   10314         if (address < 0xFEA0) {
   10315           do {
   10316             parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
   10317             parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
   10318             parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
   10319             parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
   10320           } while (address < 0xFEA0);
   10321         }
   10322         parentObj.modeSTAT = stat;
   10323       }
   10324     }
   10325     //KEY1
   10326     this.memoryHighWriter[0x4D] = this.memoryWriter[0xFF4D] = function (parentObj, address, data) {
   10327       parentObj.memory[0xFF4D] = (data & 0x7F) | (parentObj.memory[0xFF4D] & 0x80);
   10328     }
   10329     this.memoryHighWriter[0x4F] = this.memoryWriter[0xFF4F] = function (parentObj, address, data) {
   10330       parentObj.currVRAMBank = data & 0x01;
   10331       if (parentObj.currVRAMBank > 0) {
   10332         parentObj.BGCHRCurrentBank = parentObj.BGCHRBank2;
   10333       }
   10334       else {
   10335         parentObj.BGCHRCurrentBank = parentObj.BGCHRBank1;
   10336       }
   10337       //Only writable by GBC.
   10338     }
   10339     this.memoryHighWriter[0x51] = this.memoryWriter[0xFF51] = function (parentObj, address, data) {
   10340       if (!parentObj.hdmaRunning) {
   10341         parentObj.memory[0xFF51] = data;
   10342       }
   10343     }
   10344     this.memoryHighWriter[0x52] = this.memoryWriter[0xFF52] = function (parentObj, address, data) {
   10345       if (!parentObj.hdmaRunning) {
   10346         parentObj.memory[0xFF52] = data & 0xF0;
   10347       }
   10348     }
   10349     this.memoryHighWriter[0x53] = this.memoryWriter[0xFF53] = function (parentObj, address, data) {
   10350       if (!parentObj.hdmaRunning) {
   10351         parentObj.memory[0xFF53] = data & 0x1F;
   10352       }
   10353     }
   10354     this.memoryHighWriter[0x54] = this.memoryWriter[0xFF54] = function (parentObj, address, data) {
   10355       if (!parentObj.hdmaRunning) {
   10356         parentObj.memory[0xFF54] = data & 0xF0;
   10357       }
   10358     }
   10359     this.memoryHighWriter[0x55] = this.memoryWriter[0xFF55] = function (parentObj, address, data) {
   10360       if (!parentObj.hdmaRunning) {
   10361         if ((data & 0x80) == 0) {
   10362           //DMA
   10363           parentObj.DMAWrite((data & 0x7F) + 1);
   10364           parentObj.memory[0xFF55] = 0xFF;  //Transfer completed.
   10365         }
   10366         else {
   10367           //H-Blank DMA
   10368           parentObj.hdmaRunning = true;
   10369           parentObj.memory[0xFF55] = data & 0x7F;
   10370         }
   10371       }
   10372       else if ((data & 0x80) == 0) {
   10373         //Stop H-Blank DMA
   10374         parentObj.hdmaRunning = false;
   10375         parentObj.memory[0xFF55] |= 0x80;
   10376       }
   10377       else {
   10378         parentObj.memory[0xFF55] = data & 0x7F;
   10379       }
   10380     }
   10381     this.memoryHighWriter[0x68] = this.memoryWriter[0xFF68] = function (parentObj, address, data) {
   10382       parentObj.memory[0xFF69] = parentObj.gbcBGRawPalette[data & 0x3F];
   10383       parentObj.memory[0xFF68] = data;
   10384     }
   10385     this.memoryHighWriter[0x69] = this.memoryWriter[0xFF69] = function (parentObj, address, data) {
   10386       parentObj.updateGBCBGPalette(parentObj.memory[0xFF68] & 0x3F, data);
   10387       if (parentObj.memory[0xFF68] > 0x7F) { // high bit = autoincrement
   10388         var next = ((parentObj.memory[0xFF68] + 1) & 0x3F);
   10389         parentObj.memory[0xFF68] = (next | 0x80);
   10390         parentObj.memory[0xFF69] = parentObj.gbcBGRawPalette[next];
   10391       }
   10392       else {
   10393         parentObj.memory[0xFF69] = data;
   10394       }
   10395     }
   10396     this.memoryHighWriter[0x6A] = this.memoryWriter[0xFF6A] = function (parentObj, address, data) {
   10397       parentObj.memory[0xFF6B] = parentObj.gbcOBJRawPalette[data & 0x3F];
   10398       parentObj.memory[0xFF6A] = data;
   10399     }
   10400     this.memoryHighWriter[0x6B] = this.memoryWriter[0xFF6B] = function (parentObj, address, data) {
   10401       parentObj.updateGBCOBJPalette(parentObj.memory[0xFF6A] & 0x3F, data);
   10402       if (parentObj.memory[0xFF6A] > 0x7F) { // high bit = autoincrement
   10403         var next = ((parentObj.memory[0xFF6A] + 1) & 0x3F);
   10404         parentObj.memory[0xFF6A] = (next | 0x80);
   10405         parentObj.memory[0xFF6B] = parentObj.gbcOBJRawPalette[next];
   10406       }
   10407       else {
   10408         parentObj.memory[0xFF6B] = data;
   10409       }
   10410     }
   10411     //SVBK
   10412     this.memoryHighWriter[0x70] = this.memoryWriter[0xFF70] = function (parentObj, address, data) {
   10413       var addressCheck = (parentObj.memory[0xFF51] << 8) | parentObj.memory[0xFF52];  //Cannot change the RAM bank while WRAM is the source of a running HDMA.
   10414       if (!parentObj.hdmaRunning || addressCheck < 0xD000 || addressCheck >= 0xE000) {
   10415         parentObj.gbcRamBank = Math.max(data & 0x07, 1);  //Bank range is from 1-7
   10416         parentObj.gbcRamBankPosition = ((parentObj.gbcRamBank - 1) << 12) - 0xD000;
   10417         parentObj.gbcRamBankPositionECHO = parentObj.gbcRamBankPosition - 0x2000;
   10418       }
   10419       parentObj.memory[0xFF70] = data;  //Bit 6 cannot be written to.
   10420     }
   10421     this.memoryHighWriter[0x74] = this.memoryWriter[0xFF74] = function (parentObj, address, data) {
   10422       parentObj.memory[0xFF74] = data;
   10423     }
   10424   }
   10425   else {
   10426     //Fill in the GameBoy Color I/O registers as normal RAM for GameBoy compatibility:
   10427     //SC (Serial Transfer Control Register)
   10428     this.memoryHighWriter[0x2] = this.memoryWriter[0xFF02] = function (parentObj, address, data) {
   10429       if (((data & 0x1) == 0x1)) {
   10430         //Internal clock:
   10431         parentObj.memory[0xFF02] = (data & 0x7F);
   10432         parentObj.serialTimer = 4096;  //Set the Serial IRQ counter.
   10433         parentObj.serialShiftTimer = parentObj.serialShiftTimerAllocated = 512;  //Set the transfer data shift counter.
   10434       }
   10435       else {
   10436         //External clock:
   10437         parentObj.memory[0xFF02] = data;
   10438         parentObj.serialShiftTimer = parentObj.serialShiftTimerAllocated = parentObj.serialTimer = 0;  //Zero the timers, since we're emulating as if nothing is connected.
   10439       }
   10440     }
   10441     this.memoryHighWriter[0x40] = this.memoryWriter[0xFF40] = function (parentObj, address, data) {
   10442       if (parentObj.memory[0xFF40] != data) {
   10443         parentObj.midScanLineJIT();
   10444         var temp_var = (data > 0x7F);
   10445         if (temp_var != parentObj.LCDisOn) {
   10446           //When the display mode changes...
   10447           parentObj.LCDisOn = temp_var;
   10448           parentObj.memory[0xFF41] &= 0x78;
   10449           parentObj.midScanlineOffset = -1;
   10450           parentObj.totalLinesPassed = parentObj.currentX = parentObj.queuedScanLines = parentObj.lastUnrenderedLine = parentObj.STATTracker = parentObj.LCDTicks = parentObj.actualScanLine = parentObj.memory[0xFF44] = 0;
   10451           if (parentObj.LCDisOn) {
   10452             parentObj.modeSTAT = 2;
   10453             parentObj.matchLYC();  //Get the compare of the first scan line.
   10454             parentObj.LCDCONTROL = parentObj.LINECONTROL;
   10455           }
   10456           else {
   10457             parentObj.modeSTAT = 0;
   10458             parentObj.LCDCONTROL = parentObj.DISPLAYOFFCONTROL;
   10459             parentObj.DisplayShowOff();
   10460           }
   10461           parentObj.interruptsRequested &= 0xFD;
   10462         }
   10463         parentObj.gfxWindowCHRBankPosition = ((data & 0x40) == 0x40) ? 0x400 : 0;
   10464         parentObj.gfxWindowDisplay = (data & 0x20) == 0x20;
   10465         parentObj.gfxBackgroundBankOffset = ((data & 0x10) == 0x10) ? 0 : 0x80;
   10466         parentObj.gfxBackgroundCHRBankPosition = ((data & 0x08) == 0x08) ? 0x400 : 0;
   10467         parentObj.gfxSpriteNormalHeight = ((data & 0x04) == 0);
   10468         parentObj.gfxSpriteShow = (data & 0x02) == 0x02;
   10469         parentObj.bgEnabled = ((data & 0x01) == 0x01);
   10470         parentObj.memory[0xFF40] = data;
   10471       }
   10472     }
   10473     this.memoryHighWriter[0x41] = this.memoryWriter[0xFF41] = function (parentObj, address, data) {
   10474       parentObj.LYCMatchTriggerSTAT = ((data & 0x40) == 0x40);
   10475       parentObj.mode2TriggerSTAT = ((data & 0x20) == 0x20);
   10476       parentObj.mode1TriggerSTAT = ((data & 0x10) == 0x10);
   10477       parentObj.mode0TriggerSTAT = ((data & 0x08) == 0x08);
   10478       parentObj.memory[0xFF41] = data & 0x78;
   10479       if ((!parentObj.usedBootROM || !parentObj.usedGBCBootROM) && parentObj.LCDisOn && parentObj.modeSTAT < 2) {
   10480         parentObj.interruptsRequested |= 0x2;
   10481         parentObj.checkIRQMatching();
   10482       }
   10483     }
   10484     this.memoryHighWriter[0x46] = this.memoryWriter[0xFF46] = function (parentObj, address, data) {
   10485       parentObj.memory[0xFF46] = data;
   10486       if (data > 0x7F && data < 0xE0) {  //DMG cannot DMA from the ROM banks.
   10487         data <<= 8;
   10488         address = 0xFE00;
   10489         var stat = parentObj.modeSTAT;
   10490         parentObj.modeSTAT = 0;
   10491         var newData = 0;
   10492         do {
   10493           newData = parentObj.memoryReader[data](parentObj, data++);
   10494           if (newData != parentObj.memory[address]) {
   10495             //JIT the graphics render queue:
   10496             parentObj.modeSTAT = stat;
   10497             parentObj.graphicsJIT();
   10498             parentObj.modeSTAT = 0;
   10499             parentObj.memory[address++] = newData;
   10500             break;
   10501           }
   10502         } while (++address < 0xFEA0);
   10503         if (address < 0xFEA0) {
   10504           do {
   10505             parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
   10506             parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
   10507             parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
   10508             parentObj.memory[address++] = parentObj.memoryReader[data](parentObj, data++);
   10509           } while (address < 0xFEA0);
   10510         }
   10511         parentObj.modeSTAT = stat;
   10512       }
   10513     }
   10514     this.memoryHighWriter[0x47] = this.memoryWriter[0xFF47] = function (parentObj, address, data) {
   10515       if (parentObj.memory[0xFF47] != data) {
   10516         parentObj.midScanLineJIT();
   10517         parentObj.updateGBBGPalette(data);
   10518         parentObj.memory[0xFF47] = data;
   10519       }
   10520     }
   10521     this.memoryHighWriter[0x48] = this.memoryWriter[0xFF48] = function (parentObj, address, data) {
   10522       if (parentObj.memory[0xFF48] != data) {
   10523         parentObj.midScanLineJIT();
   10524         parentObj.updateGBOBJPalette(0, data);
   10525         parentObj.memory[0xFF48] = data;
   10526       }
   10527     }
   10528     this.memoryHighWriter[0x49] = this.memoryWriter[0xFF49] = function (parentObj, address, data) {
   10529       if (parentObj.memory[0xFF49] != data) {
   10530         parentObj.midScanLineJIT();
   10531         parentObj.updateGBOBJPalette(4, data);
   10532         parentObj.memory[0xFF49] = data;
   10533       }
   10534     }
   10535     this.memoryHighWriter[0x4D] = this.memoryWriter[0xFF4D] = function (parentObj, address, data) {
   10536       parentObj.memory[0xFF4D] = data;
   10537     }
   10538     this.memoryHighWriter[0x4F] = this.memoryWriter[0xFF4F] = this.cartIgnoreWrite;  //Not writable in DMG mode.
   10539     this.memoryHighWriter[0x55] = this.memoryWriter[0xFF55] = this.cartIgnoreWrite;
   10540     this.memoryHighWriter[0x68] = this.memoryWriter[0xFF68] = this.cartIgnoreWrite;
   10541     this.memoryHighWriter[0x69] = this.memoryWriter[0xFF69] = this.cartIgnoreWrite;
   10542     this.memoryHighWriter[0x6A] = this.memoryWriter[0xFF6A] = this.cartIgnoreWrite;
   10543     this.memoryHighWriter[0x6B] = this.memoryWriter[0xFF6B] = this.cartIgnoreWrite;
   10544     this.memoryHighWriter[0x6C] = this.memoryWriter[0xFF6C] = this.cartIgnoreWrite;
   10545     this.memoryHighWriter[0x70] = this.memoryWriter[0xFF70] = this.cartIgnoreWrite;
   10546     this.memoryHighWriter[0x74] = this.memoryWriter[0xFF74] = this.cartIgnoreWrite;
   10547   }
   10548 }
   10549 GameBoyCore.prototype.recompileBootIOWriteHandling = function () {
   10550   //Boot I/O Registers:
   10551   if (this.inBootstrap) {
   10552     this.memoryHighWriter[0x50] = this.memoryWriter[0xFF50] = function (parentObj, address, data) {
   10553       cout("Boot ROM reads blocked: Bootstrap process has ended.", 0);
   10554       parentObj.inBootstrap = false;
   10555       parentObj.disableBootROM();      //Fill in the boot ROM ranges with ROM  bank 0 ROM ranges
   10556       parentObj.memory[0xFF50] = data;  //Bits are sustained in memory?
   10557     }
   10558     if (this.cGBC) {
   10559       this.memoryHighWriter[0x6C] = this.memoryWriter[0xFF6C] = function (parentObj, address, data) {
   10560         if (parentObj.inBootstrap) {
   10561           parentObj.cGBC = ((data & 0x1) == 0);
   10562           //Exception to the GBC identifying code:
   10563           if (parentObj.name + parentObj.gameCode + parentObj.ROM[0x143] == "Game and Watch 50") {
   10564             parentObj.cGBC = true;
   10565             cout("Created a boot exception for Game and Watch Gallery 2 (GBC ID byte is wrong on the cartridge).", 1);
   10566           }
   10567           cout("Booted to GBC Mode: " + parentObj.cGBC, 0);
   10568         }
   10569         parentObj.memory[0xFF6C] = data;
   10570       }
   10571     }
   10572   }
   10573   else {
   10574     //Lockout the ROMs from accessing the BOOT ROM control register:
   10575     this.memoryHighWriter[0x50] = this.memoryWriter[0xFF50] = this.cartIgnoreWrite;
   10576   }
   10577 }
   10578 //Helper Functions
   10579 GameBoyCore.prototype.toTypedArray = function (baseArray, memtype) {
   10580   try {
   10581     // The following line was modified for benchmarking:
   10582     if (settings[5] || (memtype != "float32" && GameBoyWindow.opera && this.checkForOperaMathBug())) {
   10583       return baseArray;
   10584     }
   10585     if (!baseArray || !baseArray.length) {
   10586       return [];
   10587     }
   10588     var length = baseArray.length;
   10589     switch (memtype) {
   10590       case "uint8":
   10591         var typedArrayTemp = new Uint8Array(length);
   10592         break;
   10593       case "int8":
   10594         var typedArrayTemp = new Int8Array(length);
   10595         break;
   10596       case "int32":
   10597         var typedArrayTemp = new Int32Array(length);
   10598         break;
   10599       case "float32":
   10600         var typedArrayTemp = new Float32Array(length);
   10601     }
   10602     for (var index = 0; index < length; index++) {
   10603       typedArrayTemp[index] = baseArray[index];
   10604     }
   10605     return typedArrayTemp;
   10606   }
   10607   catch (error) {
   10608     cout("Could not convert an array to a typed array: " + error.message, 1);
   10609     return baseArray;
   10610   }
   10611 }
   10612 GameBoyCore.prototype.fromTypedArray = function (baseArray) {
   10613   try {
   10614     if (!baseArray || !baseArray.length) {
   10615       return [];
   10616     }
   10617     var arrayTemp = [];
   10618     for (var index = 0; index < baseArray.length; ++index) {
   10619       arrayTemp[index] = baseArray[index];
   10620     }
   10621     return arrayTemp;
   10622   }
   10623   catch (error) {
   10624     cout("Conversion from a typed array failed: " + error.message, 1);
   10625     return baseArray;
   10626   }
   10627 }
   10628 GameBoyCore.prototype.getTypedArray = function (length, defaultValue, numberType) {
   10629   try {
   10630     if (settings[5]) {
   10631       throw(new Error(""));
   10632     }
   10633     // The following line was modified for benchmarking:
   10634     if (numberType != "float32" && GameBoyWindow.opera && this.checkForOperaMathBug()) {
   10635       //Caught Opera breaking typed array math:
   10636       throw(new Error(""));
   10637     }
   10638     switch (numberType) {
   10639       case "int8":
   10640         var arrayHandle = new Int8Array(length);
   10641         break;
   10642       case "uint8":
   10643         var arrayHandle = new Uint8Array(length);
   10644         break;
   10645       case "int32":
   10646         var arrayHandle = new Int32Array(length);
   10647         break;
   10648       case "float32":
   10649         var arrayHandle = new Float32Array(length);
   10650     }
   10651     if (defaultValue != 0) {
   10652       var index = 0;
   10653       while (index < length) {
   10654         arrayHandle[index++] = defaultValue;
   10655       }
   10656     }
   10657   }
   10658   catch (error) {
   10659     cout("Could not convert an array to a typed array: " + error.message, 1);
   10660     var arrayHandle = [];
   10661     var index = 0;
   10662     while (index < length) {
   10663       arrayHandle[index++] = defaultValue;
   10664     }
   10665   }
   10666   return arrayHandle;
   10667 }
   10668 GameBoyCore.prototype.checkForOperaMathBug = function () {
   10669   var testTypedArray = new Uint8Array(1);
   10670   testTypedArray[0] = -1;
   10671   testTypedArray[0] >>= 0;
   10672   if (testTypedArray[0] != 0xFF) {
   10673     cout("Detected faulty math by your browser.", 2);
   10674     return true;
   10675   }
   10676   else {
   10677     return false;
   10678   }
   10679 }
   10680 
   10681 // End of js/GameBoyCore.js file.
   10682 
   10683 // Start of js/GameBoyIO.js file.
   10684 
   10685 "use strict";
   10686 var gameboy = null;            //GameBoyCore object.
   10687 var gbRunInterval = null;        //GameBoyCore Timer
   10688 var settings = [            //Some settings.
   10689   true,                 //Turn on sound.
   10690   false,                //Boot with boot ROM first? (set to false for benchmarking)
   10691   false,                //Give priority to GameBoy mode
   10692   [39, 37, 38, 40, 88, 90, 16, 13],  //Keyboard button map.
   10693   true,                //Colorize GB mode?
   10694   false,                //Disallow typed arrays?
   10695   4,                  //Interval for the emulator loop.
   10696   15,                  //Audio buffer minimum span amount over x interpreter iterations.
   10697   30,                  //Audio buffer maximum span amount over x interpreter iterations.
   10698   false,                //Override to allow for MBC1 instead of ROM only (compatibility for broken 3rd-party cartridges).
   10699   false,                //Override MBC RAM disabling and always allow reading and writing to the banks.
   10700   false,                //Use the GameBoy boot ROM instead of the GameBoy Color boot ROM.
   10701   false,                //Scale the canvas in JS, or let the browser scale the canvas?
   10702   0x10,                //Internal audio buffer pre-interpolation factor.
   10703   1                  //Volume level set.
   10704 ];
   10705 function start(canvas, ROM) {
   10706   clearLastEmulation();
   10707   autoSave();  //If we are about to load a new game, then save the last one...
   10708   gameboy = new GameBoyCore(canvas, ROM);
   10709   gameboy.openMBC = openSRAM;
   10710   gameboy.openRTC = openRTC;
   10711   gameboy.start();
   10712   run();
   10713 }
   10714 function run() {
   10715   if (GameBoyEmulatorInitialized()) {
   10716     if (!GameBoyEmulatorPlaying()) {
   10717       gameboy.stopEmulator &= 1;
   10718       cout("Starting the iterator.", 0);
   10719       var dateObj = new_Date();  // The line is changed for benchmarking.
   10720       gameboy.firstIteration = dateObj.getTime();
   10721       gameboy.iterations = 0;
   10722       // The following lines are commented out for benchmarking.
   10723       // gbRunInterval = setInterval(function () {
   10724       //  if (!document.hidden && !document.msHidden && !document.mozHidden && !document.webkitHidden) {
   10725       //    gameboy.run();
   10726       // }
   10727       // }, settings[6]);
   10728     }
   10729     else {
   10730       cout("The GameBoy core is already running.", 1);
   10731     }
   10732   }
   10733   else {
   10734     cout("GameBoy core cannot run while it has not been initialized.", 1);
   10735   }
   10736 }
   10737 function pause() {
   10738   if (GameBoyEmulatorInitialized()) {
   10739     if (GameBoyEmulatorPlaying()) {
   10740       clearLastEmulation();
   10741     }
   10742     else {
   10743       cout("GameBoy core has already been paused.", 1);
   10744     }
   10745   }
   10746   else {
   10747     cout("GameBoy core cannot be paused while it has not been initialized.", 1);
   10748   }
   10749 }
   10750 function clearLastEmulation() {
   10751   if (GameBoyEmulatorInitialized() && GameBoyEmulatorPlaying()) {
   10752     clearInterval(gbRunInterval);
   10753     gameboy.stopEmulator |= 2;
   10754     cout("The previous emulation has been cleared.", 0);
   10755   }
   10756   else {
   10757     cout("No previous emulation was found to be cleared.", 0);
   10758   }
   10759 }
   10760 function save() {
   10761   if (GameBoyEmulatorInitialized()) {
   10762     try {
   10763       var state_suffix = 0;
   10764       while (findValue("FREEZE_" + gameboy.name + "_" + state_suffix) != null) {
   10765         state_suffix++;
   10766       }
   10767       setValue("FREEZE_" + gameboy.name + "_" + state_suffix, gameboy.saveState());
   10768       cout("Saved the current state as: FREEZE_" + gameboy.name + "_" + state_suffix, 0);
   10769     }
   10770     catch (error) {
   10771       cout("Could not save the current emulation state(\"" + error.message + "\").", 2);
   10772     }
   10773   }
   10774   else {
   10775     cout("GameBoy core cannot be saved while it has not been initialized.", 1);
   10776   }
   10777 }
   10778 function saveSRAM() {
   10779   if (GameBoyEmulatorInitialized()) {
   10780     if (gameboy.cBATT) {
   10781       try {
   10782         var sram = gameboy.saveSRAMState();
   10783         if (sram.length > 0) {
   10784           cout("Saving the SRAM...", 0);
   10785           if (findValue("SRAM_" + gameboy.name) != null) {
   10786             //Remove the outdated storage format save:
   10787             cout("Deleting the old SRAM save due to outdated format.", 0);
   10788             deleteValue("SRAM_" + gameboy.name);
   10789           }
   10790           setValue("B64_SRAM_" + gameboy.name, arrayToBase64(sram));
   10791         }
   10792         else {
   10793           cout("SRAM could not be saved because it was empty.", 1);
   10794         }
   10795       }
   10796       catch (error) {
   10797         cout("Could not save the current emulation state(\"" + error.message + "\").", 2);
   10798       }
   10799     }
   10800     else {
   10801       cout("Cannot save a game that does not have battery backed SRAM specified.", 1);
   10802     }
   10803     saveRTC();
   10804   }
   10805   else {
   10806     cout("GameBoy core cannot be saved while it has not been initialized.", 1);
   10807   }
   10808 }
   10809 function saveRTC() {  //Execute this when SRAM is being saved as well.
   10810   if (GameBoyEmulatorInitialized()) {
   10811     if (gameboy.cTIMER) {
   10812       try {
   10813         cout("Saving the RTC...", 0);
   10814         setValue("RTC_" + gameboy.name, gameboy.saveRTCState());
   10815       }
   10816       catch (error) {
   10817         cout("Could not save the RTC of the current emulation state(\"" + error.message + "\").", 2);
   10818       }
   10819     }
   10820   }
   10821   else {
   10822     cout("GameBoy core cannot be saved while it has not been initialized.", 1);
   10823   }
   10824 }
   10825 function autoSave() {
   10826   if (GameBoyEmulatorInitialized()) {
   10827     cout("Automatically saving the SRAM.", 0);
   10828     saveSRAM();
   10829     saveRTC();
   10830   }
   10831 }
   10832 function openSRAM(filename) {
   10833   try {
   10834     if (findValue("B64_SRAM_" + filename) != null) {
   10835       cout("Found a previous SRAM state (Will attempt to load).", 0);
   10836       return base64ToArray(findValue("B64_SRAM_" + filename));
   10837     }
   10838     else if (findValue("SRAM_" + filename) != null) {
   10839       cout("Found a previous SRAM state (Will attempt to load).", 0);
   10840       return findValue("SRAM_" + filename);
   10841     }
   10842     else {
   10843       cout("Could not find any previous SRAM copy for the current ROM.", 0);
   10844     }
   10845   }
   10846   catch (error) {
   10847     cout("Could not open the  SRAM of the saved emulation state.", 2);
   10848   }
   10849   return [];
   10850 }
   10851 function openRTC(filename) {
   10852   try {
   10853     if (findValue("RTC_" + filename) != null) {
   10854       cout("Found a previous RTC state (Will attempt to load).", 0);
   10855       return findValue("RTC_" + filename);
   10856     }
   10857     else {
   10858       cout("Could not find any previous RTC copy for the current ROM.", 0);
   10859     }
   10860   }
   10861   catch (error) {
   10862     cout("Could not open the RTC data of the saved emulation state.", 2);
   10863   }
   10864   return [];
   10865 }
   10866 function openState(filename, canvas) {
   10867   try {
   10868     if (findValue(filename) != null) {
   10869       try {
   10870         clearLastEmulation();
   10871         cout("Attempting to run a saved emulation state.", 0);
   10872         gameboy = new GameBoyCore(canvas, "");
   10873         gameboy.savedStateFileName = filename;
   10874         gameboy.returnFromState(findValue(filename));
   10875         run();
   10876       }
   10877       catch (error) {
   10878         alert(error.message + " file: " + error.fileName + " line: " + error.lineNumber);
   10879       }
   10880     }
   10881     else {
   10882       cout("Could not find the save state " + filename + "\".", 2);
   10883     }
   10884   }
   10885   catch (error) {
   10886     cout("Could not open the saved emulation state.", 2);
   10887   }
   10888 }
   10889 function import_save(blobData) {
   10890   blobData = decodeBlob(blobData);
   10891   if (blobData && blobData.blobs) {
   10892     if (blobData.blobs.length > 0) {
   10893       for (var index = 0; index < blobData.blobs.length; ++index) {
   10894         cout("Importing blob \"" + blobData.blobs[index].blobID + "\"", 0);
   10895         if (blobData.blobs[index].blobContent) {
   10896           if (blobData.blobs[index].blobID.substring(0, 5) == "SRAM_") {
   10897             setValue("B64_" + blobData.blobs[index].blobID, base64(blobData.blobs[index].blobContent));
   10898           }
   10899           else {
   10900             setValue(blobData.blobs[index].blobID, JSON.parse(blobData.blobs[index].blobContent));
   10901           }
   10902         }
   10903         else if (blobData.blobs[index].blobID) {
   10904           cout("Save file imported had blob \"" + blobData.blobs[index].blobID + "\" with no blob data interpretable.", 2);
   10905         }
   10906         else {
   10907           cout("Blob chunk information missing completely.", 2);
   10908         }
   10909       }
   10910     }
   10911     else {
   10912       cout("Could not decode the imported file.", 2);
   10913     }
   10914   }
   10915   else {
   10916     cout("Could not decode the imported file.", 2);
   10917   }
   10918 }
   10919 function generateBlob(keyName, encodedData) {
   10920   //Append the file format prefix:
   10921   var saveString = "EMULATOR_DATA";
   10922   var consoleID = "GameBoy";
   10923   //Figure out the length:
   10924   var totalLength = (saveString.length + 4 + (1 + consoleID.length)) + ((1 + keyName.length) + (4 + encodedData.length));
   10925   //Append the total length in bytes:
   10926   saveString += to_little_endian_dword(totalLength);
   10927   //Append the console ID text's length:
   10928   saveString += to_byte(consoleID.length);
   10929   //Append the console ID text:
   10930   saveString += consoleID;
   10931   //Append the blob ID:
   10932   saveString += to_byte(keyName.length);
   10933   saveString += keyName;
   10934   //Now append the save data:
   10935   saveString += to_little_endian_dword(encodedData.length);
   10936   saveString += encodedData;
   10937   return saveString;
   10938 }
   10939 function generateMultiBlob(blobPairs) {
   10940   var consoleID = "GameBoy";
   10941   //Figure out the initial length:
   10942   var totalLength = 13 + 4 + 1 + consoleID.length;
   10943   //Append the console ID text's length:
   10944   var saveString = to_byte(consoleID.length);
   10945   //Append the console ID text:
   10946   saveString += consoleID;
   10947   var keyName = "";
   10948   var encodedData = "";
   10949   //Now append all the blobs:
   10950   for (var index = 0; index < blobPairs.length; ++index) {
   10951     keyName = blobPairs[index][0];
   10952     encodedData = blobPairs[index][1];
   10953     //Append the blob ID:
   10954     saveString += to_byte(keyName.length);
   10955     saveString += keyName;
   10956     //Now append the save data:
   10957     saveString += to_little_endian_dword(encodedData.length);
   10958     saveString += encodedData;
   10959     //Update the total length:
   10960     totalLength += 1 + keyName.length + 4 + encodedData.length;
   10961   }
   10962   //Now add the prefix:
   10963   saveString = "EMULATOR_DATA" + to_little_endian_dword(totalLength) + saveString;
   10964   return saveString;
   10965 }
   10966 function decodeBlob(blobData) {
   10967   /*Format is as follows:
   10968     - 13 byte string "EMULATOR_DATA"
   10969     - 4 byte total size (including these 4 bytes).
   10970     - 1 byte Console type ID length
   10971     - Console type ID text of 8 bit size
   10972     blobs {
   10973       - 1 byte blob ID length
   10974       - blob ID text (Used to say what the data is (SRAM/freeze state/etc...))
   10975       - 4 byte blob length
   10976       - blob length of 32 bit size
   10977     }
   10978   */
   10979   var length = blobData.length;
   10980   var blobProperties = {};
   10981   blobProperties.consoleID = null;
   10982   var blobsCount = -1;
   10983   blobProperties.blobs = [];
   10984   if (length > 17) {
   10985     if (blobData.substring(0, 13) == "EMULATOR_DATA") {
   10986       var length = Math.min(((blobData.charCodeAt(16) & 0xFF) << 24) | ((blobData.charCodeAt(15) & 0xFF) << 16) | ((blobData.charCodeAt(14) & 0xFF) << 8) | (blobData.charCodeAt(13) & 0xFF), length);
   10987       var consoleIDLength = blobData.charCodeAt(17) & 0xFF;
   10988       if (length > 17 + consoleIDLength) {
   10989         blobProperties.consoleID = blobData.substring(18, 18 + consoleIDLength);
   10990         var blobIDLength = 0;
   10991         var blobLength = 0;
   10992         for (var index = 18 + consoleIDLength; index < length;) {
   10993           blobIDLength = blobData.charCodeAt(index++) & 0xFF;
   10994           if (index + blobIDLength < length) {
   10995             blobProperties.blobs[++blobsCount] = {};
   10996             blobProperties.blobs[blobsCount].blobID = blobData.substring(index, index + blobIDLength);
   10997             index += blobIDLength;
   10998             if (index + 4 < length) {
   10999               blobLength = ((blobData.charCodeAt(index + 3) & 0xFF) << 24) | ((blobData.charCodeAt(index + 2) & 0xFF) << 16) | ((blobData.charCodeAt(index + 1) & 0xFF) << 8) | (blobData.charCodeAt(index) & 0xFF);
   11000               index += 4;
   11001               if (index + blobLength <= length) {
   11002                 blobProperties.blobs[blobsCount].blobContent =  blobData.substring(index, index + blobLength);
   11003                 index += blobLength;
   11004               }
   11005               else {
   11006                 cout("Blob length check failed, blob determined to be incomplete.", 2);
   11007                 break;
   11008               }
   11009             }
   11010             else {
   11011               cout("Blob was incomplete, bailing out.", 2);
   11012               break;
   11013             }
   11014           }
   11015           else {
   11016             cout("Blob was incomplete, bailing out.", 2);
   11017             break;
   11018           }
   11019         }
   11020       }
   11021     }
   11022   }
   11023   return blobProperties;
   11024 }
   11025 function matchKey(key) {  //Maps a keyboard key to a gameboy key.
   11026   //Order: Right, Left, Up, Down, A, B, Select, Start
   11027   for (var index = 0; index < settings[3].length; index++) {
   11028     if (settings[3][index] == key) {
   11029       return index;
   11030     }
   11031   }
   11032   return -1;
   11033 }
   11034 function GameBoyEmulatorInitialized() {
   11035   return (typeof gameboy == "object" && gameboy != null);
   11036 }
   11037 function GameBoyEmulatorPlaying() {
   11038   return ((gameboy.stopEmulator & 2) == 0);
   11039 }
   11040 function GameBoyKeyDown(e) {
   11041   if (GameBoyEmulatorInitialized() && GameBoyEmulatorPlaying()) {
   11042     var keycode = matchKey(e.keyCode);
   11043     if (keycode >= 0 && keycode < 8) {
   11044       gameboy.JoyPadEvent(keycode, true);
   11045       try {
   11046         e.preventDefault();
   11047       }
   11048       catch (error) { }
   11049     }
   11050   }
   11051 }
   11052 function GameBoyKeyUp(e) {
   11053   if (GameBoyEmulatorInitialized() && GameBoyEmulatorPlaying()) {
   11054     var keycode = matchKey(e.keyCode);
   11055     if (keycode >= 0 && keycode < 8) {
   11056       gameboy.JoyPadEvent(keycode, false);
   11057       try {
   11058         e.preventDefault();
   11059       }
   11060       catch (error) { }
   11061     }
   11062   }
   11063 }
   11064 function GameBoyGyroSignalHandler(e) {
   11065   if (GameBoyEmulatorInitialized() && GameBoyEmulatorPlaying()) {
   11066     if (e.gamma || e.beta) {
   11067       gameboy.GyroEvent(e.gamma * Math.PI / 180, e.beta * Math.PI / 180);
   11068     }
   11069     else {
   11070       gameboy.GyroEvent(e.x, e.y);
   11071     }
   11072     try {
   11073       e.preventDefault();
   11074     }
   11075     catch (error) { }
   11076   }
   11077 }
   11078 //The emulator will call this to sort out the canvas properties for (re)initialization.
   11079 function initNewCanvas() {
   11080   if (GameBoyEmulatorInitialized()) {
   11081     gameboy.canvas.width = gameboy.canvas.clientWidth;
   11082     gameboy.canvas.height = gameboy.canvas.clientHeight;
   11083   }
   11084 }
   11085 //Call this when resizing the canvas:
   11086 function initNewCanvasSize() {
   11087   if (GameBoyEmulatorInitialized()) {
   11088     if (!settings[12]) {
   11089       if (gameboy.onscreenWidth != 160 || gameboy.onscreenHeight != 144) {
   11090         gameboy.initLCD();
   11091       }
   11092     }
   11093     else {
   11094       if (gameboy.onscreenWidth != gameboy.canvas.clientWidth || gameboy.onscreenHeight != gameboy.canvas.clientHeight) {
   11095         gameboy.initLCD();
   11096       }
   11097     }
   11098   }
   11099 }
   11100 
   11101 // End of js/GameBoyIO.js file.
   11102 
   11103 // Start of realtime.js file.
   11104 // ROM code from Public Domain LPC2000 Demo "realtime" by AGO.
   11105 
   11106 gameboy_rom='r+BPyZiEZwA+AeBPySAobeEq6gAgKlYj5WJv6SRmZjjhKuXqACDJ/////////////////////////////////xgHZwCYhGcA2fX6/3/1xdXlIRPKNgHN9f/h0cHx6gAg+hLKtyAC8cnwgLcoF/CC7hjgUT6Q4FOv4FLgVOCAPv/gVfHZ8IG3IALx2fBA7gjgQA8PD+YB7gHgT/CC4FHuEOCCPojgU6/gUuBU4IE+/uBV4ID6NMs86jTL8dkKCgoKbWFkZSBieSBhZ28uIGVtYWlsOmdvYnV6b3ZAeWFob28uY29tCnVybDogc3BlY2N5LmRhLnJ1CgoKCv///////wDDSgnO7WZmzA0ACwNzAIMADAANAAgRH4iJAA7czG7m3d3Zmbu7Z2NuDuzM3dyZn7u5Mz5BR08nUyBSRUFMVElNRSCAAAAAAgEDADMBSTQeIUD/y37I8P/1y4fg//BE/pEg+su+8eD/yT7A4EY+KD0g/cnF1eWvEQPK1RITEhMGAyEAyuXFTgYAIWAMCQkqEhMqEhPB4SMFIOrhrwYIzYsU4dHByf////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8AAgMFBggJCwwOEBETFBYXGBobHR4fISIjJSYnKSorLC0uLzAxMjM0NTY3ODg5Ojo7PDw9PT4+Pj8/Pz9AQEBAQEBAQEBAPz8/Pz4+PT08PDs7Ojk5ODc2NTU0MzIxMC8uLCsqKSgmJSQjISAfHRwaGRcWFRMSEA8NCwoIBwUEAgH//fz6+ff29PPx8O7t6+ro5+Xk4uHg3t3c2tnY19bU09LR0M/OzczLysnJyMfGxsXFxMPDw8LCwcHBwcDAwMDAwMDAwMDBwcHBwsLDw8PExcXGxsfIycnKy8zNzs/Q0dLT1NXX2Nna3N3e4OHi5OXn6Onr7O7v8fL09vf5+vz9AAEECRAZJDFAUWR5kKnE4QAhRGmQueQRQHGk2RBJhMEAQYTJEFmk8UCR5DmQ6UShAGHEKZD5ZNFAsSSZEIkEgQCBBIkQmSSxQNFk+ZApxGEAoUTpkDnkkUDxpFkQyYRBAMGESRDZpHFAEeS5kGlEIQDhxKmQeWRRQDEkGRAJBAEAAQQJEBkkMUBRZHmQqcThACFEaZC55BFAcaTZEEmEwQBBhMkQWaTxQJHkOZDpRKEAYcQpkPlk0UCxJJkQiQSBAIEEiRCZJLFA0WT5kCnEYQChROmQOeSRQPGkWRDJhEEAwYRJENmkcUAR5LmQaUQhAOHEqZB5ZFFAMSQZEAkEAQAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAgICAgIDAwMDBAQEBAUFBQUGBgYHBwcICAkJCQoKCgsLDAwNDQ4ODw8QEBEREhITExQUFRUWFxcYGRkaGhscHB0eHh8gISEiIyQkJSYnJygpKisrLC0uLzAxMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1FSU1RVVldZWltcXV9gYWJkZWZnaWprbG5vcHJzdHZ3eXp7fX5/gYKEhYeIiouNjpCRk5SWl5manJ2foKKkpaepqqytr7GytLa3ubu9vsDCxMXHycvMztDS1NXX2dvd3+Hi5Obo6uzu8PL09vj6/P4A//z38Ofcz8CvnIdwVzwfAN+8l3BHHO/Aj1wn8Ld8PwC/fDfwp1wPwG8cx3AXvF8AnzzXcAecL8BP3Gfwd/x/AH/8d/Bn3E/AL5wHcNc8nwBfvBdwxxxvwA9cp/A3fL8AP3y38Cdcj8DvHEdwl7zfAB88V3CHnK/Az9zn8Pf8/wD//Pfw59zPwK+ch3BXPB8A37yXcEcc78CPXCfwt3w/AL98N/CnXA/AbxzHcBe8XwCfPNdwB5wvwE/cZ/B3/H8Af/x38GfcT8AvnAdw1zyfAF+8F3DHHG/AD1yn8Dd8vwA/fLfwJ1yPwO8cR3CXvN8AHzxXcIecr8DP3Ofw9/z/AP/////////////////////+/v7+/v79/f39/fz8/Pz8+/v7+vr6+vn5+fj4+Pf39/b29fX19PTz8/Ly8fHw8PDv7u7t7ezs6+vq6uno6Ofn5uXl5OPj4uHh4N/e3t3c3Nva2djY19bV1NTT0tHQz8/OzczLysnIx8bFxMPCwcDAvr28u7q5uLe2tbSzsrGwr62sq6qpqKalpKOioJ+enZyamZiWlZSTkZCPjYyLiYiHhYSCgYB+fXt6eHd1dHJxcG5sa2loZmVjYmBfXVtaWFdVU1JQTk1LSUhGREJBPz08Ojg2NDMxLy0rKigmJCIgHx0bGRcVExEPDQsJBwUDAf9/Px8PBwMBgEAgEAgEAgEAAQEBAQEBAQEBAQEA//////////////+AEAcAAQABAAEBAAEBAAEA/wD//wD//wD/AP+AKwcBAAEAAQD/AP8A/wD/AP8A/wABAAEAAQCARgcBAQEBAQD//////////////wABAQEBAQGAYQf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+AwODw+Pz+/xEAwAGxwj4E9cU+BfUKbwMKZ37+gCALI34LAiN+AwILGOsahhIDHBwcHPE9IN7BIRAAGVRdPgX1Cm8DCmcalhIjfAILfQIDAx0dHR3xPSDnIRgAGVRd8T0grskRAcAB6cI+BPUKbwMKZ37+gCALI34LAiN+AwILGOs+CvUahhIcHBwc8T0g9CN8Agt9AgMD8T0g0MkgIEZJTExFRCAgIFBPTFlHT05TIEhFTElDT1BURVJJTiBBQ1RJT04gIQDADgpwLHQsGhPWICI2ACwNIPE+oOoQyngBCQDlYmsJVF3hDMYKR3AsdCwaG9YgIjYALA0g8a/qEcrJ+hDK/jDI1gTqEMpHPqCQ/lA4Aj5QDgAM1ggw+3ghAcARBAB3xggZDSD5+hHKg+oRykf+UDgCPlAOAAzWCDD7eC4td9YIGQ0g+ckh9grzMf/PzVABr+Am4P/gD+BD4EL2SOBFPkDgQT4E4AfN9RM+CuoAAA4HeeBwJqCvIstsKPsNIPIh/v8yy30g+wEKABH1/yFpAc3kE+cCAVYAEQDBIVt2zeQTrwYYIWsOzYsUIYsOzaQUxwGwAxEAgCGhF8XlzeQT4cERAIjN5BMhAJgRAwABYMDHcc9yIwUg+BQdIPHN9RMhuxUGAc2WE82JEz5E4EGv4EU+A+D/+z4B6hLK4E0QAAB4zccTBSD6zZATxwEACFkhAIhzIwt4sSD5IQDHPv9FdyRwJCJ3JXclcCwg8x5/IQCYx3PPNgDL1DYIx3PLlCPLVCjuPoABDxARIAAhIpjF5XfL1HfLlDwZDSD1POEswQUg7D486jPLr+o0yz3qL8s+oOCCPgLqG8vNiRM+ROBBr+BFPgPg/68+ACEXyyI+CiI+IHev6h7L4ITgluodyz4B6h/L6g/D6g3KBlARnAjNxAjNcwsBLAHFzTsLzQAJwQt4sSDzzZATxwEACFkhAIhzIwt4sSD5zfUTeQYQIYMOzYsUPv/qKcsGgBGwCM3ECM2JEwEsAcXNbAzNAAnBC3ixIPOv6hLKzZATPpDgU/PHAbADEQCIIaEXzeQTzfUTIQIWBgHNlhPNiRM+ROBBr+BFPgPg//sY/j4D6gAgzcRGBgMhF8t+gCJ+gDwifoB3zckP+jDLb/oxy2fNtgs+AeCB8IG3IPv6Dcq3KAPNcwHJ+h3LBgARTg2Hb2AZKmZvTgkq4ItfKjzgjD1PKuCNe4eHg0cRAMUqEhwFIPp5h4eBRxEAxCoSHAUg+n3qMMt86jHLyfCL4I7wjOCP8I3gkBEAw9XlzcoQ4dHwpeaAEhwBAwAJ8JA94JAg6CEAxQYPKk+gXxq3IB95yzegXxq3IBYqT6BfGrcgD3nLN6BfGrcgBiwsLBhHLOXNyhDwlrcoKwYB8KXGP0/LfygBBcXwpMY/Vx4AzZMOe8H18KPGP1ceAM2TDsHhJCJwGAzhJPCjxj8i8KTGPyIsJRbDBg/wjj3gjsLiCz4C6gAgw1JhfBjcHwAL7mpIYL9vBgMhF8t+gCJ+gDwifoB3zckPIcsNEQDGzf4MI+U+A+oAICEgy83+DPocy9YIb+ocy82vYAYDESDLIWIOxeXVzcoQ4fCjxhQi8KQiNg8jVF3hIyMjwQUg5M3ERsE+AeoAIAr+/ygiEQDGbyYAKRnlAwoDbyYAKRleI1bhKmZvxc0xHMwAQMEY2T4B4IHwgbcg+8l+PMjl1c3KEAYB8KVPy38oAQXF8KTLf/UoAi88Vx4AzZMO8XsgAi88xn/B9fCjy3/1KAIvPFceAM2TDvF7KAIvPMZ/wdESE3gSE+EjIyMYsFANAgAIDAYCRCgoFANEKAAUE0QAABQSRAAoFAJVKCjsA1UoAOwTVQAA7BJVACjsAAAEBQAAAAEFAAEBAwIGAQEDBwYCAgAHAwICAAcEAwMBAgYDAwEFBgQEAAECBAQAAwIFBQQFBgUFBAcGMgAAzgAAADIAAM4AAAAyAADOKAAAHhEAChEAAAAACu8AHu8AFAAKFAD2FAAPCgAF6AAC4gAQ3gAQ4gD+CgD74g4C3Q4C4QAC4vIC3fIC4AAM4PsM4PsQ4/sJ3fsJ/wABAQICAwMEBAUFAAAGAQYCBgMGBAYFBgAHAQcCBwMHBAcFBwYICQoKCwsMDA0NDgoPDxAQEQoSEhMTERQVFRYVFxUYCBkIGggb/yAAD/AbD/DlD/9//3+XEQAAAGD/f5cRAAAYAP9/lxEAAIB8lxH/f/9/QHz/f18IAADLI8sSeC9HeS9PAyEAAH2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEn2Pb3yPZwk4BWd9kW+3yxPLEssoyxkJ0BPJ+hfLJgJvfuCcLzzgnn3GQG9+4Jvgn6/gmOCZ4JrgneChPkDgl/oYy29OfcZAb0bFeOCgeeCizdMQ8KPgpvCk4KnwpeCsr+Cg4KI+QOChzdMQ8KPgp/Ck4KrwpeCtwXkvPOCgr+CheOCizdMQ8KPgmfCk4JzwpeCf8Kbgl/Cp4JrwrOCd8KfgmPCq4JvwreCe+hnLJgJvTn3GQG9GxXjgoHkvPOChr+CizdMQ8KPgpvCk4KnwpeCswXngoHjgoa/gos3TEPCj4KfwpOCq8KXgra/goOChPkDgos3TEPCj4JnwpOCc8KXgn/Cm4JfwqeCa8KzgnfCn4JjwquCb8K3gnskq4KAq4KEq4KLwl1/woCYGV8t6ICDLe3soJy88X3qTMAIvPG96g1YlXiVvfiVuZxl8LzwYH3ovPFfLeyjhey88X5IwAi88b3qDViVeJW9+JW5nGXxH8Jhf8KEmBlfLeiAgy3t7KCcvPF96kzACLzxveoNWJV4lb34lbmcZfC88GB96LzxXy3so4XsvPF+SMAIvPG96g1YlXiVvfiVuZxl8T/CZX/CiJgZXy3ogIMt7eygnLzxfepMwAi88b3qDViVeJW9+JW5nGXwvPBgfei88V8t7KOF7LzxfkjACLzxveoNWJV4lb34lbmcZfICB4KPwml/woCYGV8t6ICDLe3soJy88X3qTMAIvPG96g1YlXiVvfiVuZxl8LzwYH3ovPFfLeyjhey88X5IwAi88b3qDViVeJW9+JW5nGXxH8Jtf8KEmBlfLeiAgy3t7KCcvPF96kzACLzxveoNWJV4lb34lbmcZfC88GB96LzxXy3so4XsvPF+SMAIvPG96g1YlXiVvfiVuZxl8T/CcX/CiJgZXy3ogIMt7eygnLzxfepMwAi88b3qDViVeJW9+JW5nGXwvPBgfei88V8t7KOF7LzxfkjACLzxveoNWJV4lb34lbmcZfICB4KTwnV/woCYGV8t6ICDLe3soJy88X3qTMAIvPG96g1YlXiVvfiVuZxl8LzwYH3ovPFfLeyjhey88X5IwAi88b3qDViVeJW9+JW5nGXxH8J5f8KEmBlfLeiAgy3t7KCcvPF96kzACLzxveoNWJV4lb34lbmcZfC88GB96LzxXy3so4XsvPF+SMAIvPG96g1YlXiVvfiVuZxl8T/CfX/CiJgZXy3ogIMt7eygnLzxfepMwAi88b3qDViVeJW9+JW5nGXwvPBgfei88V8t7KOF7LzxfkjACLzxveoNWJV4lb34lbmcZfICB4KXJ9T6D4EDxyfWv4EDxyfXF1eXHKv7/KFD+FiAaTiMqh4eHVF1vJgApKXgGmAlHelRne11vGNzGYBLPeBIcGNN2ACETyjQ1KPc1yfvFBmR2AAUg+8HJ+3YABSD7yfXF1eUqEhMLeLEg+OHRwfHJxeUBAKAhAMDNAxThwcnF5XEjBSD74cHJxdXlAQCAIZXKzQMU4dHBycXV5a/qFcuwIAwaEyIaEzIEDXjqFcvlxRq+EyAPIxq+IAkTIw0gCMHhGBkrGyMjBSDmecFPBBoTIhoTIiEVyzThDSDS+hXL4dHBydVfzXIUuzD60cnF9cH6FMrLD6mAR/CLkR+AR/AFqOoUysHJ9cXltxcXF/aA4Ggq4GkFIPo+5OBH4cHxyfXF5bcXFxf2gOBqKuBrBSD6PuTgSOBJ4cHxyT4Q4ADwAC/LN+bwRz4g4ADwAC/mD7DqFsvJzyEAgK8GIE8+CCINIPwFIPnHIQCABiBPIg0g/AUg+cnFzQMVSs0eFcHJxc0RFUjNGRVLzSMVwcnFBgHNKxXBycUGABj2xQYDGPHFBgLNKxXByfXlh4eAJsBvceHxyfXlh4cmwG9GI04jXiNW4fHJ9cXV5eCDKjzK8BPWIF/wg835FF95xghPezwY6PXF1eXF1c13FdHBex4FIS3LGNUBKssR8NjNlRURGPzNlRURnP/NlRUR9v/NlRUR//8+LzwZOPwCA3ovV3svXxMZyTAwRlBT/zAwUE5UU/8wMExJTkVT/xYFB1dFTENPTUUgVE8WBQgtUkVBTFRJTUUtFgAJREVNTyBNQURFIEVTUEVDSUFMTFkWAQpGT1IgTENQJzIwMDAgUEFSVFn/FgAAR1JFRVRJTlg6ICAgICAgICAgICAWAAFEU0MsUEFOLFNBQixGQVRBTElUWRYAAkpFRkYgRlJPSFdFSU4sSUNBUlVTFgADRE9YLFFVQU5HLEFCWVNTICAgICAWAAQgICAgICAgICAgICAgICAgICAgIBYABUNSRURJVFM6ICAgICAgICAgICAgFgAGQUxMIEdGWCZDT0RFIEJZIEFHTyAWAAdIRUxJQ09QVEVSIDNEIE1PREVMIBYACENSRUFURUQgQlkgQlVTWSAgICAgFgAJICAgICAgICAgICAgICAgICAgICAWAApVU0VEIFNPRlRXQVJFOiAgICAgIBYAC1JHQkRTLE5PJENBU0gsRkFSICAgFgAMICAgICAgICAgICAgICAgICAgICAWAA1DT05UQUNUOiAgICAgICAgICAgIBYADkdPQlVaT1ZAWUFIT08uQ09NICAgFgAPSFRUUDovL1NQRUNDWS5EQS5SVSAWABAgICAgICAgICAgICAgICAgICAgIBYAEVNFRSBZT1UgT04gR0JERVYyMDAw/wAAAAAAAAAAAAAAAAAAAAAICBwUHBQ4KDgoMDBwUCAgKCh8VHxUKCgAAAAAAAAAABQUPip/QT4qfFT+gnxUKCgICDw0fkL8rP6Cfmr8hHhYJCR+Wn5SPCR4SPyU/LRISBgYPCR+Wjwkflr8tH5KNDQQEDgocFAgIAAAAAAAAAAABAQOChwUOCg4KDgoHBQICBAQOCgcFBwUHBQ4KHBQICAAABQUPio8NH5CPCx8VCgoAAAICBwUPDR+QjwsOCgQEAAAAAAAAAAAEBA4KHBQcFAAAAAAAAB8fP6CfHwAAAAAAAAAAAAAAAAwMHhIeEgwMAQEDgoeEjwkeEjwkOCgQEAYGDwkflr+qv6q/LR4SDAwGBg8JHxUPDQ4KHxs/oJ8fBwcPiJ+Wjw0eEj8vP6CfHwcHD4iflo8NE5K/LR4SDAwJCR+Wn5afFT8tP6CfGwQEBwcPiJ8XPyEfnr8tHhIMDAYGDwkeFj8pP66/LR4SDAwPDx+Qv66XFQ4KHBQcFAgIBwcPiJ+Wjwkflr8tPiIcHAcHD4iflr+sn5KfHT4iHBwAAAAAAgIHBQICBAQOCgQEAAACAgcFAgIEBA4KDgocFAAAAAAHBQ4KHBQcFA4KAAAAAAAADw8fkJ8fPyEeHgAAAAAAAA4KBwUHBQ4KHBQAAAYGDwkflr8tHhoEBA4KBAQHBw+In5a/rL8pPi4+IhwcBwcPiJ+Wv66/oL+uvy0SEg4OHxEflr8pP6a/LT4iHBwHBw+In5a5qbgoP6y/IxwcDAweEh8VH5a7qr+uvyEeHgcHD4ifFx8RHhY/Lz+gnx8HBw+Inxc/IT4uOCg4KBAQBwcPiJ+Wvy8/qL+uvyEeHgkJH5a/rr+gv66/LT8tEhIPDx+QjwsOChwUHhY/IR4eDw8fkI+Og4KXFT8tHhIMDAkJH5afFR+Qv66/LT8tEhIICBwUHBQ4KDkpP66fEQ4OCgofFR+Qv6q/rr8tPy0SEgkJH5a/pr+qv6y7qr8tEhIHBw+In5a7qruqvy0+IhwcBwcPiJ+Wv66/IT4uOCgQEAcHD4iflr+uv6q/LT+inZ2HBw+In5a/LT4iPy0/LRISBwcPiJ8XP6Cfnr8tPiIcHB8fP6CfGw4KHBQcFBwUCAgJCR+Wn5a7qruqvy0eEgwMERE7qruqnxUfFR4SHBQICAkJH5aflr+uv6q/KR8VCgoJCR+WnxUOCg8JH5a/LRISCQkflr8tPy0eEhwUHBQICA8PH5C/LT46Dwsflr8hHh4HBw+IjwsOChwUHhYfEQ4OEBA4KDwkHhIPCQeEg4KBAQ4OHxEPDQcFDgoeGj4iHBwGBg8JH5a7qpERAAAAAAAAAAAAAAAAAAAAAB8fP6CfHx81rdPfJJne5X1MAIvPEevyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxnLEcsXlDABhMsRyxeUMAGEyxHLF5QwAYTLEcsXlDABhMsRyxeUMAGEyxHLF5QwAYTLEcsXlDABhMsRyxeUMAGEeRcvT/F5MAIvPIVvJrcBAAA+t7zLEbrLED6/vcsRu8sQPj+8P8sRuj/LEL0/yxG7P8sQeLHIeKHAebcgB3xiV31rX3jLH9L/HD5AlU97lW96lPUwAi88R6/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGTABgB/LGcsRyxeVMAGFyxHLF5UwAYXLEcsXlTABhcsRyxeVMAGFyxHLF5UwAYXLEcsXlTABhcsRyxeVMAGFyxHLF5UwAYV5Fy9P8XkwAi88hGcuQMMxHMsf0pcdPkCUT3qUZ3uV9TACLzxHr8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZMAGAH8sZyxHLF5QwAYTLEcsXlDABhMsRyxeUMAGEyxHLF5QwAYTLEcsXlDABhMsRyxeUMAGEyxHLF5QwAYTLEcsXlDABhHkXL0/xeTACLzyFbyZAwzEcyx/SoRt91r9PfZNvepT1MAIvPEevyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxnLEcsXlTABhcsRyxeVMAGFyxHLF5UwAYXLEcsXlTABhcsRyxeVMAGFyxHLF5UwAYXLEcsXlTABhcsRyxeVMAGFeRcvT/F5MAIvPIRnLr/DMRz//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////3q8MAVUZ3tdb3u90pdAfZNPepRfkTA+V3nLPy88g+CDPn+R5YdPbyYARCkpKQkBkVIJweV41kAXb3nWQB8fH+YPZ/CChGd55gcGB/YITwpP8INHLMl5S1+RV3nLPy88g+CDPneR5YdPbyYARCkpKQkBklsJweV41kAXb3nWQB8fH+YPZ/CChGd55gcGB/YITwpP8INHLMmVT3qUX5EwPld5yz8vPIPggz5/keWHT28mAEQpKSkJAR9BCcHleNZAF2951kAfHx/mD2fwgoRneeYHBgf2CE8KT/CDRyzJeUtfkVd5yz8vPIPggz53keWHT28mAEQpKSkJASBKCcHleNZAF2951kAfHx/mD2fwgoRneeYHBgf2CE8KT/CDRyzJfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkfrF3e8t4IAN6LCyAR8sJMAEkyX6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALH6xInvLeCAGessJMAEkgEcALMl+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASV+sXd7y3ggA3osLIBHywEwASXJfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsfrF3e8t4IAZ6ywEwASWARywsyf///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wHRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyLRe7o4A1pXewYHoE8K9XqgTwQK4JF6Hx8f5g9X8JNnTixGLXsfHx/mD1/wgoNne5LRxADB8JGiVy+mX3qhsyJ6L6ZfeqCzItF7ujgDWld7BgegTwr1eqBPBArgkXofHx/mD1fwk2dOLEYtex8fH+YPX/CCg2d7ktHEAMHwkaJXL6ZfeqGzInovpl96oLMi0Xu6OANaV3sGB6BPCvV6oE8ECuCReh8fH+YPV/CTZ04sRi17Hx8f5g9f8IKDZ3uS0cQAwfCRolcvpl96obMiei+mX3qgsyIxDsrh+eEWwxgNIf3Er+oLyuoMyiwsLPCPPcjgj14sGrcqKPDGeeCT+g3Ktygm+gvKPP4DIAI+AeoLyiAH+gzKPOoMyvoMyl8WyvCT1nkSe8bH4JMqTypHKuUmxl+Hh4M8PG8qX1Z5h4eBPDxveE4sh4eARjw8bypmb3y6OAViV31rX3y4OAVgR31pT3q4OAVQR3tZT3iU4JR8h+CV5dXFr+CSzUpifeCS0eHVzUpi0eE+AeCSzUpi8JRfPniTZy5Hr8sdMAGEH8sdMAGEH8sdMAGEH8sdMAGEH8sdMAGEH8sdMAGEH8sdMAGEH8sdMAGEH8sdxkBnCA7KMQDC5fCVb8l7vTBVfZNPepRfkTAkV3nLPy88Rz5/kU3Fh09vJgBEKSkJAfdiCcHlJsLwkm94BoDJeUtfkVd5yz8vPEc+d5FNxYdPbyYARCkpCQH4ZwnB5SbC8JJveAaAyZVPepRfkTAkV3nLPy88Rz5/kU3Fh09vJgBEKSkJAalsCcHlJsLwkm94BoDJeUtfkVd5yz8vPEc+d5FNxYdPbyYARCkpCQGqcQnB5SbC8JJveAaAyYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNg7gwBZOCcSwsDYO4MAWTgnEsLA2DuDAFk4JxLCwNyXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDXEsLIO4MAOTgg1xLCyDuDADk4INcSwsg7gwA5OCDcmDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDIO4MAWTgnEsLAyDuDAFk4JxLCwMg7gwBZOCcSwsDMlxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggxxLCyDuDADk4IMcSwsg7gwA5OCDHEsLIO4MAOTggzJxg+Hh+oawXovpl96obMiei+mX3qgszIkeRgAInAtJCJwLSQicC0kInAtJCJwLSQicC0kInAtJCJwLSQicC0kInAtJCJwLSQicC0kInAtJCJwLSQW/8n///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+qqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVACEzDDPAABIAEjPAMwwAIQAhMwwzwAASABIzwDMMACEAITMMM8AAEgASM8AzDAAhACEzDDPAABIAEjPAMwwAIQAhMwwzwAASABIzwDMMACEAITMMM8AAEgASM8AzDAAhACEzDDPAABIAEjPAMwwAIQAhMwwzwAASABIzwDMMACEAITMMM8AAEgASM8AzDAAhACEzDDPAABIAEjPAMwwAIQAhMwwzwAASABIzwDMMACEAITMMM8AAEgASM8AzDAAhACEzDDPAABIAEjPAMwwAIQAhMwwzwAASABIzwDMMACEAITMMM8AAEgASM8AzDAAhACEzDDPAABIAEjPAMwwAIQj8GH4y/WT7wO+B50CzINkI/Bh+Mv1k+8DvgedAsyDZCPwYfjL9ZPvA74HnQLMg2Qj8GH4y/WT7wO+B50CzINkI/Bh+Mv1k+8DvgedAsyDZCPwYfjL9ZPvA74HnQLMg2Qj8GH4y/WT7wO+B50CzINkI/Bh+Mv1k+8DvgedAsyDZCPwYfjL9ZPvA74HnQLMg2Qj8GH4y/WT7wO+B50CzINkI/Bh+Mv1k+8DvgedAsyDZCPwYfjL9ZPvA74HnQLMg2Qj8GH4y/WT7wO+B50CzINkI/Bh+Mv1k+8DvgedAsyDZCPwYfjL9ZPvA74HnQLMg2Qj8GH4y/WT7wO+B50CzINnMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzzMzMzDMzMzPMzMzMMzMzM8zMzMwzMzMzwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDMDAwMAMDAwMwMDAwAwMDAzAwMDADAwMDPHxAQEBAQEBHx8QEBAQEBDx8QEBAQEBAR8fEBAQEBAQ8fEBAQEBAQEfHxAQEBAQEPHxAQEBAQEBHx8QEBAQEBDx8QEBAQEBAR8fEBAQEBAQ8fEBAQEBAQEfHxAQEBAQEPHxAQEBAQEBHx8QEBAQEBDx8QEBAQEBAR8fEBAQEBAQ8fEBAQEBAQEfHxAQEBAQEPHxAQEBAQEBHx8QEBAQEBDx8QEBAQEBAR8fEBAQEBAQ8fEBAQEBAQEfHxAQEBAQEPHxAQEBAQEBHx8QEBAQEBDx8QEBAQEBAR8fEBAQEBAQ8fEBAQEBAQEfHxAQEBAQEPHxAQEBAQEBHx8QEBAQEBCqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlVVqqpVVaqqVVWqqlUC4XIscAl7InAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJLCwly2XIJGjJycnJyeEicAlyLHAJeyJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSwsJctlyCRoycnJycnhInAJInAJcixwCXsicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCXLZcgkaMnJycnJ4SJwCSJwCSJwCXIscAl7InAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJLCwly2XIJGjJycnJyeEicAkicAkicAkicAlyLHAJeyJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSwsJctlyCRoycnJycnhInAJInAJInAJInAJInAJcixwCXsicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCXLZcgkaMnJycnJ4SJwCSJwCSJwCSJwCSJwCSJwCXIscAl7InAJInAJInAJInAJInAJInAJInAJInAJInAJLCwly2XIJGjJycnJyeEicAkicAkicAkicAkicAkicAkicAlyLHAJeyJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSwsJctlyCRoycnJycnhInAJInAJInAJInAJInAJInAJInAJInAJcixwCXsicAkicAkicAkicAkicAkicAkicAksLCXLZcgkaMnJycnJ4SJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCXIscAl7InAJInAJInAJInAJInAJInAJLCwly2XIJGjJycnJyeEicAkicAkicAkicAkicAkicAkicAkicAkicAkicAlyLHAJeyJwCSJwCSJwCSJwCSJwCSwsJctlyCRoycnJycnhInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJcixwCXsicAkicAkicAkicAksLCXLZcgkaMnJycnJ4SJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCXIscAl7InAJInAJInAJLCwly2XIJGjJycnJyeEicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAlyLHAJeyJwCSJwCSwsJctlyCRoycnJycnhInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJInAJcixwCXsicAksLCXLZcgkaMnJycnJ4SJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCSJwCXIscAl7LCwly2XIJGjJycnJydE+t5LI4IXmB8RSRPCFHx8focjlzTJE4XkicCwicCwicCwicCwicCwicCwicCwicCzJ+ABUXWhHeZAfyx1nATNZCfCCMQCv/qAoAzEAvwH/AOlHPgeQVF1HDjOvyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxkwAYAfyxlHIbRXCeViaz7/AQ8Ayfoay2/6G8uFZ/4UIAU+/y0YBtbsIAU8LOoby3zqGsvNr2AhlEbNyhDwpMagV/Cjxn9f1SGXRs3KEPCkxqBn8KPGf2/RzTEcKAsf2hhZH9oYWcPERny6OAViV31rX+XNmkbh1Xu90sxFe9ZA4Ih9k0884Il6lF/ghjzgij2RMGvgh3nLPy88g+CF8IIBDwBvVHzWQBfLN6GFZ3rmBxdvGAjwij3KAETgivCJX/CGV/CFGASCHSgLy38g+Ffwh4LghR3NYkUY2nvgifCIg1/l5gf2CG8mB1Z7aB8fHx/LHR/LHeYDxkBnrx7/6XnghpPgh3vLPy88geCF8IIBDwBvVHzWQBfLN6GFZ3rmBxdv8Ilf8IZX8IXLfyAHV/CHgh0YAYLghc1iRfCKPcoAROCKGN171kDgiHuVTzzgiXqUX+CGPOCKPZEwa+CHecs/LzyD4IXwggEPAG9UfNZAF8s3oYVneuYHF28YCPCKPcoAROCK8Ilf8IZX8IUYBIIdKAvLfyD4V/CHguCFHc0qRhjae+CJ8IiTX+XmB/YQbyYHVntoHx8fH8sdH8sd5gPGQGc+/1jpeeCGk+CHe8s/LzyB4IXwggEPAG9UfNZAF8s3oYVneuYHF2/wiV/whlfwhct/IAdX8IeCHRgBguCFzSpG8Io9ygBE4IoY3UYAALoAAHzWQMhPHx8f5h9HeeYHKAsE/gUwBvUhylblBT4PkCHJRoRn5fCCZ69vyfCCZ69vIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIsnxAQ8APcqEVz0odj0oOj0idwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwksLCXLZSgCJGgidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwksLCXLZSgCJGgidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwksLCXLZSgCJGgidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkidwkid8kicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAksLCUicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAkicAloyfgAVF3wgjEAr/6gKAMxAL8B/wDFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcVia/nJJgJ+4JovPOCYfcZAb37gl+Cbr+CZ4JzgneCePkDgn8n/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Aw==';
   11107 
   11108 // End of realtime.js file.
   11109