diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 0000000..1f84612 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,5 @@ +;;; Directory Local Variables +;;; For more information see (info "(emacs) Directory Variables") + +((js-mode + (js2-basic-offset . 2))) diff --git a/README.md b/README.md new file mode 100644 index 0000000..4652136 --- /dev/null +++ b/README.md @@ -0,0 +1,154 @@ +# Name # + +js-emulators + +# Synopsis # + +The goal of this little project is to make it easy to embed a +javascript-based emulator in your own webpage. It downloads the files +you specify (with aprogress ui to show what is happening), arranges +them to form a filesystem, constructs the necessary arguments for the +emulator, handles transitions to and from full-screen mode, and +detects and enables game pads. + +To use this project you'll need to provide it with a canvas element, +styled as necessary so that it has the correct size on screen (the +program will be scaled up automatically to fit, controlling for aspect +ratio). You will also likely want to provide a simple UI for entering +full-screen mode or muting the audio; these can simply call methods on +the emulator when activated. + +# Emulator API # + +The `Emulator` constructor takes three arguments: a canvas element, an +optional callback (which will be called after fully initializing the +emulator but just before it starts running the emulated program), and +a config (as detailed below) or a function which returns a `Promise` +of a config. + +# Configuration # + +## Examples ## + +### Arcade game ### + +Loads the emulator for the arcade game 1943, and gives it a compressed +copy of the rom (which it loads from examples/1943.zip). + + var emulator = new Emulator(document.querySelector("#canvas"), + null, + new JSMAMELoader(JSMAMELoader.driver("1943"), + JSMAMELoader.nativeResolution(224, 256), + JSMAMELoader.emulatorJS("emulators/mess1943.js"), + JSMAMELoader.mountFile("1943.zip", + JSMAMELoader.fetchFile("Game File", + "examples/1943.zip")))) + emulator.setScale(3); + emulator.start({ waitAfterDownloading: true }); + +### Console game for Atari 2600 ### + +Loads the emulator for the Atari 2600 console, and an image of a +catridge for Pitfall. Notice how we download the image, storing it in +a file, then set up a "cart" peripheral so that the emulator can find +it. We also load a configuration file that preconfigures some +keybindings needed to use the 2600. + + var emulator = new Emulator(document.querySelector("#canvas"), + null, + new JSMESSLoader(JSMESSLoader.driver("a2600"), + JSMESSLoader.nativeResolution(352, 223), + JSMESSLoader.emulatorJS("emulators/messa2600.js"), + JSMESSLoader.mountFile("Pitfall_Activision_1982.bin", + JSMESSLoader.fetchFile("Game File", + "examples/Pitfall_Activision_1982.bin")), + JSMESSLoader.mountFile("a2600.cfg", + JSMESSLoader.fetchFile("Config File", + "examples/a2600.cfg")), + JSMESSLoader.peripheral("cart", "Pitfall_Activision_1982.bin"))) + emulator.setScale(3).start({ waitAfterDownloading: true }); + +### DOS game ### + +Here we load the dosbox emulator, and a zip file containing the game +ZZT which we decompress and then mount as the C drive. We also tell +DosBox to immediately start running zzt.exe, which is inside the zip. + + var emulator = new Emulator(document.querySelector("#canvas"), + null, + new DosBoxLoader(DosBoxLoader.emulatorJS("emulators/dosbox.js"), + DosBoxLoader.nativeResolution(640, 400), + DosBoxLoader.mountZip("c", + DosBoxLoader.fetchFile("Game File", + "examples/Zzt_1991_Epic_Megagames_Inc.zip")), + DosBoxLoader.startExe("zzt.exe"))) + emulator.start({ waitAfterDownloading: true }); + +## Configuration API ## + +Currently there are two supported emulators, JSMESS and +EM-DosBox. JSMESS provides emulation for arcade games, consoles, and +early personal computers. As this emulator supports such a wide +variety of hardware it has been broken up into several dozen emulators +each supporting one machine lest the resulting javascript be +intractably large (60+ megabytes). EM-DosBox provides emulation for +software that runs on x86 PCs using the DOS operating systems common +to the era. + +Each of these is configured by calling a constructor function and +providing it with arguments formed by calling static methods on that +same constructor. + +### Common ### + +* `emulatorJS(url)` +* `mountZip(drive, file)` +* `mountFile(filename, file)` +* `fetchFile(url)` +* `fetchOptionalFile(url)` +* `localFile(data)` + +### JSMESS ### + +* `driver(driverName)` +* `extraArgs(args)` +* `peripheral(name, filename)` + +### JSMAME ### + +* `driver(driverName)` +* `extraArgs(args)` + +### EM-DosBox ### + +* `startExe(filename)` + +## Internet Archive ## + +There's also a helper for loading software from +[the Internet Archive](https://archive.org/v2), `IALoader`. IALoader +looks at the metadata associated with an Internet Archive item and +uses that to build the configuration for the emulator. + +## Examples ## + + var emulator = new IALoader(document.querySelector("#canvas"), + "Pitfall_Activision_1982/Pitfall_Activision_1982.bin"); + +# Runtime API # + +Once you have an emulator object, there are several methods you can call. + +* `start()` +* `requestFullScreen()` +* `mute()` +* `setSplashColors()` +* others… + +# Known Bugs # + +* splash screen doesn't always fit inside the canvas +* need to improve the download progress indicators +* browser feature detection for volume/mute/full-screen +* handling of aspect ratios, and their interaction with full-screen mode +* finish API for volume/mute/full-screen requests diff --git a/browserfs.js b/browserfs.js new file mode 100644 index 0000000..eacbb24 --- /dev/null +++ b/browserfs.js @@ -0,0 +1,5 @@ +!function(){if(Date.now||(Date.now=function(){return(new Date).getTime()}),Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)}),Object.keys||(Object.keys=function(){var t=Object.prototype.hasOwnProperty,e=!{toString:null}.propertyIsEnumerable("toString"),n=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],r=n.length;return function(i){if("object"!=typeof i&&("function"!=typeof i||null===i))throw new TypeError("Object.keys called on non-object");var o,a,s=[];for(o in i)t.call(i,o)&&s.push(o);if(e)for(a=0;r>a;a++)t.call(i,n[a])&&s.push(n[a]);return s}}()),"b"!=="ab".substr(-1)&&(String.prototype.substr=function(t){return function(e,n){return 0>e&&(e=this.length+e),t.call(this,e,n)}}(String.prototype.substr)),Array.prototype.forEach||(Array.prototype.forEach=function(t,e){for(var n=0;n0)){var r=e.shift();return r()}};t.addEventListener?t.addEventListener("message",i,!0):t.attachEvent("onmessage",i)}else if(t.MessageChannel){var o=new t.MessageChannel;o.port1.onmessage=function(){return e.length>0?e.shift()():void 0},t.setImmediate=function(t){e.push(t),o.port2.postMessage("")}}else t.setImmediate=function(t){return setTimeout(t,0)}}Array.prototype.indexOf||(Array.prototype.indexOf=function(t,e){if("undefined"==typeof e&&(e=0),!this)throw new TypeError;var n=this.length;if(0===n||r>=n)return-1;var r=e;0>r&&(r=n+r);for(var i=r;n>i;i++)if(this[i]===t)return i;return-1}),Array.prototype.forEach||(Array.prototype.forEach=function(t,e){var n,r;for(n=0,r=this.length;r>n;++n)n in this&&t.call(e,this[n],n,this)}),Array.prototype.map||(Array.prototype.map=function(t,e){var n,r,i;if(null==this)throw new TypeError(" this is null or not defined");var o=Object(this),a=o.length>>>0;if("function"!=typeof t)throw new TypeError(t+" is not a function");for(e&&(n=e),r=new Array(a),i=0;a>i;){var s,u;i in o&&(s=o[i],u=t.call(n,s,i,o),r[i]=u),i++}return r}),"undefined"!=typeof document&&void 0===window.chrome&&document.write("\r\n\r\n");var a,s,u;!function(t){function e(t,e){return b.call(t,e)}function n(t,e){var n,r,i,o,a,s,u,f,c,p,h,l=e&&e.split("/"),d=m.map,y=d&&d["*"]||{};if(t&&"."===t.charAt(0))if(e){for(l=l.slice(0,l.length-1),t=t.split("/"),a=t.length-1,m.nodeIdCompat&&S.test(t[a])&&(t[a]=t[a].replace(S,"")),t=l.concat(t),c=0;c0&&(t.splice(c-1,2),c-=2)}t=t.join("/")}else 0===t.indexOf("./")&&(t=t.substring(2));if((l||y)&&d){for(n=t.split("/"),c=n.length;c>0;c-=1){if(r=n.slice(0,c).join("/"),l)for(p=l.length;p>0;p-=1)if(i=d[l.slice(0,p).join("/")],i&&(i=i[r])){o=i,s=c;break}if(o)break;!u&&y&&y[r]&&(u=y[r],f=c)}!o&&u&&(o=u,s=f),o&&(n.splice(0,s,o),t=n.join("/"))}return t}function r(e,n){return function(){var r=E.call(arguments,0);return"string"!=typeof r[0]&&1===r.length&&r.push(null),l.apply(t,r.concat([e,n]))}}function i(t){return function(e){return n(e,t)}}function o(t){return function(e){g[t]=e}}function f(n){if(e(w,n)){var r=w[n];delete w[n],v[n]=!0,h.apply(t,r)}if(!e(g,n)&&!e(v,n))throw new Error("No "+n);return g[n]}function c(t){var e,n=t?t.indexOf("!"):-1;return n>-1&&(e=t.substring(0,n),t=t.substring(n+1,t.length)),[e,t]}function p(t){return function(){return m&&m.config&&m.config[t]||{}}}var h,l,d,y,g={},w={},m={},v={},b=Object.prototype.hasOwnProperty,E=[].slice,S=/\.js$/;d=function(t,e){var r,o=c(t),a=o[0];return t=o[1],a&&(a=n(a,e),r=f(a)),a?t=r&&r.normalize?r.normalize(t,i(e)):n(t,e):(t=n(t,e),o=c(t),a=o[0],t=o[1],a&&(r=f(a))),{f:a?a+"!"+t:t,n:t,pr:a,p:r}},y={require:function(t){return r(t)},exports:function(t){var e=g[t];return"undefined"!=typeof e?e:g[t]={}},module:function(t){return{id:t,uri:"",exports:g[t],config:p(t)}}},h=function(n,i,a,s){var u,c,p,h,l,m,b=[],E=typeof a;if(s=s||n,"undefined"===E||"function"===E){for(i=!i.length&&a.length?["require","exports","module"]:i,l=0;l>>24)},t.prototype.writeInt16LE=function(t,e){this.writeUInt8(t,255&e),this.writeUInt8(t+1,255&e>>>8|(2147483648&e)>>>24)},t.prototype.writeInt16BE=function(t,e){this.writeUInt8(t+1,255&e),this.writeUInt8(t,255&e>>>8|(2147483648&e)>>>24)},t.prototype.writeInt32LE=function(t,e){this.writeUInt8(t,255&e),this.writeUInt8(t+1,255&e>>>8),this.writeUInt8(t+2,255&e>>>16),this.writeUInt8(t+3,255&e>>>24)},t.prototype.writeInt32BE=function(t,e){this.writeUInt8(t+3,255&e),this.writeUInt8(t+2,255&e>>>8),this.writeUInt8(t+1,255&e>>>16),this.writeUInt8(t,255&e>>>24)},t.prototype.writeUInt8=function(){throw new n.ApiError(14,"BufferCore implementations should implement writeUInt8.")},t.prototype.writeUInt16LE=function(t,e){this.writeUInt8(t,255&e),this.writeUInt8(t+1,255&e>>8)},t.prototype.writeUInt16BE=function(t,e){this.writeUInt8(t+1,255&e),this.writeUInt8(t,255&e>>8)},t.prototype.writeUInt32LE=function(t,e){this.writeInt32LE(t,0|e)},t.prototype.writeUInt32BE=function(t,e){this.writeInt32BE(t,0|e)},t.prototype.writeFloatLE=function(t,e){this.writeInt32LE(t,this.float2intbits(e))},t.prototype.writeFloatBE=function(t,e){this.writeInt32BE(t,this.float2intbits(e))},t.prototype.writeDoubleLE=function(t,e){var n=this.double2longbits(e);this.writeInt32LE(t,n[0]),this.writeInt32LE(t+4,n[1])},t.prototype.writeDoubleBE=function(t,e){var n=this.double2longbits(e);this.writeInt32BE(t+4,n[0]),this.writeInt32BE(t,n[1])},t.prototype.readInt8=function(t){var e=this.readUInt8(t);return 128&e?4294967168|e:e},t.prototype.readInt16LE=function(t){var e=this.readUInt16LE(t);return 32768&e?4294934528|e:e},t.prototype.readInt16BE=function(t){var e=this.readUInt16BE(t);return 32768&e?4294934528|e:e},t.prototype.readInt32LE=function(t){return 0|this.readUInt32LE(t)},t.prototype.readInt32BE=function(t){return 0|this.readUInt32BE(t)},t.prototype.readUInt8=function(){throw new n.ApiError(14,"BufferCore implementations should implement readUInt8.")},t.prototype.readUInt16LE=function(t){return this.readUInt8(t+1)<<8|this.readUInt8(t)},t.prototype.readUInt16BE=function(t){return this.readUInt8(t)<<8|this.readUInt8(t+1)},t.prototype.readUInt32LE=function(t){return(this.readUInt8(t+3)<<24|this.readUInt8(t+2)<<16|this.readUInt8(t+1)<<8|this.readUInt8(t))>>>0},t.prototype.readUInt32BE=function(t){return(this.readUInt8(t)<<24|this.readUInt8(t+1)<<16|this.readUInt8(t+2)<<8|this.readUInt8(t+3))>>>0},t.prototype.readFloatLE=function(t){return this.intbits2float(this.readInt32LE(t))},t.prototype.readFloatBE=function(t){return this.intbits2float(this.readInt32BE(t))},t.prototype.readDoubleLE=function(t){return this.longbits2double(this.readInt32LE(t+4),this.readInt32LE(t))},t.prototype.readDoubleBE=function(t){return this.longbits2double(this.readInt32BE(t),this.readInt32BE(t+4))},t.prototype.copy=function(){throw new n.ApiError(14,"BufferCore implementations should implement copy.")},t.prototype.fill=function(t,e,n){for(var r=e;n>r;r++)this.writeUInt8(r,t)},t.prototype.float2intbits=function(t){var e,n,r;return 0===t?0:t===Number.POSITIVE_INFINITY?o:t===Number.NEGATIVE_INFINITY?a:isNaN(t)?s:(r=0>t?1:0,t=Math.abs(t),1.1754942106924411e-38>=t&&t>=1.401298464324817e-45?(e=0,n=Math.round(t/Math.pow(2,-126)*Math.pow(2,23)),r<<31|e<<23|n):(e=Math.floor(Math.log(t)/Math.LN2),n=Math.round((t/Math.pow(2,e)-1)*Math.pow(2,23)),r<<31|e+127<<23|n))},t.prototype.double2longbits=function(t){var e,n,r,i;return 0===t?[0,0]:t===Number.POSITIVE_INFINITY?[0,2146435072]:t===Number.NEGATIVE_INFINITY?[0,-1048576]:isNaN(t)?[0,2146959360]:(i=0>t?1<<31:0,t=Math.abs(t),2.225073858507201e-308>=t&&t>=5e-324?(e=0,r=t/Math.pow(2,-1022)*Math.pow(2,52)):(e=Math.floor(Math.log(t)/Math.LN2),t>>31,s=(2139095040&t)>>>23,u=8388607&t;return e=0===s?Math.pow(-1,n)*u*Math.pow(2,-149):Math.pow(-1,n)*(1+u*Math.pow(2,-23))*Math.pow(2,s-127),(i>e||e>r)&&(e=0/0),e},t.prototype.longbits2double=function(t,e){var n=(2147483648&t)>>>31,r=(2146435072&t)>>>20,i=(1048575&t)*Math.pow(2,32)+e;return 0===r&&0===i?0:2047===r?0===i?1===n?Number.NEGATIVE_INFINITY:Number.POSITIVE_INFINITY:0/0:0===r?Math.pow(-1,n)*i*Math.pow(2,-1074):Math.pow(-1,n)*(1+i*Math.pow(2,-52))*Math.pow(2,r-1023)},t}();e.BufferCoreCommon=u});var f=this.__extends||function(t,e){function n(){this.constructor=t}for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);n.prototype=e.prototype,t.prototype=new n};u("core/buffer_core_array",["require","exports","./buffer_core"],function(t,e,n){var r=[4294967040,4294902015,4278255615,16777215],i=function(t){function e(e){t.call(this),this.length=e,this.buff=new Array(Math.ceil(e/4));for(var n=this.buff.length,r=0;n>r;r++)this.buff[r]=0}return f(e,t),e.isAvailable=function(){return!0},e.prototype.getLength=function(){return this.length},e.prototype.writeUInt8=function(t,e){e&=255;var n=t>>2,i=3&t;this.buff[n]=this.buff[n]&r[i],this.buff[n]=this.buff[n]|e<<(i<<3)},e.prototype.readUInt8=function(t){var e=t>>2,n=3&t;return 255&this.buff[e]>>(n<<3)},e.prototype.copy=function(t,n){for(var r=new e(n-t),i=t;n>i;i++)r.writeUInt8(i-t,this.readUInt8(i));return r},e}(n.BufferCoreCommon);e.BufferCoreArray=i});var f=this.__extends||function(t,e){function n(){this.constructor=t}for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);n.prototype=e.prototype,t.prototype=new n};u("core/buffer_core_arraybuffer",["require","exports","./buffer_core"],function(t,e,n){var r=function(t){function e(e){t.call(this),this.buff="number"==typeof e?new DataView(new ArrayBuffer(e)):e instanceof DataView?e:new DataView(e),this.length=this.buff.byteLength}return f(e,t),e.isAvailable=function(){return"undefined"!=typeof DataView},e.prototype.getLength=function(){return this.length},e.prototype.writeInt8=function(t,e){this.buff.setInt8(t,e)},e.prototype.writeInt16LE=function(t,e){this.buff.setInt16(t,e,!0)},e.prototype.writeInt16BE=function(t,e){this.buff.setInt16(t,e,!1)},e.prototype.writeInt32LE=function(t,e){this.buff.setInt32(t,e,!0)},e.prototype.writeInt32BE=function(t,e){this.buff.setInt32(t,e,!1)},e.prototype.writeUInt8=function(t,e){this.buff.setUint8(t,e)},e.prototype.writeUInt16LE=function(t,e){this.buff.setUint16(t,e,!0)},e.prototype.writeUInt16BE=function(t,e){this.buff.setUint16(t,e,!1)},e.prototype.writeUInt32LE=function(t,e){this.buff.setUint32(t,e,!0)},e.prototype.writeUInt32BE=function(t,e){this.buff.setUint32(t,e,!1)},e.prototype.writeFloatLE=function(t,e){this.buff.setFloat32(t,e,!0)},e.prototype.writeFloatBE=function(t,e){this.buff.setFloat32(t,e,!1)},e.prototype.writeDoubleLE=function(t,e){this.buff.setFloat64(t,e,!0)},e.prototype.writeDoubleBE=function(t,e){this.buff.setFloat64(t,e,!1)},e.prototype.readInt8=function(t){return this.buff.getInt8(t)},e.prototype.readInt16LE=function(t){return this.buff.getInt16(t,!0)},e.prototype.readInt16BE=function(t){return this.buff.getInt16(t,!1)},e.prototype.readInt32LE=function(t){return this.buff.getInt32(t,!0)},e.prototype.readInt32BE=function(t){return this.buff.getInt32(t,!1)},e.prototype.readUInt8=function(t){return this.buff.getUint8(t)},e.prototype.readUInt16LE=function(t){return this.buff.getUint16(t,!0)},e.prototype.readUInt16BE=function(t){return this.buff.getUint16(t,!1)},e.prototype.readUInt32LE=function(t){return this.buff.getUint32(t,!0)},e.prototype.readUInt32BE=function(t){return this.buff.getUint32(t,!1)},e.prototype.readFloatLE=function(t){return this.buff.getFloat32(t,!0)},e.prototype.readFloatBE=function(t){return this.buff.getFloat32(t,!1)},e.prototype.readDoubleLE=function(t){return this.buff.getFloat64(t,!0)},e.prototype.readDoubleBE=function(t){return this.buff.getFloat64(t,!1)},e.prototype.copy=function(t,n){var r,i=this.buff.buffer;if(ArrayBuffer.prototype.slice)r=i.slice(t,n);else{var o=n-t;r=new ArrayBuffer(o);var a=new Uint8Array(r),s=new Uint8Array(i);a.set(s.subarray(t,n))}return new e(r)},e.prototype.fill=function(t,e,n){t=255&t;var r,i=n-e,o=4*(0|i/4),a=t<<24|t<<16|t<<8|t;for(r=0;o>r;r+=4)this.writeInt32LE(r+e,a);for(r=o;i>r;r++)this.writeUInt8(r+e,t)},e.prototype.getDataView=function(){return this.buff},e}(n.BufferCoreCommon);e.BufferCoreArrayBuffer=r});var f=this.__extends||function(t,e){function n(){this.constructor=t}for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);n.prototype=e.prototype,t.prototype=new n};u("core/buffer_core_imagedata",["require","exports","./buffer_core"],function(t,e,n){var r=function(t){function e(n){t.call(this),this.length=n,this.buff=e.getCanvasPixelArray(n)}return f(e,t),e.getCanvasPixelArray=function(t){var n=e.imageDataFactory;return void 0===n&&(e.imageDataFactory=n=document.createElement("canvas").getContext("2d")),0===t&&(t=1),n.createImageData(Math.ceil(t/4),1).data},e.isAvailable=function(){return"undefined"!=typeof CanvasPixelArray},e.prototype.getLength=function(){return this.length},e.prototype.writeUInt8=function(t,e){this.buff[t]=e},e.prototype.readUInt8=function(t){return this.buff[t]},e.prototype.copy=function(t,n){for(var r=new e(n-t),i=t;n>i;i++)r.writeUInt8(i-t,this.buff[i]);return r},e}(n.BufferCoreCommon);e.BufferCoreImageData=r}),u("core/string_util",["require","exports"],function(t,e){function n(t){switch(t=function(){switch(typeof t){case"object":return""+t;case"string":return t;default:throw new Error("Invalid encoding argument specified")}}(),t=t.toLowerCase()){case"utf8":case"utf-8":return r;case"ascii":return i;case"binary":return a;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return u;case"hex":return f;case"base64":return s;case"binary_string":return c;case"binary_string_ie":return p;case"extended_ascii":return o;default:throw new Error("Unknown encoding: "+t)}}e.FindUtil=n;var r=function(){function t(){}return t.str2byte=function(t,e){for(var n=e.length,r=0,i=0,o=n,a=0;ri;){var s=t.charCodeAt(r++),u=t.charCodeAt(r);if(s>=55296&&56319>=s&&u>=56320&&57343>=u){if(i+3>=o)break;a++;var f=(1024|1023&s)<<10|1023&u;e.writeUInt8(240|f>>18,i++),e.writeUInt8(128|63&f>>12,i++),e.writeUInt8(128|63&f>>6,i++),e.writeUInt8(128|63&f,i++),r++}else if(128>s)e.writeUInt8(s,i++),a++;else if(2048>s){if(i+1>=o)break;a++,e.writeUInt8(192|s>>6,i++),e.writeUInt8(128|63&s,i++)}else if(65536>s){if(i+2>=o)break;a++,e.writeUInt8(224|s>>12,i++),e.writeUInt8(128|63&s>>6,i++),e.writeUInt8(128|63&s,i++)}}return i},t.byte2str=function(t){for(var e=[],n=0;nr)e.push(String.fromCharCode(r));else{if(192>r)throw new Error("Found incomplete part of character in string.");if(224>r)e.push(String.fromCharCode((31&r)<<6|63&t.readUInt8(n++)));else if(240>r)e.push(String.fromCharCode((15&r)<<12|(63&t.readUInt8(n++))<<6|63&t.readUInt8(n++)));else{if(!(248>r))throw new Error("Unable to represent UTF-8 string as UTF-16 JavaScript string.");var i=t.readUInt8(n+2);e.push(String.fromCharCode(55296|1023&((7&r)<<8|(63&t.readUInt8(n++))<<2|(63&t.readUInt8(n++))>>4))),e.push(String.fromCharCode(56320|((15&i)<<6|63&t.readUInt8(n++))))}}}return e.join("")},t.byteLength=function(t){var e=encodeURIComponent(t).match(/%[89ABab]/g);return t.length+(e?e.length:0)},t}();e.UTF8=r;var i=function(){function t(){}return t.str2byte=function(t,e){for(var n=t.length>e.length?e.length:t.length,r=0;n>r;r++)e.writeUInt8(t.charCodeAt(r)%256,r);return n},t.byte2str=function(t){for(var e=new Array(t.length),n=0;nn.length?n.length:e.length,i=0;r>i;i++){var o=e.charCodeAt(i);if(o>127){var a=t.extendedChars.indexOf(e.charAt(i));a>-1&&(o=a+128)}n.writeUInt8(o,i)}return r},t.byte2str=function(e){for(var n=new Array(e.length),r=0;r127?t.extendedChars[i-128]:String.fromCharCode(i)}return n.join("")},t.byteLength=function(t){return t.length},t.extendedChars=["Ç","ü","é","â","ä","à","å","ç","ê","ë","è","ï","î","ì","Ä","Å","É","æ","Æ","ô","ö","ò","û","ù","ÿ","Ö","Ü","ø","£","Ø","×","ƒ","á","í","ó","ú","ñ","Ñ","ª","º","¿","®","¬","½","¼","¡","«","»","_","_","_","¦","¦","Á","Â","À","©","¦","¦","+","+","¢","¥","+","+","-","-","+","-","+","ã","Ã","+","+","-","-","¦","-","+","¤","ð","Ð","Ê","Ë","È","i","Í","Î","Ï","+","+","_","_","¦","Ì","_","Ó","ß","Ô","Ò","õ","Õ","µ","þ","Þ","Ú","Û","Ù","ý","Ý","¯","´","­","±","_","¾","¶","§","÷","¸","°","¨","·","¹","³","²","_"," "],t}();e.ExtendedASCII=o;var a=function(){function t(){}return t.str2byte=function(t,e){for(var n=t.length>e.length?e.length:t.length,r=0;n>r;r++)e.writeUInt8(255&t.charCodeAt(r),r);return n},t.byte2str=function(t){for(var e=new Array(t.length),n=0;n>2,u=(3&i)<<4|o>>4,f=(15&o)<<2|a>>6,c=63&a;isNaN(o)?f=c=64:isNaN(a)&&(c=64),n=n+t.num2b64[s]+t.num2b64[u]+t.num2b64[f]+t.num2b64[c]}return n},t.str2byte=function(e,n){var r=n.length,i="",o=0;e=e.replace(/[^A-Za-z0-9\+\/\=\-\_]/g,"");for(var a=0;o>4,h=(15&u)<<4|f>>2,l=(3&f)<<6|c;if(n.writeUInt8(p,a++),a===r)break;if(64!==f&&(i+=n.writeUInt8(h,a++)),a===r)break;if(64!==c&&(i+=n.writeUInt8(l,a++)),a===r)break}return a},t.byteLength=function(t){return Math.floor(6*t.replace(/[^A-Za-z0-9\+\/\-\_]/g,"").length/8)},t.b64chars=["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","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","0","1","2","3","4","5","6","7","8","9","+","/","="],t.num2b64=function(){for(var e=new Array(t.b64chars.length),n=0;ne.length&&(n=1===e.length%2?(e.length-1)/2:e.length/2);for(var r=0;n>r;r++)e.writeUInt16LE(t.charCodeAt(r),2*r);return 2*n},t.byte2str=function(t){if(0!==t.length%2)throw new Error("Invalid UCS2 byte array.");for(var e=new Array(t.length/2),n=0;n>1;n>e.length&&(n=e.length);for(var r=0;n>r;r++){var i=this.hex2num[t.charAt(r<<1)],o=this.hex2num[t.charAt((r<<1)+1)];e.writeUInt8(i<<4|o,r)}return n},t.byte2str=function(t){for(var e=t.length,n=new Array(e<<1),r=0,i=0;e>i;i++){var o=15&t.readUInt8(i),a=t.readUInt8(i)>>4;n[r++]=this.num2hex[a],n[r++]=this.num2hex[o]}return n.join("")},t.byteLength=function(t){return t.length>>1},t.HEXCHARS="0123456789abcdef",t.num2hex=function(){for(var e=new Array(t.HEXCHARS.length),n=0;nn.length&&(r=n.length);var i=0,o=0,a=o+r,s=e.charCodeAt(i++);0!==s&&(n.writeUInt8(255&s,0),o=1);for(var u=o;a>u;u+=2){var f=e.charCodeAt(i++);1===a-u&&n.writeUInt8(f>>8,u),a-u>=2&&n.writeUInt16BE(f,u)}return r},t.byte2str=function(t){var e=t.length;if(0===e)return"";for(var n=new Array((e>>1)+1),r=0,i=0;ie.length?e.length:t.length,r=0;n>r;r++)e.writeUInt8(t.charCodeAt(r)-32,r);return n},t.byte2str=function(t){for(var e=new Array(t.length),n=0;n>>0)throw new TypeError("Buffer size must be a uint32.");this.length=e,this.data=new u(e)}else if("undefined"!=typeof DataView&&e instanceof DataView)this.data=new i.BufferCoreArrayBuffer(e),this.length=e.byteLength;else if("undefined"!=typeof ArrayBuffer&&e instanceof ArrayBuffer)this.data=new i.BufferCoreArrayBuffer(e),this.length=e.byteLength;else if(e instanceof t){var c=e;this.data=new u(e.length),this.length=e.length,c.copy(this)}else if(Array.isArray(e)||null!=e&&"object"==typeof e&&"number"==typeof e[0]){for(this.data=new u(e.length),a=0;ae?this.writeInt8(e,t):this.writeUInt8(e,t)},t.prototype.get=function(t){return this.readUInt8(t)},t.prototype.write=function(e,n,r,i){if("undefined"==typeof n&&(n=0),"undefined"==typeof r&&(r=this.length),"undefined"==typeof i&&(i="utf8"),"string"==typeof n?(i=""+n,n=0,r=this.length):"string"==typeof r&&(i=""+r,r=this.length),n>=this.length)return 0;var o=a.FindUtil(i);return r=r+n>this.length?this.length-n:r,n+=this.offset,o.str2byte(e,0===n&&r===this.length?this:new t(this.data,n,r+n))},t.prototype.toString=function(e,n,r){if("undefined"==typeof e&&(e="utf8"),"undefined"==typeof n&&(n=0),"undefined"==typeof r&&(r=this.length),!(r>=n))throw new Error("Invalid start/end positions: "+n+" - "+r);if(n===r)return"";r>this.length&&(r=this.length);var i=a.FindUtil(e);return i.byte2str(0===n&&r===this.length?this:new t(this.data,n+this.offset,r+this.offset))},t.prototype.toJSON=function(){for(var t=this.length,e=new Array(t),n=0;t>n;n++)e[n]=this.readUInt8(n);return{type:"Buffer",data:e}},t.prototype.copy=function(t,e,n,r){if("undefined"==typeof e&&(e=0),"undefined"==typeof n&&(n=0),"undefined"==typeof r&&(r=this.length),e=0>e?0:e,n=0>n?0:n,n>r)throw new RangeError("sourceEnd < sourceStart");if(r===n)return 0;if(e>=t.length)throw new RangeError("targetStart out of bounds");if(n>=this.length)throw new RangeError("sourceStart out of bounds");if(r>this.length)throw new RangeError("sourceEnd out of bounds");for(var i=Math.min(r-n,t.length-e,this.length-n),o=0;i>o;o++)t.writeUInt8(this.readUInt8(n+o),e+o);return i},t.prototype.slice=function(e,n){if("undefined"==typeof e&&(e=0),"undefined"==typeof n&&(n=this.length),0>e&&(e+=this.length,0>e&&(e=0)),0>n&&(n+=this.length,0>n&&(n=0)),n>this.length&&(n=this.length),e>n&&(e=n),0>e||0>n||e>=this.length||n>this.length)throw new Error("Invalid slice indices.");return new t(this.data,e+this.offset,n+this.offset)},t.prototype.sliceCopy=function(e,n){if("undefined"==typeof e&&(e=0),"undefined"==typeof n&&(n=this.length),0>e&&(e+=this.length,0>e&&(e=0)),0>n&&(n+=this.length,0>n&&(n=0)),n>this.length&&(n=this.length),e>n&&(e=n),0>e||0>n||e>=this.length||n>this.length)throw new Error("Invalid slice indices.");return new t(this.data.copy(e+this.offset,n+this.offset))},t.prototype.fill=function(t,e,n){"undefined"==typeof e&&(e=0),"undefined"==typeof n&&(n=this.length);var r=typeof t;switch(r){case"string":t=255&t.charCodeAt(0);break;case"number":break;default:throw new Error("Invalid argument to fill.")}e+=this.offset,n+=this.offset,this.data.fill(t,e,n)},t.prototype.readUInt8=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readUInt8(t)},t.prototype.readUInt16LE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readUInt16LE(t)},t.prototype.readUInt16BE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readUInt16BE(t)},t.prototype.readUInt32LE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readUInt32LE(t)},t.prototype.readUInt32BE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readUInt32BE(t)},t.prototype.readInt8=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readInt8(t)},t.prototype.readInt16LE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readInt16LE(t)},t.prototype.readInt16BE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readInt16BE(t)},t.prototype.readInt32LE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readInt32LE(t)},t.prototype.readInt32BE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readInt32BE(t)},t.prototype.readFloatLE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readFloatLE(t)},t.prototype.readFloatBE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readFloatBE(t)},t.prototype.readDoubleLE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readDoubleLE(t)},t.prototype.readDoubleBE=function(t,e){return"undefined"==typeof e&&(e=!1),t+=this.offset,this.data.readDoubleBE(t)},t.prototype.writeUInt8=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeUInt8(e,t)},t.prototype.writeUInt16LE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeUInt16LE(e,t)},t.prototype.writeUInt16BE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeUInt16BE(e,t)},t.prototype.writeUInt32LE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeUInt32LE(e,t)},t.prototype.writeUInt32BE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeUInt32BE(e,t)},t.prototype.writeInt8=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeInt8(e,t)},t.prototype.writeInt16LE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeInt16LE(e,t)},t.prototype.writeInt16BE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeInt16BE(e,t)},t.prototype.writeInt32LE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeInt32LE(e,t)},t.prototype.writeInt32BE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeInt32BE(e,t)},t.prototype.writeFloatLE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeFloatLE(e,t)},t.prototype.writeFloatBE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeFloatBE(e,t)},t.prototype.writeDoubleLE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeDoubleLE(e,t)},t.prototype.writeDoubleBE=function(t,e,n){"undefined"==typeof n&&(n=!1),e+=this.offset,this.data.writeDoubleBE(e,t)},t.isEncoding=function(t){try{a.FindUtil(t)}catch(e){return!1}return!0},t.isBuffer=function(e){return e instanceof t},t.byteLength=function(t,e){"undefined"==typeof e&&(e="utf8");var n=a.FindUtil(e); +return n.byteLength(t)},t.concat=function(e,n){var r;if(0===e.length||0===n)return new t(0);if(1===e.length)return e[0];if(null==n){n=0;for(var i=0;ithis.maxListeners&&process.stdout.write("Warning: Event "+t+" has more than "+this.maxListeners+" listeners.\n"),this.emit("newListener",t,e),this},t.prototype.on=function(t,e){return this.addListener(t,e)},t.prototype.once=function(t,e){var n=!1,r=function(){this.removeListener(t,r),n||(n=!0,e.apply(this,arguments))};return this.addListener(t,r)},t.prototype._emitRemoveListener=function(t,e){var n;if(this._listeners.removeListener&&this._listeners.removeListener.length>0)for(n=0;n-1&&n.splice(r,1)}return this.emit("removeListener",t,e),this},t.prototype.removeAllListeners=function(t){var e,n,r;if("undefined"!=typeof t)e=this._listeners[t],this._listeners[t]=[],this._emitRemoveListener(t,e);else for(n=Object.keys(this._listeners),r=0;r0&&setTimeout(function(){i.emit("readable")},0):this.resume(),r},e.prototype._processArgs=function(t,e,n){return"string"==typeof e?new a(t,e,n):new a(t,null,e)},e.prototype._processEvents=function(){var t=0===this.buffer.length;this.drained!==t&&this.drained&&this.emit("readable"),this.flowing&&0!==this.buffer.length&&this.emit("data",this.read()),this.drained=0===this.buffer.length},e.prototype.emitEvent=function(t,e){this.emit(t,e.getData(this.encoding)),e.cb&&e.cb()},e.prototype.write=function(t,e,n){if(this.ended)throw new o(0,"Cannot write to an ended stream.");var r=this._processArgs(t,e,n);return this._push(r),this.flowing},e.prototype.end=function(t,e,n){if(this.ended)throw new o(0,"Stream is already closed.");var r=this._processArgs(t,e,n);this.ended=!0,this.endEvent=r,this._processEvents()},e.prototype.read=function(t){var e,n,r,o,s=[],u=[],f=0,c=0,p="number"!=typeof t;for(p&&(t=4294967295),c=0;cf;c++)n=this.buffer[c],s.push(n.getData()),n.cb&&u.push(n.cb),f+=n.size,e=n.cb;if(!p&&t>f)return null;if(this.buffer=this.buffer.slice(s.length),o=f>t?t:f,r=i.concat(s),f>t&&(e&&u.pop(),this._push(new a(r.slice(t),null,e))),u.length>0&&setTimeout(function(){var t;for(t=0;t0&&".."!==i[0])?i.pop():i.push(a))}if(!n&&i.length<2)switch(i.length){case 1:""===i[0]&&i.unshift(".");break;default:i.push(".")}return e=i.join(t.sep),n&&e.charAt(0)!==t.sep&&(e=t.sep+e),e},t.join=function(){for(var e=[],n=0;n1&&s.charAt(s.length-1)===t.sep)return s.substr(0,s.length-1);if(s.charAt(0)!==t.sep){"."!==s.charAt(0)||1!==s.length&&s.charAt(1)!==t.sep||(s=1===s.length?"":s.substr(2));var u=r.cwd();s=""!==s?this.normalize(u+("/"!==u?t.sep:"")+s):u}return s},t.relative=function(e,n){var r;e=t.resolve(e),n=t.resolve(n);var i=e.split(t.sep),o=n.split(t.sep);o.shift(),i.shift();var a=0,s=[];for(r=0;ri.length&&(a=i.length);var f="";for(r=0;a>r;r++)f+="../";return f+=s.join(t.sep),f.length>1&&f.charAt(f.length-1)===t.sep&&(f=f.substr(0,f.length-1)),f},t.dirname=function(e){e=t._removeDuplicateSeps(e);var n=e.charAt(0)===t.sep,r=e.split(t.sep);return""===r.pop()&&r.length>0&&r.pop(),r.length>1?r.join(t.sep):n?t.sep:"."},t.basename=function(e,n){if("undefined"==typeof n&&(n=""),""===e)return e;e=t.normalize(e);var r=e.split(t.sep),i=r[r.length-1];if(""===i&&r.length>1)return r[r.length-2];if(n.length>0){var o=i.substr(i.length-n.length);if(o===n)return i.substr(0,i.length-n.length)}return i},t.extname=function(e){e=t.normalize(e);var n=e.split(t.sep);if(e=n.pop(),""===e&&n.length>0&&(e=n.pop()),".."===e)return"";var r=e.lastIndexOf(".");return-1===r||0===r?"":e.substr(r)},t.isAbsolute=function(e){return e.length>0&&e.charAt(0)===t.sep},t._makeLong=function(t){return t},t._removeDuplicateSeps=function(t){return t=t.replace(this._replaceRegex,this.sep)},t.sep="/",t._replaceRegex=new RegExp("//+","g"),t.delimiter=":",t}();e.path=i}),u("core/node_fs",["require","exports","./api_error","./file_flag","./buffer","./node_path"],function(t,e,n,r,i,o){function a(t,e){if("function"!=typeof t)throw new h(9,"Callback must be a function.");switch("undefined"==typeof __numWaiting&&(__numWaiting=0),__numWaiting++,e){case 1:return function(e){setImmediate(function(){return __numWaiting--,t(e)})};case 2:return function(e,n){setImmediate(function(){return __numWaiting--,t(e,n)})};case 3:return function(e,n,r){setImmediate(function(){return __numWaiting--,t(e,n,r)})};default:throw new Error("Invalid invocation of wrapCb.")}}function s(t){if("function"!=typeof t.write)throw new h(3,"Invalid file descriptor.")}function u(t,e){switch(typeof t){case"number":return t;case"string":var n=parseInt(t,8);if(0/0!==n)return n;default:return e}}function f(t){if(t.indexOf("\x00")>=0)throw new h(9,"Path must be a string without null bytes.");if(""===t)throw new h(9,"Path must not be empty.");return y.resolve(t)}function c(t,e,n,r){switch(typeof t){case"object":return{encoding:"undefined"!=typeof t.encoding?t.encoding:e,flag:"undefined"!=typeof t.flag?t.flag:n,mode:u(t.mode,r)};case"string":return{encoding:t,flag:n,mode:r};default:return{encoding:e,flag:n,mode:r}}}function p(){}var h=n.ApiError;n.ErrorCode;var l=r.FileFlag,d=i.Buffer,y=o.path,g=function(){function t(){}return t._initialize=function(e){if(!e.constructor.isAvailable())throw new h(9,"Tried to instantiate BrowserFS with an unavailable file system.");return t.root=e},t._toUnixTimestamp=function(t){if("number"==typeof t)return t;if(t instanceof Date)return t.getTime()/1e3;throw new Error("Cannot parse time: "+t)},t.getRootFS=function(){return t.root?t.root:null},t.rename=function(e,n,r){"undefined"==typeof r&&(r=p);var i=a(r,1);try{t.root.rename(f(e),f(n),i)}catch(o){i(o)}},t.renameSync=function(e,n){t.root.renameSync(f(e),f(n))},t.exists=function(e,n){"undefined"==typeof n&&(n=p);var r=a(n,1);try{return t.root.exists(f(e),r)}catch(i){return r(!1)}},t.existsSync=function(e){try{return t.root.existsSync(f(e))}catch(n){return!1}},t.stat=function(e,n){"undefined"==typeof n&&(n=p);var r=a(n,2);try{return t.root.stat(f(e),!1,r)}catch(i){return r(i,null)}},t.statSync=function(e){return t.root.statSync(f(e),!1)},t.lstat=function(e,n){"undefined"==typeof n&&(n=p);var r=a(n,2);try{return t.root.stat(f(e),!0,r)}catch(i){return r(i,null)}},t.lstatSync=function(e){return t.root.statSync(f(e),!0)},t.truncate=function(e,n,r){"undefined"==typeof n&&(n=0),"undefined"==typeof r&&(r=p);var i=0;"function"==typeof n?r=n:"number"==typeof n&&(i=n);var o=a(r,1);try{if(0>i)throw new h(9);return t.root.truncate(f(e),i,o)}catch(s){return o(s)}},t.truncateSync=function(e,n){if("undefined"==typeof n&&(n=0),0>n)throw new h(9);return t.root.truncateSync(f(e),n)},t.unlink=function(e,n){"undefined"==typeof n&&(n=p);var r=a(n,1);try{return t.root.unlink(f(e),r)}catch(i){return r(i)}},t.unlinkSync=function(e){return t.root.unlinkSync(f(e))},t.open=function(e,n,r,i){"undefined"==typeof i&&(i=p);var o=u(r,420);i="function"==typeof r?r:i;var s=a(i,2);try{return t.root.open(f(e),l.getFileFlag(n),o,s)}catch(c){return s(c,null)}},t.openSync=function(e,n,r){return"undefined"==typeof r&&(r=420),t.root.openSync(f(e),l.getFileFlag(n),r)},t.readFile=function(e,n,r){"undefined"==typeof n&&(n={}),"undefined"==typeof r&&(r=p);var i=c(n,null,"r",null);r="function"==typeof n?n:r;var o=a(r,2);try{var s=l.getFileFlag(i.flag);return s.isReadable()?t.root.readFile(f(e),i.encoding,s,o):o(new h(9,"Flag passed to readFile must allow for reading."))}catch(u){return o(u,null)}},t.readFileSync=function(e,n){"undefined"==typeof n&&(n={});var r=c(n,null,"r",null),i=l.getFileFlag(r.flag);if(!i.isReadable())throw new h(9,"Flag passed to readFile must allow for reading.");return t.root.readFileSync(f(e),r.encoding,i)},t.writeFile=function(e,n,r,i){"undefined"==typeof r&&(r={}),"undefined"==typeof i&&(i=p);var o=c(r,"utf8","w",420);i="function"==typeof r?r:i;var s=a(i,1);try{var u=l.getFileFlag(o.flag);return u.isWriteable()?t.root.writeFile(f(e),n,o.encoding,u,o.mode,s):s(new h(9,"Flag passed to writeFile must allow for writing."))}catch(d){return s(d)}},t.writeFileSync=function(e,n,r){var i=c(r,"utf8","w",420),o=l.getFileFlag(i.flag);if(!o.isWriteable())throw new h(9,"Flag passed to writeFile must allow for writing.");return t.root.writeFileSync(f(e),n,i.encoding,o,i.mode)},t.appendFile=function(e,n,r,i){"undefined"==typeof i&&(i=p);var o=c(r,"utf8","a",420);i="function"==typeof r?r:i;var s=a(i,1);try{var u=l.getFileFlag(o.flag);if(!u.isAppendable())return s(new h(9,"Flag passed to appendFile must allow for appending."));t.root.appendFile(f(e),n,o.encoding,u,o.mode,s)}catch(d){s(d)}},t.appendFileSync=function(e,n,r){var i=c(r,"utf8","a",420),o=l.getFileFlag(i.flag);if(!o.isAppendable())throw new h(9,"Flag passed to appendFile must allow for appending.");return t.root.appendFileSync(f(e),n,i.encoding,o,i.mode)},t.fstat=function(t,e){"undefined"==typeof e&&(e=p);var n=a(e,2);try{s(t),t.stat(n)}catch(r){n(r)}},t.fstatSync=function(t){return s(t),t.statSync()},t.close=function(t,e){"undefined"==typeof e&&(e=p);var n=a(e,1);try{s(t),t.close(n)}catch(r){n(r)}},t.closeSync=function(t){return s(t),t.closeSync()},t.ftruncate=function(t,e,n){"undefined"==typeof n&&(n=p);var r="number"==typeof e?e:0;n="function"==typeof e?e:n;var i=a(n,1);try{if(s(t),0>r)throw new h(9);t.truncate(r,i)}catch(o){i(o)}},t.ftruncateSync=function(t,e){return"undefined"==typeof e&&(e=0),s(t),t.truncateSync(e)},t.fsync=function(t,e){"undefined"==typeof e&&(e=p);var n=a(e,1);try{s(t),t.sync(n)}catch(r){n(r)}},t.fsyncSync=function(t){return s(t),t.syncSync()},t.fdatasync=function(t,e){"undefined"==typeof e&&(e=p);var n=a(e,1);try{s(t),t.datasync(n)}catch(r){n(r)}},t.fdatasyncSync=function(t){s(t),t.datasyncSync()},t.write=function(t,e,n,r,i,o){"undefined"==typeof o&&(o=p);var u,f,c,l=null;if("string"==typeof e){var y="utf8";switch(typeof n){case"function":o=n;break;case"number":l=n,y="string"==typeof r?r:"utf8",o="function"==typeof i?i:o;break;default:return o="function"==typeof r?r:"function"==typeof i?i:o,o(new h(9,"Invalid arguments."))}u=new d(e,y),f=0,c=u.length}else u=e,f=n,c=r,l="number"==typeof i?i:null,o="function"==typeof i?i:o;var g=a(o,3);try{s(t),null==l&&(l=t.getPos()),t.write(u,f,c,l,g)}catch(w){g(w)}},t.writeSync=function(t,e,n,r,i){var o,a,u,f=0;if("string"==typeof e){u="number"==typeof n?n:null;var c="string"==typeof r?r:"utf8";f=0,o=new d(e,c),a=o.length}else o=e,f=n,a=r,u="number"==typeof i?i:null;return s(t),null==u&&(u=t.getPos()),t.writeSync(o,f,a,u)},t.read=function(t,e,n,r,i,o){"undefined"==typeof o&&(o=p);var u,f,c,h,l;if("number"==typeof e){c=e,u=n;var y=r;o="function"==typeof i?i:o,f=0,h=new d(c),l=a(function(t,e,n){return t?o(t):(o(t,n.toString(y),e),void 0)},3)}else h=e,f=n,c=r,u=i,l=a(o,3);try{s(t),null==u&&(u=t.getPos()),t.read(h,f,c,u,l)}catch(g){l(g)}},t.readSync=function(t,e,n,r,i){var o,a,u,f,c=!1;if("number"==typeof e){u=e,f=n;var p=r;a=0,o=new d(u),c=!0}else o=e,a=n,u=r,f=i;s(t),null==f&&(f=t.getPos());var h=t.readSync(o,a,u,f);return c?[o.toString(p),h]:h},t.fchown=function(t,e,n,r){"undefined"==typeof r&&(r=p);var i=a(r,1);try{s(t),t.chown(e,n,i)}catch(o){i(o)}},t.fchownSync=function(t,e,n){return s(t),t.chownSync(e,n)},t.fchmod=function(t,e,n){"undefined"==typeof n&&(n=p);var r=a(n,1);try{e="string"==typeof e?parseInt(e,8):e,s(t),t.chmod(e,r)}catch(i){r(i)}},t.fchmodSync=function(t,e){return e="string"==typeof e?parseInt(e,8):e,s(t),t.chmodSync(e)},t.futimes=function(t,e,n,r){"undefined"==typeof r&&(r=p);var i=a(r,1);try{s(t),"number"==typeof e&&(e=new Date(1e3*e)),"number"==typeof n&&(n=new Date(1e3*n)),t.utimes(e,n,i)}catch(o){i(o)}},t.futimesSync=function(t,e,n){return s(t),"number"==typeof e&&(e=new Date(1e3*e)),"number"==typeof n&&(n=new Date(1e3*n)),t.utimesSync(e,n)},t.rmdir=function(e,n){"undefined"==typeof n&&(n=p);var r=a(n,1);try{e=f(e),t.root.rmdir(e,r)}catch(i){r(i)}},t.rmdirSync=function(e){return e=f(e),t.root.rmdirSync(e)},t.mkdir=function(e,n,r){"undefined"==typeof r&&(r=p),"function"==typeof n&&(r=n,n=511);var i=a(r,1);try{e=f(e),t.root.mkdir(e,n,i)}catch(o){i(o)}},t.mkdirSync=function(e,n){return"undefined"==typeof n&&(n=511),n="string"==typeof n?parseInt(n,8):n,e=f(e),t.root.mkdirSync(e,n)},t.readdir=function(e,n){"undefined"==typeof n&&(n=p);var r=a(n,2);try{e=f(e),t.root.readdir(e,r)}catch(i){r(i)}},t.readdirSync=function(e){return e=f(e),t.root.readdirSync(e)},t.link=function(e,n,r){"undefined"==typeof r&&(r=p);var i=a(r,1);try{e=f(e),n=f(n),t.root.link(e,n,i)}catch(o){i(o)}},t.linkSync=function(e,n){return e=f(e),n=f(n),t.root.linkSync(e,n)},t.symlink=function(e,n,r,i){"undefined"==typeof i&&(i=p);var o="string"==typeof r?r:"file";i="function"==typeof r?r:i;var s=a(i,1);try{if("file"!==o&&"dir"!==o)return s(new h(9,"Invalid type: "+o));e=f(e),n=f(n),t.root.symlink(e,n,o,s)}catch(u){s(u)}},t.symlinkSync=function(e,n,r){if(null==r)r="file";else if("file"!==r&&"dir"!==r)throw new h(9,"Invalid type: "+r);return e=f(e),n=f(n),t.root.symlinkSync(e,n,r)},t.readlink=function(e,n){"undefined"==typeof n&&(n=p);var r=a(n,2);try{e=f(e),t.root.readlink(e,r)}catch(i){r(i)}},t.readlinkSync=function(e){return e=f(e),t.root.readlinkSync(e)},t.chown=function(e,n,r,i){"undefined"==typeof i&&(i=p);var o=a(i,1);try{e=f(e),t.root.chown(e,!1,n,r,o)}catch(s){o(s)}},t.chownSync=function(e,n,r){e=f(e),t.root.chownSync(e,!1,n,r)},t.lchown=function(e,n,r,i){"undefined"==typeof i&&(i=p);var o=a(i,1);try{e=f(e),t.root.chown(e,!0,n,r,o)}catch(s){o(s)}},t.lchownSync=function(e,n,r){return e=f(e),t.root.chownSync(e,!0,n,r)},t.chmod=function(e,n,r){"undefined"==typeof r&&(r=p);var i=a(r,1);try{n="string"==typeof n?parseInt(n,8):n,e=f(e),t.root.chmod(e,!1,n,i)}catch(o){i(o)}},t.chmodSync=function(e,n){return n="string"==typeof n?parseInt(n,8):n,e=f(e),t.root.chmodSync(e,!1,n)},t.lchmod=function(e,n,r){"undefined"==typeof r&&(r=p);var i=a(r,1);try{n="string"==typeof n?parseInt(n,8):n,e=f(e),t.root.chmod(e,!0,n,i)}catch(o){i(o)}},t.lchmodSync=function(e,n){return e=f(e),n="string"==typeof n?parseInt(n,8):n,t.root.chmodSync(e,!0,n)},t.utimes=function(e,n,r,i){"undefined"==typeof i&&(i=p);var o=a(i,1);try{e=f(e),"number"==typeof n&&(n=new Date(1e3*n)),"number"==typeof r&&(r=new Date(1e3*r)),t.root.utimes(e,n,r,o)}catch(s){o(s)}},t.utimesSync=function(e,n,r){return e=f(e),"number"==typeof n&&(n=new Date(1e3*n)),"number"==typeof r&&(r=new Date(1e3*r)),t.root.utimesSync(e,n,r)},t.realpath=function(e,n,r){"undefined"==typeof r&&(r=p);var i="object"==typeof n?n:{};r="function"==typeof n?n:p;var o=a(r,2);try{e=f(e),t.root.realpath(e,i,o)}catch(s){o(s)}},t.realpathSync=function(e,n){return"undefined"==typeof n&&(n={}),e=f(e),t.root.realpathSync(e,n)},t.root=null,t}();e.fs=g}),u("core/browserfs",["require","exports","./buffer","./node_fs","./node_path","./node_process"],function(t,e,n,r,i,o){function a(t){t.Buffer=n.Buffer,t.process=o.process;var r=null!=t.require?t.require:null;t.require=function(t){var n=e.BFSRequire(t);return null==n?r.apply(null,Array.prototype.slice.call(arguments,0)):n}}function s(t,n){e.FileSystem[t]=n}function u(t){switch(t){case"fs":return r.fs;case"path":return i.path;case"buffer":return n;case"process":return o.process;default:return e.FileSystem[t]}}function f(t){return r.fs._initialize(t)}e.install=a,e.FileSystem={},e.registerFileSystem=s,e.BFSRequire=u,e.initialize=f}),u("generic/emscripten_fs",["require","exports","../core/browserfs","../core/node_fs","../core/buffer","../core/buffer_core_arraybuffer"],function(t,e,n,r,i,o){var a=i.Buffer,s=o.BufferCoreArrayBuffer,u=r.fs,f=function(){function t(t){this.fs=t}return t.prototype.open=function(t){var e=this.fs.realPath(t.node);try{FS.isFile(t.node.mode)&&(t.nfd=u.openSync(e,this.fs.flagsToPermissionString(t.flags)))}catch(n){if(!n.code)throw n;throw new FS.ErrnoError(ERRNO_CODES[n.code])}},t.prototype.close=function(t){try{FS.isFile(t.node.mode)&&t.nfd&&u.closeSync(t.nfd)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(ERRNO_CODES[e.code])}},t.prototype.read=function(t,e,n,r,i){var o,f=new s(e.buffer),c=new a(f,e.byteOffset+n,e.byteOffset+n+r);try{o=u.readSync(t.nfd,c,0,r,i)}catch(p){throw new FS.ErrnoError(ERRNO_CODES[p.code])}return o},t.prototype.write=function(t,e,n,r,i){var o,f=new s(e.buffer),c=new a(f,e.byteOffset+n,e.byteOffset+n+r);try{o=u.writeSync(t.nfd,c,0,r,i)}catch(p){throw new FS.ErrnoError(ERRNO_CODES[p.code])}return o},t.prototype.llseek=function(t,e,n){var r=e;if(1===n)r+=t.position;else if(2===n&&FS.isFile(t.node.mode))try{var i=u.fstatSync(t.nfd);r+=i.size}catch(o){throw new FS.ErrnoError(ERRNO_CODES[o.code])}if(0>r)throw new FS.ErrnoError(ERRNO_CODES.EINVAL);return t.position=r,r},t}(),c=function(){function t(t){this.fs=t}return t.prototype.getattr=function(t){var e,n=this.fs.realPath(t);try{e=u.lstatSync(n)}catch(r){if(!r.code)throw r;throw new FS.ErrnoError(ERRNO_CODES[r.code])}return{dev:e.dev,ino:e.ino,mode:e.mode,nlink:e.nlink,uid:e.uid,gid:e.gid,rdev:e.rdev,size:e.size,atime:e.atime,mtime:e.mtime,ctime:e.ctime,blksize:e.blksize,blocks:e.blocks}},t.prototype.setattr=function(t,e){var n=this.fs.realPath(t);try{if(void 0!==e.mode&&(u.chmodSync(n,e.mode),t.mode=e.mode),void 0!==e.timestamp){var r=new Date(e.timestamp);u.utimesSync(n,r,r)}void 0!==e.size&&u.truncateSync(n,e.size)}catch(i){if(!i.code)throw i;if("ENOTSUP"===i.code)return;throw new FS.ErrnoError(ERRNO_CODES[i.code])}},t.prototype.lookup=function(t,e){var n=PATH.join2(this.fs.realPath(t),e),r=this.fs.getMode(n);return this.fs.createNode(t,e,r)},t.prototype.mknod=function(t,e,n,r){var i=this.fs.createNode(t,e,n,r),o=this.fs.realPath(i);try{FS.isDir(i.mode)?u.mkdirSync(o,i.mode):u.writeFileSync(o,"",{mode:i.mode})}catch(a){if(!a.code)throw a;throw new FS.ErrnoError(ERRNO_CODES[a.code])}return i},t.prototype.rename=function(t,e,n){var r=this.fs.realPath(t),i=PATH.join2(this.fs.realPath(e),n);try{u.renameSync(r,i)}catch(o){if(!o.code)throw o;throw new FS.ErrnoError(ERRNO_CODES[o.code])}},t.prototype.unlink=function(t,e){var n=PATH.join2(this.fs.realPath(t),e);try{u.unlinkSync(n)}catch(r){if(!r.code)throw r;throw new FS.ErrnoError(ERRNO_CODES[r.code])}},t.prototype.rmdir=function(t,e){var n=PATH.join2(this.fs.realPath(t),e);try{u.rmdirSync(n)}catch(r){if(!r.code)throw r;throw new FS.ErrnoError(ERRNO_CODES[r.code])}},t.prototype.readdir=function(t){var e=this.fs.realPath(t);try{return u.readdirSync(e)}catch(n){if(!n.code)throw n;throw new FS.ErrnoError(ERRNO_CODES[n.code])}},t.prototype.symlink=function(t,e,n){var r=PATH.join2(this.fs.realPath(t),e);try{u.symlinkSync(n,r)}catch(i){if(!i.code)throw i;throw new FS.ErrnoError(ERRNO_CODES[i.code])}},t.prototype.readlink=function(t){var e=this.fs.realPath(t);try{return u.readlinkSync(e)}catch(n){if(!n.code)throw n;throw new FS.ErrnoError(ERRNO_CODES[n.code])}},t}(),p=function(){function t(){if(this.flagsToPermissionStringMap={0:"r",1:"r+",2:"r+",64:"r",65:"r+",66:"r+",129:"rx+",193:"rx+",514:"w+",577:"w",578:"w+",705:"wx",706:"wx+",1024:"a",1025:"a",1026:"a+",1089:"a",1090:"a+",1153:"ax",1154:"ax+",1217:"ax",1218:"ax+",4096:"rs",4098:"rs+"},this.node_ops=new c(this),this.stream_ops=new f(this),"undefined"==typeof n)throw new Error("BrowserFS is not loaded. Please load it before this library.")}return t.prototype.mount=function(t){return this.createNode(null,"/",this.getMode(t.opts.root),0)},t.prototype.createNode=function(t,e,n){if(!FS.isDir(n)&&!FS.isFile(n)&&!FS.isLink(n))throw new FS.ErrnoError(ERRNO_CODES.EINVAL);var r=FS.createNode(t,e,n);return r.node_ops=this.node_ops,r.stream_ops=this.stream_ops,r},t.prototype.getMode=function(t){var e;try{e=u.lstatSync(t)}catch(n){if(!n.code)throw n;throw new FS.ErrnoError(ERRNO_CODES[n.code])}return e.mode},t.prototype.realPath=function(t){for(var e=[];t.parent!==t;)e.push(t.name),t=t.parent;return e.push(t.mount.opts.root),e.reverse(),PATH.join.apply(null,e)},t.prototype.flagsToPermissionString=function(t){return t in this.flagsToPermissionStringMap?this.flagsToPermissionStringMap[t]:t},t}();e.BFSEmscriptenFS=p,n.EmscriptenFS=p});var f=this.__extends||function(t,e){function n(){this.constructor=t}for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);n.prototype=e.prototype,t.prototype=new n};u("core/file_system",["require","exports","./api_error","./file_flag","./node_path","./buffer"],function(t,e,n,r,i,o){var a=n.ApiError;n.ErrorCode;var s=i.path,u=o.Buffer;r.ActionType;var c=function(){function t(){}return t.prototype.supportsLinks=function(){return!1},t.prototype.diskSpace=function(t,e){e(0,0)},t.prototype.openFile=function(){throw new a(14)},t.prototype.createFile=function(){throw new a(14)},t.prototype.open=function(t,e,n,r){var i=this,o=function(o,u){if(o)switch(e.pathNotExistsAction()){case 3:return i.stat(s.dirname(t),!1,function(o,u){o?r(o):u.isDirectory()?i.createFile(t,e,n,r):r(new a(7,s.dirname(t)+" is not a directory."))});case 1:return r(new a(1,""+t+" doesn't exist."));default:return r(new a(9,"Invalid FileFlag object."))}else{if(u.isDirectory())return r(new a(8,t+" is a directory."));switch(e.pathExistsAction()){case 1:return r(new a(6,t+" already exists."));case 2:return i.openFile(t,e,function(t,e){t?r(t):e.truncate(0,function(){e.sync(function(){r(null,e)})})});case 0:return i.openFile(t,e,r);default:return r(new a(9,"Invalid FileFlag object."))}}};this.stat(t,!1,o)},t.prototype.rename=function(t,e,n){n(new a(14))},t.prototype.renameSync=function(){throw new a(14)},t.prototype.stat=function(t,e,n){n(new a(14))},t.prototype.statSync=function(){throw new a(14)},t.prototype.openFileSync=function(){throw new a(14)},t.prototype.createFileSync=function(){throw new a(14)},t.prototype.openSync=function(t,e,n){var r;try{r=this.statSync(t,!1)}catch(i){switch(e.pathNotExistsAction()){case 3:var o=this.statSync(s.dirname(t),!1);if(!o.isDirectory())throw new a(7,s.dirname(t)+" is not a directory.");return this.createFileSync(t,e,n);case 1:throw new a(1,""+t+" doesn't exist.");default:throw new a(9,"Invalid FileFlag object.")}}if(r.isDirectory())throw new a(8,t+" is a directory.");switch(e.pathExistsAction()){case 1:throw new a(6,t+" already exists.");case 2:return this.unlinkSync(t),this.createFileSync(t,e,r.mode);case 0:return this.openFileSync(t,e);default:throw new a(9,"Invalid FileFlag object.")}},t.prototype.unlink=function(t,e){e(new a(14))},t.prototype.unlinkSync=function(){throw new a(14)},t.prototype.rmdir=function(t,e){e(new a(14))},t.prototype.rmdirSync=function(){throw new a(14)},t.prototype.mkdir=function(t,e,n){n(new a(14))},t.prototype.mkdirSync=function(){throw new a(14)},t.prototype.readdir=function(t,e){e(new a(14))},t.prototype.readdirSync=function(){throw new a(14)},t.prototype.exists=function(t,e){this.stat(t,null,function(t){e(null==t)})},t.prototype.existsSync=function(t){try{return this.statSync(t,!0),!0}catch(e){return!1}},t.prototype.realpath=function(t,e,n){if(this.supportsLinks())for(var r=t.split(s.sep),i=0;ithis._buffer.length){var e=new u(t-this._buffer.length);return e.fill(0),this.writeSync(e,0,e.length,this._buffer.length),this._flag.isSynchronous()&&s.getRootFS().supportsSynch()&&this.syncSync(),void 0}this._stat.size=t;var n=new u(t);this._buffer.copy(n,0,0,t),this._buffer=n,this._flag.isSynchronous()&&s.getRootFS().supportsSynch()&&this.syncSync()},e.prototype.write=function(t,e,n,r,i){try{i(null,this.writeSync(t,e,n,r),t)}catch(o){i(o)}},e.prototype.writeSync=function(t,e,n,r){if(null==r&&(r=this.getPos()),!this._flag.isWriteable())throw new a(0,"File not opened with a writeable mode.");var i=r+n;if(i>this._stat.size&&(this._stat.size=i,i>this._buffer.length)){var o=new u(i);this._buffer.copy(o),this._buffer=o}var s=t.copy(this._buffer,r,e,e+n);return this._stat.mtime=new Date,this._flag.isSynchronous()?(this.syncSync(),s):(this.setPos(r+s),s)},e.prototype.read=function(t,e,n,r,i){try{i(null,this.readSync(t,e,n,r),t)}catch(o){i(o)}},e.prototype.readSync=function(t,e,n,r){if(!this._flag.isReadable())throw new a(0,"File not opened with a readable mode.");null==r&&(r=this.getPos());var i=r+n;i>this._stat.size&&(n=this._stat.size-r);var o=this._buffer.copy(t,e,r,r+n);return this._stat.atime=new Date,this._pos=r+n,o},e.prototype.chmod=function(t,e){try{this.chmodSync(t),e()}catch(n){e(n)}},e.prototype.chmodSync=function(t){if(!this._fs.supportsProps())throw new a(14);this._stat.chmod(t),this.syncSync()},e}(n.BaseFile);e.PreloadFile=c;var p=function(t){function e(e,n,r,i,o){t.call(this,e,n,r,i,o)}return f(e,t),e.prototype.sync=function(t){t()},e.prototype.syncSync=function(){},e.prototype.close=function(t){t()},e.prototype.closeSync=function(){},e}(c);e.NoSyncFile=p});var f=this.__extends||function(t,e){function n(){this.constructor=t}for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);n.prototype=e.prototype,t.prototype=new n};u("generic/key_value_filesystem",["require","exports","../core/file_system","../core/api_error","../core/node_fs_stats","../core/node_path","../generic/inode","../core/buffer","../generic/preload_file"],function(t,e,n,r,i,o,a,s,u){function c(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){var e=0|16*Math.random(),n="x"==t?e:8|3&e;return n.toString(16)})}function p(t,e){return t?(e(t),!1):!0}function h(t,e,n){return t?(e.abort(function(){n(t)}),!1):!0}var l="/",d=o.path,y=r.ApiError,g=s.Buffer,w=function(){function t(t){this.store=t,this.originalData={},this.modifiedKeys=[]}return t.prototype.stashOldValue=function(t,e){this.originalData.hasOwnProperty(t)||(this.originalData[t]=e)},t.prototype.markModified=function(t){-1===this.modifiedKeys.indexOf(t)&&(this.modifiedKeys.push(t),this.originalData.hasOwnProperty(t)||(this.originalData[t]=this.store.get(t)))},t.prototype.get=function(t){var e=this.store.get(t);return this.stashOldValue(t,e),e},t.prototype.put=function(t,e,n){return this.markModified(t),this.store.put(t,e,n)},t.prototype.delete=function(t){this.markModified(t),this.store.delete(t)},t.prototype.commit=function(){},t.prototype.abort=function(){var t,e,n;for(t=0;tr;)try{return n=c(),t.put(n,e,!1),n}catch(i){}throw new y(2,"Unable to commit data to key-value store.")},e.prototype.commitNewFile=function(t,e,n,r,i){var o=d.dirname(e),s=d.basename(e),u=this.findINode(t,o),f=this.getDirListing(t,o,u),c=(new Date).getTime();if("/"===e)throw y.EEXIST(e);if(f[s])throw y.EEXIST(e);try{var p=this.addNewNode(t,i),h=new a(p,i.length,r|n,c,c,c),l=this.addNewNode(t,h.toBuffer());f[s]=l,t.put(u.id,new g(JSON.stringify(f)),!0)}catch(w){throw t.abort(),w}return t.commit(),h},e.prototype.empty=function(){this.store.clear(),this.makeRootDirectory()},e.prototype.renameSync=function(t,e){var n=this.store.beginTransaction("readwrite"),r=d.dirname(t),i=d.basename(t),o=d.dirname(e),a=d.basename(e),s=this.findINode(n,r),u=this.getDirListing(n,r,s);if(!u[i])throw y.ENOENT(t);var f=u[i];if(delete u[i],0===(o+"/").indexOf(t+"/"))throw new y(5,r);var c,p;if(o===r?(c=s,p=u):(c=this.findINode(n,o),p=this.getDirListing(n,o,c)),p[a]){var h=this.getINode(n,e,p[a]);if(!h.isFile())throw y.EPERM(e);try{n.delete(h.id),n.delete(p[a])}catch(l){throw n.abort(),l}}p[a]=f;try{n.put(s.id,new g(JSON.stringify(u)),!0),n.put(c.id,new g(JSON.stringify(p)),!0)}catch(l){throw n.abort(),l}n.commit()},e.prototype.statSync=function(t){return this.findINode(this.store.beginTransaction("readonly"),t).toStats()},e.prototype.createFileSync=function(t,e,n){var r=this.store.beginTransaction("readwrite"),i=new g(0),o=this.commitNewFile(r,t,32768,n,i);return new m(this,t,e,o.toStats(),i)},e.prototype.openFileSync=function(t,e){var n=this.store.beginTransaction("readonly"),r=this.findINode(n,t),i=n.get(r.id);if(void 0===i)throw y.ENOENT(t);return new m(this,t,e,r.toStats(),i)},e.prototype.removeEntry=function(t,e){var n=this.store.beginTransaction("readwrite"),r=d.dirname(t),i=this.findINode(n,r),o=this.getDirListing(n,r,i),a=d.basename(t);if(!o[a])throw y.ENOENT(t);var s=o[a];delete o[a];var u=this.getINode(n,t,s);if(!e&&u.isDirectory())throw y.EISDIR(t);if(e&&!u.isDirectory())throw y.ENOTDIR(t);try{n.delete(u.id),n.delete(s),n.put(i.id,new g(JSON.stringify(o)),!0)}catch(f){throw n.abort(),f}n.commit()},e.prototype.unlinkSync=function(t){this.removeEntry(t,!1)},e.prototype.rmdirSync=function(t){this.removeEntry(t,!0)},e.prototype.mkdirSync=function(t,e){var n=this.store.beginTransaction("readwrite"),r=new g("{}");this.commitNewFile(n,t,16384,e,r)},e.prototype.readdirSync=function(t){var e=this.store.beginTransaction("readonly");return Object.keys(this.getDirListing(e,t,this.findINode(e,t)))},e.prototype._syncSync=function(t,e,n){var r=this.store.beginTransaction("readwrite"),i=this._findINode(r,d.dirname(t),d.basename(t)),o=this.getINode(r,t,i),a=o.update(n);try{r.put(o.id,e,!0),a&&r.put(i,o.toBuffer(),!0)}catch(s){throw r.abort(),s}r.commit()},e}(n.SynchronousFileSystem);e.SyncKeyValueFileSystem=v;var b=function(t){function e(e,n,r,i,o){t.call(this,e,n,r,i,o)}return f(e,t),e.prototype.sync=function(t){this._fs._sync(this._path,this._buffer,this._stat,t)},e.prototype.close=function(t){this.sync(t)},e}(u.PreloadFile);e.AsyncKeyValueFile=b;var E=function(t){function e(){t.apply(this,arguments)}return f(e,t),e.prototype.init=function(t,e){this.store=t,this.makeRootDirectory(e)},e.isAvailable=function(){return!0},e.prototype.getName=function(){return this.store.name()},e.prototype.isReadOnly=function(){return!1},e.prototype.supportsSymlinks=function(){return!1},e.prototype.supportsProps=function(){return!1},e.prototype.supportsSynch=function(){return!1},e.prototype.makeRootDirectory=function(t){var e=this.store.beginTransaction("readwrite");e.get(l,function(n,r){if(n||void 0===r){var i=(new Date).getTime(),o=new a(c(),4096,16895,i,i,i);e.put(o.id,new g("{}"),!1,function(n){h(n,e,t)&&e.put(l,o.toBuffer(),!1,function(n){n?e.abort(function(){t(n)}):e.commit(t)})})}else e.commit(t)})},e.prototype._findINode=function(t,e,n,r){var i=this,o=function(t,i,o){t?r(t):o[n]?r(null,o[n]):r(y.ENOENT(d.resolve(e,n)))};"/"===e?""===n?r(null,l):this.getINode(t,e,l,function(n,a){p(n,r)&&i.getDirListing(t,e,a,function(t,e){o(t,a,e)})}):this.findINodeAndDirListing(t,e,o)},e.prototype.findINode=function(t,e,n){var r=this;this._findINode(t,d.dirname(e),d.basename(e),function(i,o){p(i,n)&&r.getINode(t,e,o,n)})},e.prototype.getINode=function(t,e,n,r){t.get(n,function(t,n){p(t,r)&&(void 0===n?r(y.ENOENT(e)):r(null,a.fromBuffer(n)))})},e.prototype.getDirListing=function(t,e,n,r){n.isDirectory()?t.get(n.id,function(t,n){if(p(t,r))try{r(null,JSON.parse(n.toString()))}catch(t){r(y.ENOENT(e))}}):r(y.ENOTDIR(e))},e.prototype.findINodeAndDirListing=function(t,e,n){var r=this;this.findINode(t,e,function(i,o){p(i,n)&&r.getDirListing(t,e,o,function(t,e){p(t,n)&&n(null,o,e)})})},e.prototype.addNewNode=function(t,e,n){var r,i=0,o=function(){5===++i?n(new y(2,"Unable to commit data to key-value store.")):(r=c(),t.put(r,e,!1,function(t,e){t||!e?o():n(null,r)}))};o()},e.prototype.commitNewFile=function(t,e,n,r,i,o){var s=this,u=d.dirname(e),f=d.basename(e),c=(new Date).getTime();return"/"===e?o(y.EEXIST(e)):(this.findINodeAndDirListing(t,u,function(u,p,l){h(u,t,o)&&(l[f]?t.abort(function(){o(y.EEXIST(e))}):s.addNewNode(t,i,function(e,u){if(h(e,t,o)){var d=new a(u,i.length,r|n,c,c,c);s.addNewNode(t,d.toBuffer(),function(e,n){h(e,t,o)&&(l[f]=n,t.put(p.id,new g(JSON.stringify(l)),!0,function(e){h(e,t,o)&&t.commit(function(e){h(e,t,o)&&o(null,d)})}))})}}))}),void 0)},e.prototype.empty=function(t){var e=this;this.store.clear(function(n){p(n,t)&&e.makeRootDirectory(t)})},e.prototype.rename=function(t,e,n){var r=this,i=this.store.beginTransaction("readwrite"),o=d.dirname(t),a=d.basename(t),s=d.dirname(e),u=d.basename(e),f={},c={},p=!1;if(0===(s+"/").indexOf(t+"/"))return n(new y(5,o));var l=function(){if(!p&&c.hasOwnProperty(o)&&c.hasOwnProperty(s)){var l=c[o],d=f[o],w=c[s],m=f[s];if(l[a]){var v=l[a];delete l[a];var b=function(){w[u]=v,i.put(d.id,new g(JSON.stringify(l)),!0,function(t){h(t,i,n)&&(o===s?i.commit(n):i.put(m.id,new g(JSON.stringify(w)),!0,function(t){h(t,i,n)&&i.commit(n)}))})};w[u]?r.getINode(i,e,w[u],function(t,r){h(t,i,n)&&(r.isFile()?i.delete(r.id,function(t){h(t,i,n)&&i.delete(w[u],function(t){h(t,i,n)&&b()})}):i.abort(function(){n(y.EPERM(e))}))}):b()}else n(y.ENOENT(t))}},w=function(t){r.findINodeAndDirListing(i,t,function(e,r,o){e?p||(p=!0,i.abort(function(){n(e)})):(f[t]=r,c[t]=o,l())})};w(o),o!==s&&w(s)},e.prototype.stat=function(t,e,n){var r=this.store.beginTransaction("readonly");this.findINode(r,t,function(t,e){p(t,n)&&n(null,e.toStats())})},e.prototype.createFile=function(t,e,n,r){var i=this,o=this.store.beginTransaction("readwrite"),a=new g(0);this.commitNewFile(o,t,32768,n,a,function(n,o){p(n,r)&&r(null,new b(i,t,e,o.toStats(),a))})},e.prototype.openFile=function(t,e,n){var r=this,i=this.store.beginTransaction("readonly");this.findINode(i,t,function(o,a){p(o,n)&&i.get(a.id,function(i,o){p(i,n)&&(void 0===o?n(y.ENOENT(t)):n(null,new b(r,t,e,a.toStats(),o)))})})},e.prototype.removeEntry=function(t,e,n){var r=this,i=this.store.beginTransaction("readwrite"),o=d.dirname(t),a=d.basename(t);this.findINodeAndDirListing(i,o,function(o,s,u){if(h(o,i,n))if(u[a]){var f=u[a];delete u[a],r.getINode(i,t,f,function(r,o){h(r,i,n)&&(!e&&o.isDirectory()?i.abort(function(){n(y.EISDIR(t))}):e&&!o.isDirectory()?i.abort(function(){n(y.ENOTDIR(t))}):i.delete(o.id,function(t){h(t,i,n)&&i.delete(f,function(t){h(t,i,n)&&i.put(s.id,new g(JSON.stringify(u)),!0,function(t){h(t,i,n)&&i.commit(n)})})}))})}else i.abort(function(){n(y.ENOENT(t))})})},e.prototype.unlink=function(t,e){this.removeEntry(t,!1,e)},e.prototype.rmdir=function(t,e){this.removeEntry(t,!0,e)},e.prototype.mkdir=function(t,e,n){var r=this.store.beginTransaction("readwrite"),i=new g("{}");this.commitNewFile(r,t,16384,e,i,n)},e.prototype.readdir=function(t,e){var n=this,r=this.store.beginTransaction("readonly");this.findINode(r,t,function(i,o){p(i,e)&&n.getDirListing(r,t,o,function(t,n){p(t,e)&&e(null,Object.keys(n))})})},e.prototype._sync=function(t,e,n,r){var i=this,o=this.store.beginTransaction("readwrite");this._findINode(o,d.dirname(t),d.basename(t),function(a,s){h(a,o,r)&&i.getINode(o,t,s,function(t,i){if(h(t,o,r)){var a=i.update(n);o.put(i.id,e,!0,function(t){h(t,o,r)&&(a?o.put(s,i.toBuffer(),!0,function(t){h(t,o,r)&&o.commit(r)}):o.commit(r))})}})})},e}(n.BaseFileSystem);e.AsyncKeyValueFileSystem=E}),u("core/global",["require","exports"],function(){var t;return t="undefined"!=typeof window?window:"undefined"!=typeof self?self:global});var f=this.__extends||function(t,e){function n(){this.constructor=t}for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);n.prototype=e.prototype,t.prototype=new n};u("backend/IndexedDB",["require","exports","../core/buffer","../core/browserfs","../generic/key_value_filesystem","../core/api_error","../core/buffer_core_arraybuffer","../core/global"],function(t,e,n,r,i,o,a,s){function u(t,e){switch("undefined"==typeof e&&(e=t.toString()),t.name){case"NotFoundError":return new l(1,e);case"QuotaExceededError":return new l(11,e);default:return new l(2,e)}}function c(t,e,n){return"undefined"==typeof e&&(e=2),"undefined"==typeof n&&(n=null),function(r){r.preventDefault(),t(new l(e,n))}}function p(t){var e=t.getBufferCore();e instanceof a.BufferCoreArrayBuffer||(t=new h(this._buffer.length),this._buffer.copy(t),e=t.getBufferCore());var n=e.getDataView();return n.buffer}var h=n.Buffer,l=o.ApiError,d=(o.ErrorCode,s.indexedDB||s.mozIndexedDB||s.webkitIndexedDB||s.msIndexedDB),y=function(){function t(t,e){this.tx=t,this.store=e}return t.prototype.get=function(t,e){try{var n=this.store.get(t);n.onerror=c(e),n.onsuccess=function(t){var n=t.target.result;void 0===n?e(null,n):e(null,new h(n))}}catch(r){e(u(r))}},t}();e.IndexedDBROTransaction=y;var g=function(t){function e(e,n){t.call(this,e,n)}return f(e,t),e.prototype.put=function(t,e,n,r){try{var i,o=p(e);i=n?this.store.put(o,t):this.store.add(o,t),i.onerror=c(r),i.onsuccess=function(){r(null,!0)}}catch(a){r(u(a))}},e.prototype.delete=function(t,e){try{var n=this.store.delete(t);n.onerror=c(e),n.onsuccess=function(){e()}}catch(r){e(u(r))}},e.prototype.commit=function(t){setTimeout(t,0)},e.prototype.abort=function(t){var e;try{this.tx.abort()}catch(n){e=u(n)}finally{t(e)}},e}(y);e.IndexedDBRWTransaction=g;var w=function(){function t(t,e){"undefined"==typeof e&&(e="browserfs");var n=this;this.storeName=e;var r=d.open(this.storeName,1);r.onupgradeneeded=function(t){var e=t.target.result;e.objectStoreNames.contains(n.storeName)&&e.deleteObjectStore(n.storeName),e.createObjectStore(n.storeName)},r.onsuccess=function(e){n.db=e.target.result,t(null,n)},r.onerror=c(t,4)}return t.prototype.name=function(){return"IndexedDB - "+this.storeName},t.prototype.clear=function(t){try{var e=this.db.transaction(this.storeName,"readwrite"),n=e.objectStore(this.storeName),r=n.clear();r.onsuccess=function(){setTimeout(t,0)},r.onerror=c(t)}catch(i){t(u(i))}},t.prototype.beginTransaction=function(t){"undefined"==typeof t&&(t="readonly");var e=this.db.transaction(this.storeName,t),n=e.objectStore(this.storeName);if("readwrite"===t)return new g(e,n);if("readonly"===t)return new y(e,n);throw new l(9,"Invalid transaction type.")},t}();e.IndexedDBStore=w;var m=function(t){function e(e,n){var r=this;t.call(this),new w(function(t,n){t?e(t):r.init(n,function(t){e(t,r)})},n)}return f(e,t),e.isAvailable=function(){return"undefined"!=typeof d},e}(i.AsyncKeyValueFileSystem);e.IndexedDBFileSystem=m,r.registerFileSystem("IndexedDB",m)}),u("generic/file_index",["require","exports","../core/node_fs_stats","../core/node_path"],function(t,e,n,r){var i=n.Stats,o=r.path,a=function(){function t(){this._index={},this.addPath("/",new u)}return t.prototype._split_path=function(t){var e=o.dirname(t),n=t.substr(e.length+("/"===e?0:1));return[e,n]},t.prototype.fileIterator=function(t){for(var e in this._index)for(var n=this._index[e],r=n.getListing(),i=0;i0;){var a,f=o.pop(),c=f[0],p=f[1],h=f[2];for(var l in p){var d=p[l],y=""+c+"/"+l;null!=d?(n._index[y]=a=new u,o.push([y,d,a])):a=new s(new i(32768,-1,365)),null!=h&&(h._ls[l]=a)}}return n},t}();e.FileIndex=a;var s=function(){function t(t){this.data=t}return t.prototype.isFile=function(){return!0},t.prototype.isDir=function(){return!1},t.prototype.getData=function(){return this.data},t.prototype.setData=function(t){this.data=t},t}();e.FileInode=s;var u=function(){function t(){this._ls={}}return t.prototype.isFile=function(){return!1},t.prototype.isDir=function(){return!0},t.prototype.getStats=function(){return new i(16384,4096,365)},t.prototype.getListing=function(){return Object.keys(this._ls)},t.prototype.getItem=function(t){var e;return null!=(e=this._ls[t])?e:null},t.prototype.addItem=function(t,e){return t in this._ls?!1:(this._ls[t]=e,!0)},t.prototype.remItem=function(t){var e=this._ls[t];return void 0===e?null:(delete this._ls[t],e)},t}();e.DirInode=u}),u("core/util",["require","exports"],function(t,e){function n(t){var e,n,r,i,o,a;for(r=[],o=[t],e=0;0!==o.length;)if(a=o.pop(),"boolean"==typeof a)e+=4;else if("string"==typeof a)e+=2*a.length;else if("number"==typeof a)e+=8;else if("object"==typeof a&&r.indexOf(a)<0){r.push(a),e+=4;for(n in a)i=a[n],e+=2*n.length,o.push(i)}return e}e.roughSizeOfObject=n,e.isIE=null!=/(msie) ([\w.]+)/.exec(navigator.userAgent.toLowerCase())||-1!==navigator.userAgent.indexOf("Trident")}),u("generic/xhr",["require","exports","../core/util","../core/buffer","../core/api_error"],function(t,e,n,r,i){function o(t){for(var e=IEBinaryToArray_ByteStr(t),n=IEBinaryToArray_ByteStr_Last(t),r=e.replace(/[\s\S]/g,function(t){var e=t.charCodeAt(0);return String.fromCharCode(255&e,e>>8)})+n,i=new Array(r.length),o=0;o0&&"/"!==n.charAt(n.length-1)&&(n+="/");var i=this._requestFileSync(e,"json");if(null==i)throw new Error("Unable to find listing at URL: "+e);this._index=r.FileIndex.from_listing(i)}return f(e,t),e.prototype.empty=function(){this._index.fileIterator(function(t){t.file_data=null})},e.prototype.getXhrPath=function(t){return"/"===t.charAt(0)&&(t=t.slice(1)),this.prefix_url+t},e.prototype._requestFileSizeAsync=function(t,e){c.getFileSizeAsync(this.getXhrPath(t),e)},e.prototype._requestFileSizeSync=function(t){return c.getFileSizeSync(this.getXhrPath(t))},e.prototype._requestFileAsync=function(t,e,n){c.asyncDownloadFile(this.getXhrPath(t),e,n)},e.prototype._requestFileSync=function(t,e){return c.syncDownloadFile(this.getXhrPath(t),e)},e.prototype.getName=function(){return"XmlHttpRequest"},e.isAvailable=function(){return"undefined"!=typeof XMLHttpRequest&&null!==XMLHttpRequest},e.prototype.diskSpace=function(t,e){e(0,0)},e.prototype.isReadOnly=function(){return!0},e.prototype.supportsLinks=function(){return!1},e.prototype.supportsProps=function(){return!1},e.prototype.supportsSynch=function(){return!0},e.prototype.preloadFile=function(t,e){var n=this._index.getInode(t);if(null===n)throw p.ENOENT(t);var r=n.getData();r.size=e.length,r.file_data=e},e.prototype.stat=function(t,e,n){var r=this._index.getInode(t);if(null===r)return n(p.ENOENT(t));var i;r.isFile()?(i=r.getData(),i.size<0?this._requestFileSizeAsync(t,function(t,e){return t?n(t):(i.size=e,n(null,i.clone()),void 0)}):n(null,i.clone())):(i=r.getStats(),n(null,i))},e.prototype.statSync=function(t){var e=this._index.getInode(t);if(null===e)throw p.ENOENT(t);var n;return e.isFile()?(n=e.getData(),n.size<0&&(n.size=this._requestFileSizeSync(t))):n=e.getStats(),n},e.prototype.open=function(t,e,n,r){if(e.isWriteable())return r(new p(0,t));var i=this,o=this._index.getInode(t);if(null===o)return r(p.ENOENT(t));if(o.isDir())return r(p.EISDIR(t));var a=o.getData();switch(e.pathExistsAction()){case 1:case 2:return r(p.EEXIST(t));case 0:if(null!=a.file_data)return r(null,new s.NoSyncFile(i,t,e,a.clone(),a.file_data));this._requestFileAsync(t,"buffer",function(n,o){return n?r(n):(a.size=o.length,a.file_data=o,r(null,new s.NoSyncFile(i,t,e,a.clone(),o)))});break;default:return r(new p(9,"Invalid FileMode object."))}},e.prototype.openSync=function(t,e){if(e.isWriteable())throw new p(0,t);var n=this._index.getInode(t);if(null===n)throw p.ENOENT(t);if(n.isDir())throw p.EISDIR(t);var r=n.getData();switch(e.pathExistsAction()){case 1:case 2:throw p.EEXIST(t);case 0:if(null!=r.file_data)return new s.NoSyncFile(this,t,e,r.clone(),r.file_data);var i=this._requestFileSync(t,"buffer");return r.size=i.length,r.file_data=i,new s.NoSyncFile(this,t,e,r.clone(),i);default:throw new p(9,"Invalid FileMode object.")}},e.prototype.readdir=function(t,e){try{e(null,this.readdirSync(t))}catch(n){e(n)}},e.prototype.readdirSync=function(t){var e=this._index.getInode(t);if(null===e)throw p.ENOENT(t);if(e.isFile())throw p.ENOTDIR(t);return e.getListing()},e.prototype.readFile=function(t,e,n,r){var o=r;this.open(t,n,420,function(t,n){if(t)return r(t);r=function(t,e){n.close(function(n){return null==t&&(t=n),o(t,e)})}; +var a=n,s=a._buffer;if(null===e)return s.length>0?r(t,s.sliceCopy()):r(t,new i.Buffer(0));try{r(null,s.toString(e))}catch(u){r(u)}})},e.prototype.readFileSync=function(t,e,n){var r=this.openSync(t,n,420);try{var o=r,a=o._buffer;return null===e?a.length>0?a.sliceCopy():new i.Buffer(0):a.toString(e)}finally{r.closeSync()}},e}(n.BaseFileSystem);e.XmlHttpRequest=h,u.registerFileSystem("XmlHttpRequest",h)}),function(){function t(t){var n=!1;return function(){if(n)throw new Error("Callback was already called.");n=!0,t.apply(e,arguments)}}var e,n,r={};e=this,null!=e&&(n=e.async),r.noConflict=function(){return e.async=n,r};var i=function(t,e){if(t.forEach)return t.forEach(e);for(var n=0;n=e.length&&r(null))}))})},r.forEach=r.each,r.eachSeries=function(t,e,n){if(n=n||function(){},!t.length)return n();var r=0,i=function(){e(t[r],function(e){e?(n(e),n=function(){}):(r+=1,r>=t.length?n(null):i())})};i()},r.forEachSeries=r.eachSeries,r.eachLimit=function(t,e,n,r){var i=f(e);i.apply(null,[t,n,r])},r.forEachLimit=r.eachLimit;var f=function(t){return function(e,n,r){if(r=r||function(){},!e.length||0>=t)return r();var i=0,o=0,a=0;!function s(){if(i>=e.length)return r();for(;t>a&&o=e.length?r():s())})}()}},c=function(t){return function(){var e=Array.prototype.slice.call(arguments);return t.apply(null,[r.each].concat(e))}},p=function(t,e){return function(){var n=Array.prototype.slice.call(arguments);return e.apply(null,[f(t)].concat(n))}},h=function(t){return function(){var e=Array.prototype.slice.call(arguments);return t.apply(null,[r.eachSeries].concat(e))}},l=function(t,e,n,r){var i=[];e=o(e,function(t,e){return{index:e,value:t}}),t(e,function(t,e){n(t.value,function(n,r){i[t.index]=r,e(n)})},function(t){r(t,i)})};r.map=c(l),r.mapSeries=h(l),r.mapLimit=function(t,e,n,r){return d(e)(t,n,r)};var d=function(t){return p(t,l)};r.reduce=function(t,e,n,i){r.eachSeries(t,function(t,r){n(e,t,function(t,n){e=n,r(t)})},function(t){i(t,e)})},r.inject=r.reduce,r.foldl=r.reduce,r.reduceRight=function(t,e,n,i){var a=o(t,function(t){return t}).reverse();r.reduce(a,e,n,i)},r.foldr=r.reduceRight;var y=function(t,e,n,r){var i=[];e=o(e,function(t,e){return{index:e,value:t}}),t(e,function(t,e){n(t.value,function(n){n&&i.push(t),e()})},function(){r(o(i.sort(function(t,e){return t.index-e.index}),function(t){return t.value}))})};r.filter=c(y),r.filterSeries=h(y),r.select=r.filter,r.selectSeries=r.filterSeries;var g=function(t,e,n,r){var i=[];e=o(e,function(t,e){return{index:e,value:t}}),t(e,function(t,e){n(t.value,function(n){n||i.push(t),e()})},function(){r(o(i.sort(function(t,e){return t.index-e.index}),function(t){return t.value}))})};r.reject=c(g),r.rejectSeries=h(g);var w=function(t,e,n,r){t(e,function(t,e){n(t,function(n){n?(r(t),r=function(){}):e()})},function(){r()})};r.detect=c(w),r.detectSeries=h(w),r.some=function(t,e,n){r.each(t,function(t,r){e(t,function(t){t&&(n(!0),n=function(){}),r()})},function(){n(!1)})},r.any=r.some,r.every=function(t,e,n){r.each(t,function(t,r){e(t,function(t){t||(n(!1),n=function(){}),r()})},function(){n(!0)})},r.all=r.every,r.sortBy=function(t,e,n){r.map(t,function(t,n){e(t,function(e,r){e?n(e):n(null,{value:t,criteria:r})})},function(t,e){if(t)return n(t);var r=function(t,e){var n=t.criteria,r=e.criteria;return r>n?-1:n>r?1:0};n(null,o(e.sort(r),function(t){return t.value}))})},r.auto=function(t,e){e=e||function(){};var n=s(t);if(!n.length)return e(null);var o={},u=[],f=function(t){u.unshift(t)},c=function(t){for(var e=0;ee;e++)t[e].apply(null,arguments)}])))};return i.memo=n,i.unmemoized=t,i},r.unmemoize=function(t){return function(){return(t.unmemoized||t).apply(null,arguments)}},r.times=function(t,e,n){for(var i=[],o=0;t>o;o++)i.push(o);return r.map(i,e,n)},r.timesSeries=function(t,e,n){for(var i=[],o=0;t>o;o++)i.push(o);return r.mapSeries(i,e,n)},r.compose=function(){var t=Array.prototype.reverse.call(arguments);return function(){var e=this,n=Array.prototype.slice.call(arguments),i=n.pop();r.reduce(t,n,function(t,n,r){n.apply(e,t.concat([function(){var t=arguments[0],e=Array.prototype.slice.call(arguments,1);r(t,e)}]))},function(t,n){i.apply(e,[t].concat(n))})}};var E=function(t,e){var n=function(){var n=this,r=Array.prototype.slice.call(arguments),i=r.pop();return t(e,function(t,e){t.apply(n,r.concat([e]))},i)};if(arguments.length>2){var r=Array.prototype.slice.call(arguments,2);return n.apply(this,r)}return n};r.applyEach=c(E),r.applyEachSeries=h(E),r.forever=function(t,e){function n(r){if(r){if(e)return e(r);throw r}t(n)}n()},"undefined"!=typeof u&&u.amd?u("async",[],function(){return r}):"undefined"!=typeof module&&module.exports?module.exports=r:e.async=r}();var f=this.__extends||function(t,e){function n(){this.constructor=t}for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);n.prototype=e.prototype,t.prototype=new n};u("backend/dropbox",["require","exports","../generic/preload_file","../core/file_system","../core/node_fs_stats","../core/buffer","../core/api_error","../core/node_path","../core/browserfs","../core/buffer_core_arraybuffer","async"],function(t,e,n,r,i,o,a,s,u,c){var p=o.Buffer,h=i.Stats,l=a.ApiError;a.ErrorCode;var d=s.path;i.FileType;var y=t("async"),p=o.Buffer,g=function(t){function e(e,n,r,i,o){t.call(this,e,n,r,i,o)}return f(e,t),e.prototype.sync=function(t){var e=this._buffer,n=this._buffer.getBufferCore();n instanceof c.BufferCoreArrayBuffer||(e=new p(this._buffer.length),this._buffer.copy(e),n=e.getBufferCore());var r=n.getDataView(),i=new DataView(r.buffer,r.byteOffset+e.getOffset(),e.length);this._fs._writeFileStrict(this._path,i,t)},e.prototype.close=function(t){this.sync(t)},e}(n.PreloadFile);e.DropboxFile=g;var w=function(t){function e(e){t.call(this),this.client=e}return f(e,t),e.prototype.getName=function(){return"Dropbox"},e.isAvailable=function(){return"undefined"!=typeof Dropbox},e.prototype.isReadOnly=function(){return!1},e.prototype.supportsSymlinks=function(){return!1},e.prototype.supportsProps=function(){return!1},e.prototype.supportsSynch=function(){return!1},e.prototype.empty=function(t){var e=this;this.client.readdir("/",function(n,r,i,o){if(n)t(e.convert(n));else{var a=function(t,n){e.client.remove(t.path,function(t){n(t?e.convert(t):t)})},s=function(n){n?t(e.convert(n)):t()};y.each(o,a,s)}})},e.prototype.rename=function(t,e,n){this.client.move(t,e,function(r){if(r){var i=r.response.error.indexOf(t)>-1?t:e;n(new l(1,i+" doesn't exist"))}else n()})},e.prototype.stat=function(t,e,n){var r=this;this.client.stat(t,function(e,i){if(!(e||null!=i&&i.isRemoved)){var o=new h(r._statType(i),i.size);return n(null,o)}n(new l(1,t+" doesn't exist"))})},e.prototype.open=function(t,e,n,r){var i=this;this.client.readFile(t,{arrayBuffer:!0},function(n,o,a){if(!n){var s;s=null===o?new p(0):new p(o);var u=i._makeFile(t,e,a,s);return r(null,u)}if(e.isReadable())r(new l(1,t+" doesn't exist"));else switch(n.status){case 0:return console.error("No connection");case 404:var f=new ArrayBuffer(0);return i._writeFileStrict(t,f,function(n,o){if(n)r(n);else{var a=i._makeFile(t,e,o,new p(f));r(null,a)}});default:return console.log("Unhandled error: "+n)}})},e.prototype._writeFileStrict=function(t,e,n){var r=this,i=d.dirname(t);this.stat(i,!1,function(o){o?n(new l(1,"Can't create "+t+" because "+i+" doesn't exist")):r.client.writeFile(t,e,function(t,e){t?n(r.convert(t)):n(null,e)})})},e.prototype._statType=function(t){return t.isFile?32768:16384},e.prototype._makeFile=function(t,e,n,r){var i=this._statType(n),o=new h(i,n.size);return new g(this,t,e,o,r)},e.prototype._remove=function(t,e,n){var r=this;this.client.stat(t,function(i,o){i?e(new l(1,t+" doesn't exist")):o.isFile&&!n?e(new l(7,t+" is a file.")):!o.isFile&&n?e(new l(8,t+" is a directory.")):r.client.remove(t,function(n){n?e(new l(2,"Failed to remove "+t)):e(null)})})},e.prototype.unlink=function(t,e){this._remove(t,e,!0)},e.prototype.rmdir=function(t,e){this._remove(t,e,!1)},e.prototype.mkdir=function(t,e,n){var r=this,i=d.dirname(t);this.client.stat(i,function(e){e?n(new l(1,"Can't create "+t+" because "+i+" doesn't exist")):r.client.mkdir(t,function(e){e?n(new l(6,t+" already exists")):n(null)})})},e.prototype.readdir=function(t,e){var n=this;this.client.readdir(t,function(t,r){return t?e(n.convert(t)):e(null,r)})},e.prototype.convert=function(t,e){switch("undefined"==typeof e&&(e=""),t.status){case 400:return new l(9,e);case 401:case 403:return new l(2,e);case 404:return new l(1,e);case 405:return new l(14,e);case 0:case 304:case 406:case 409:default:return new l(2,e)}},e}(r.BaseFileSystem);e.DropboxFileSystem=w,u.registerFileSystem("Dropbox",w)});var f=this.__extends||function(t,e){function n(){this.constructor=t}for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);n.prototype=e.prototype,t.prototype=new n};u("backend/html5fs",["require","exports","../generic/preload_file","../core/file_system","../core/api_error","../core/file_flag","../core/node_fs_stats","../core/buffer","../core/browserfs","../core/buffer_core_arraybuffer","../core/node_path","../core/global","async"],function(t,e,n,r,i,o,a,s,u,c,p,h){function l(t,e,n,r){if("undefined"!=typeof navigator.webkitPersistentStorage)switch(t){case h.PERSISTENT:navigator.webkitPersistentStorage.requestQuota(e,n,r);break;case h.TEMPORARY:navigator.webkitTemporaryStorage.requestQuota(e,n,r);break;default:r(null)}else h.webkitStorageInfo.requestQuota(t,e,n,r)}function d(t){return Array.prototype.slice.call(t||[],0)}var y=s.Buffer,g=a.Stats;a.FileType;var w=i.ApiError;i.ErrorCode,o.ActionType;var m=t("async"),v=h.webkitRequestFileSystem||h.requestFileSystem||null,b=function(t){function e(e,n,r,i,o){t.call(this,e,n,r,i,o)}return f(e,t),e.prototype.sync=function(t){var e=this,n={create:!1},r=this._fs,i=function(n){n.createWriter(function(n){var i=e._buffer,o=e._buffer.getBufferCore();o instanceof c.BufferCoreArrayBuffer||(i=new y(e._buffer.length),e._buffer.copy(i),o=i.getBufferCore());var a=o.getDataView(),s=new DataView(a.buffer,a.byteOffset+i.getOffset(),i.length),u=new Blob([s]),f=u.size;n.onwriteend=function(){n.onwriteend=null,n.truncate(f),t()},n.onerror=function(e){t(r.convert(e))},n.write(u)})},o=function(e){t(r.convert(e))};r.fs.root.getFile(this._path,n,i,o)},e.prototype.close=function(t){this.sync(t)},e}(n.PreloadFile);e.HTML5FSFile=b;var E=function(t){function e(e,n){t.call(this),this.size=null!=e?e:5,this.type=null!=n?n:h.PERSISTENT;var r=1024,i=r*r;this.size*=i}return f(e,t),e.prototype.getName=function(){return"HTML5 FileSystem"},e.isAvailable=function(){return null!=v},e.prototype.isReadOnly=function(){return!1},e.prototype.supportsSymlinks=function(){return!1},e.prototype.supportsProps=function(){return!1},e.prototype.supportsSynch=function(){return!1},e.prototype.convert=function(t,e){switch("undefined"==typeof e&&(e=""),t.name){case"QuotaExceededError":return new w(11,e);case"NotFoundError":return new w(1,e);case"SecurityError":return new w(4,e);case"InvalidModificationError":return new w(0,e);case"SyntaxError":case"TypeMismatchError":return new w(9,e);default:return new w(9,e)}},e.prototype.convertErrorEvent=function(t,e){return"undefined"==typeof e&&(e=""),new w(1,t.message+"; "+e)},e.prototype.allocate=function(t){var e=this;"undefined"==typeof t&&(t=function(){});var n=function(n){e.fs=n,t()},r=function(n){t(e.convert(n))};this.type===h.PERSISTENT?l(this.type,this.size,function(t){v(e.type,t,n,r)},r):v(this.type,this.size,n,r)},e.prototype.empty=function(t){var e=this;this._readdir("/",function(n,r){if(n)console.error("Failed to empty FS"),t(n);else{var i=function(){n?(console.error("Failed to empty FS"),t(n)):t()},o=function(t,n){var r=function(){n()},i=function(r){n(e.convert(r,t.fullPath))};t.isFile?t.remove(r,i):t.removeRecursively(r,i)};m.each(r,o,i)}})},e.prototype.rename=function(t,e,n){var r=this,i=2,o=0,a=this.fs.root,s=function(o){0===--i&&n(r.convert(o,"Failed to rename "+t+" to "+e+"."))},u=function(i){return 2===++o?(console.error("Something was identified as both a file and a directory. This should never happen."),void 0):t===e?n():(a.getDirectory(p.path.dirname(e),{},function(o){i.moveTo(o,p.path.basename(e),function(){n()},function(o){i.isDirectory?r.unlink(e,function(i){i?s(o):r.rename(t,e,n)}):s(o)})},s),void 0)};a.getFile(t,{},u,s),a.getDirectory(t,{},u,s)},e.prototype.stat=function(t,e,n){var r=this,i={create:!1},o=function(t){var e=function(t){var e=new g(32768,t.size);n(null,e)};t.file(e,s)},a=function(){var t=4096,e=new g(16384,t);n(null,e)},s=function(e){n(r.convert(e,t))},u=function(){r.fs.root.getDirectory(t,i,a,s)};this.fs.root.getFile(t,i,o,u)},e.prototype.open=function(t,e,n,r){var i=this,o={create:3===e.pathNotExistsAction(),exclusive:e.isExclusive()},a=function(e){r(i.convertErrorEvent(e,t))},s=function(e){r(i.convert(e,t))},u=function(n){var o=function(n){var o=new FileReader;o.onloadend=function(){var a=i._makeFile(t,e,n,o.result);r(null,a)},o.onerror=a,o.readAsArrayBuffer(n)};n.file(o,s)};this.fs.root.getFile(t,o,u,a)},e.prototype._statType=function(t){return t.isFile?32768:16384},e.prototype._makeFile=function(t,e,n,r){"undefined"==typeof r&&(r=new ArrayBuffer(0));var i=new g(32768,n.size),o=new y(r);return new b(this,t,e,i,o)},e.prototype._remove=function(t,e,n){var r=this,i=function(n){var i=function(){e()},o=function(n){e(r.convert(n,t))};n.remove(i,o)},o=function(n){e(r.convert(n,t))},a={create:!1};n?this.fs.root.getFile(t,a,i,o):this.fs.root.getDirectory(t,a,i,o)},e.prototype.unlink=function(t,e){this._remove(t,e,!0)},e.prototype.rmdir=function(t,e){this._remove(t,e,!1)},e.prototype.mkdir=function(t,e,n){var r=this,i={create:!0,exclusive:!0},o=function(){n()},a=function(e){n(r.convert(e,t))};this.fs.root.getDirectory(t,i,o,a)},e.prototype._readdir=function(t,e){var n=this;this.fs.root.getDirectory(t,{create:!1},function(r){var i=r.createReader(),o=[],a=function(r){e(n.convert(r,t))},s=function(){i.readEntries(function(t){t.length?(o=o.concat(d(t)),s()):e(null,o)},a)};s()})},e.prototype.readdir=function(t,e){this._readdir(t,function(t,n){if(null!=t)return e(t);for(var r=[],i=0;i0&&t[0]instanceof i.ApiError&&s.standardizeError(t[0],o.path,r),a.apply(null,t)}}return o.fs[t].apply(o.fs,e)}}var u=i.ApiError;i.ErrorCode;var c=o.fs,p=function(t){function e(){t.call(this),this.mntMap={},this.rootFs=new r.InMemoryFileSystem}return f(e,t),e.prototype.mount=function(t,e){if(this.mntMap[t])throw new u(9,"Mount point "+t+" is already taken.");this.rootFs.mkdirSync(t,511),this.mntMap[t]=e},e.prototype.umount=function(t){if(!this.mntMap[t])throw new u(9,"Mount point "+t+" is already unmounted.");delete this.mntMap[t],this.rootFs.rmdirSync(t)},e.prototype._get_fs=function(t){for(var e in this.mntMap){var n=this.mntMap[e];if(0===t.indexOf(e))return t=t.substr(e.length>1?e.length:0),""===t&&(t="/"),{fs:n,path:t}}return{fs:this.rootFs,path:t}},e.prototype.getName=function(){return"MountableFileSystem"},e.isAvailable=function(){return!0},e.prototype.diskSpace=function(t,e){e(0,0)},e.prototype.isReadOnly=function(){return!1},e.prototype.supportsLinks=function(){return!1},e.prototype.supportsProps=function(){return!1},e.prototype.supportsSynch=function(){return!0},e.prototype.standardizeError=function(t,e,n){var r;return-1!==(r=t.message.indexOf(e))&&(t.message=t.message.substr(0,r)+n+t.message.substr(r+e.length)),t},e.prototype.rename=function(t,e,n){var r=this._get_fs(t),i=this._get_fs(e);if(r.fs===i.fs){var o=this;return r.fs.rename(r.path,i.path,function(a){a&&o.standardizeError(o.standardizeError(a,r.path,t),i.path,e),n(a)})}return c.readFile(t,function(r,i){return r?n(r):(c.writeFile(e,i,function(e){return e?n(e):(c.unlink(t,n),void 0)}),void 0)})},e.prototype.renameSync=function(t,e){var n=this._get_fs(t),r=this._get_fs(e);if(n.fs===r.fs)try{return n.fs.renameSync(n.path,r.path)}catch(i){throw this.standardizeError(this.standardizeError(i,n.path,t),r.path,e),i}var o=c.readFileSync(t);return c.writeFileSync(e,o),c.unlinkSync(t)},e}(n.BaseFileSystem);e.MountableFileSystem=p;for(var h=[["readdir","exists","unlink","rmdir","readlink"],["stat","mkdir","realpath","truncate"],["open","readFile","chmod","utimes"],["chown"],["writeFile","appendFile"]],l=0;lf;++f)t[f]>h&&(h=t[f]),t[f]=r;){for(f=0;p>f;++f)if(t[f]===r){for(a=0,s=i,c=0;r>c;++c)a=a<<1|1&s,s>>=1;for(c=a;e>c;c+=o)n[c]=r<<16|f;++i}++r,i<<=1,o<<=1}return[n,h,l]}function n(t,e){switch(this.g=[],this.h=32768,this.c=this.f=this.d=this.k=0,this.input=u?new Uint8Array(t):t,this.l=!1,this.i=c,this.p=!1,(e||!(e={}))&&(e.index&&(this.d=e.index),e.bufferSize&&(this.h=e.bufferSize),e.bufferType&&(this.i=e.bufferType),e.resize&&(this.p=e.resize)),this.i){case f:this.a=32768,this.b=new(u?Uint8Array:Array)(32768+this.h+258);break;case c:this.a=0,this.b=new(u?Uint8Array:Array)(this.h),this.e=this.u,this.m=this.r,this.j=this.s;break;default:throw Error("invalid inflate mode")}}function r(t,e){for(var n,r=t.f,i=t.c,o=t.input,s=t.d;e>i;){if(n=o[s++],n===a)throw Error("input buffer is broken");r|=n<>>e,t.c=i-e,t.d=s,n}function i(t,e){for(var n,r,i,o=t.f,s=t.c,u=t.input,f=t.d,c=e[0],p=e[1];p>s&&(n=u[f++],n!==a);)o|=n<>>16,t.f=o>>i,t.c=s-i,t.d=f,65535&r}function o(t){function n(t,e,n){var o,a,s,u;for(u=0;t>u;)switch(o=i(this,e)){case 16:for(s=3+r(this,2);s--;)n[u++]=a;break;case 17:for(s=3+r(this,3);s--;)n[u++]=0;a=0;break;case 18:for(s=11+r(this,7);s--;)n[u++]=0;a=0;break;default:a=n[u++]=o}return n}var o,a,s,f,c=r(t,5)+257,p=r(t,5)+1,h=r(t,4)+4,l=new(u?Uint8Array:Array)(d.length);for(f=0;h>f;++f)l[d[f]]=r(t,3);o=e(l),a=new(u?Uint8Array:Array)(c),s=new(u?Uint8Array:Array)(p),t.j(e(n.call(t,c,o,a)),e(n.call(t,p,o,s)))}var a=void 0,s=this,u="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,f=0,c=1;n.prototype.t=function(){for(;!this.l;){var t=r(this,3);switch(1&t&&(this.l=!0),t>>>=1){case 0:var e=this.input,n=this.d,i=this.b,s=this.a,p=a,h=a,l=a,d=i.length,y=a;if(this.c=this.f=0,p=e[n++],p===a)throw Error("invalid uncompressed block header: LEN (first byte)");if(h=p,p=e[n++],p===a)throw Error("invalid uncompressed block header: LEN (second byte)");if(h|=p<<8,p=e[n++],p===a)throw Error("invalid uncompressed block header: NLEN (first byte)");if(l=p,p=e[n++],p===a)throw Error("invalid uncompressed block header: NLEN (second byte)");if(l|=p<<8,h===~l)throw Error("invalid uncompressed block header: length verify");if(n+h>e.length)throw Error("input buffer is broken");switch(this.i){case f:for(;s+h>i.length;){if(y=d-s,h-=y,u)i.set(e.subarray(n,n+y),s),s+=y,n+=y;else for(;y--;)i[s++]=e[n++];this.a=s,i=this.e(),s=this.a}break;case c:for(;s+h>i.length;)i=this.e({o:2});break;default:throw Error("invalid inflate mode")}if(u)i.set(e.subarray(n,n+h),s),s+=h,n+=h;else for(;h--;)i[s++]=e[n++];this.d=n,this.a=s,this.b=i;break;case 1:this.j(A,N);break;case 2:o(this);break;default:throw Error("unknown BTYPE: "+t)}}return this.m()};var p,h,l=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],d=u?new Uint16Array(l):l,y=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],g=u?new Uint16Array(y):y,w=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],m=u?new Uint8Array(w):w,v=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],b=u?new Uint16Array(v):v,E=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],S=u?new Uint8Array(E):E,I=new(u?Uint8Array:Array)(288);for(p=0,h=I.length;h>p;++p)I[p]=143>=p?8:255>=p?9:279>=p?7:8;var _,F,A=e(I),x=new(u?Uint8Array:Array)(30);for(_=0,F=x.length;F>_;++_)x[_]=5;var N=e(x);n.prototype.j=function(t,e){var n=this.b,o=this.a;this.n=t;for(var a,s,u,f,c=n.length-258;256!==(a=i(this,t));)if(256>a)o>=c&&(this.a=o,n=this.e(),o=this.a),n[o++]=a;else for(s=a-257,f=g[s],0=c&&(this.a=o,n=this.e(),o=this.a);f--;)n[o]=n[o++-u];for(;8<=this.c;)this.c-=8,this.d--;this.a=o},n.prototype.s=function(t,e){var n=this.b,o=this.a;this.n=t;for(var a,s,u,f,c=n.length;256!==(a=i(this,t));)if(256>a)o>=c&&(n=this.e(),c=n.length),n[o++]=a;else for(s=a-257,f=g[s],0c&&(n=this.e(),c=n.length);f--;)n[o]=n[o++-u];for(;8<=this.c;)this.c-=8,this.d--;this.a=o},n.prototype.e=function(){var t,e,n=new(u?Uint8Array:Array)(this.a-32768),r=this.a-32768,i=this.b;if(u)n.set(i.subarray(32768,n.length));else for(t=0,e=n.length;e>t;++t)n[t]=i[t+32768];if(this.g.push(n),this.k+=n.length,u)i.set(i.subarray(r,r+32768));else for(t=0;32768>t;++t)i[t]=i[r+t];return this.a=32768,i},n.prototype.u=function(t){var e,n,r,i,o=0|this.input.length/this.d+1,a=this.input,s=this.b;return t&&("number"==typeof t.o&&(o=t.o),"number"==typeof t.q&&(o+=t.q)),2>o?(n=(a.length-this.d)/this.n[2],i=0|258*(n/2),r=ie;++e)for(t=s[e],r=0,i=t.length;i>r;++r)f[o++]=t[r];for(e=32768,n=this.a;n>e;++e)f[o++]=a[e];return this.g=[],this.buffer=f},n.prototype.r=function(){var t,e=this.a;return u?this.p?(t=new Uint8Array(e),t.set(this.b.subarray(0,e))):t=this.b.subarray(0,e):(this.b.length>e&&(this.b.length=e),t=this.b),this.buffer=t},t("Zlib.RawInflate",n),t("Zlib.RawInflate.prototype.decompress",n.prototype.t);var L,U,D,T,O={ADAPTIVE:c,BLOCK:f};if(Object.keys)L=Object.keys(O);else for(U in L=[],D=0,O)L[D++]=U;for(D=0,T=L.length;T>D;++D)U=L[D],t("Zlib.RawInflate.BufferType."+U,O[U])}.call(this),u("zlib",function(t){return function(){var e;return e||t.Zlib.RawInflate}}(this));var f=this.__extends||function(t,e){function n(){this.constructor=t}for(var r in e)e.hasOwnProperty(r)&&(t[r]=e[r]);n.prototype=e.prototype,t.prototype=new n};u("backend/zipfs",["require","exports","../core/buffer","../core/api_error","../generic/file_index","../core/browserfs","../core/node_fs_stats","../core/file_system","../core/file_flag","../core/buffer_core_arraybuffer","../generic/preload_file","zlib"],function(t,e,n,r,i,o,a,s,u,c,p){function h(t,e){var n=31&e,r=(15&e>>5)-1,i=(e>>9)+1980,o=31&t,a=63&t>>5,s=t>>11;return new Date(i,r,n,s,a,o)}function l(t,e,n,r){return 0===r?"":t.toString(e?"utf8":"extended_ascii",n,n+r)}var d=r.ApiError;r.ErrorCode,u.ActionType;var y=Zlib.RawInflate;!function(t){t[t.MSDOS=0]="MSDOS",t[t.AMIGA=1]="AMIGA",t[t.OPENVMS=2]="OPENVMS",t[t.UNIX=3]="UNIX",t[t.VM_CMS=4]="VM_CMS",t[t.ATARI_ST=5]="ATARI_ST",t[t.OS2_HPFS=6]="OS2_HPFS",t[t.MAC=7]="MAC",t[t.Z_SYSTEM=8]="Z_SYSTEM",t[t.CP_M=9]="CP_M",t[t.NTFS=10]="NTFS",t[t.MVS=11]="MVS",t[t.VSE=12]="VSE",t[t.ACORN_RISC=13]="ACORN_RISC",t[t.VFAT=14]="VFAT",t[t.ALT_MVS=15]="ALT_MVS",t[t.BEOS=16]="BEOS",t[t.TANDEM=17]="TANDEM",t[t.OS_400=18]="OS_400",t[t.OSX=19]="OSX" +}(e.ExternalFileAttributeType||(e.ExternalFileAttributeType={})),e.ExternalFileAttributeType,function(t){t[t.STORED=0]="STORED",t[t.SHRUNK=1]="SHRUNK",t[t.REDUCED_1=2]="REDUCED_1",t[t.REDUCED_2=3]="REDUCED_2",t[t.REDUCED_3=4]="REDUCED_3",t[t.REDUCED_4=5]="REDUCED_4",t[t.IMPLODE=6]="IMPLODE",t[t.DEFLATE=8]="DEFLATE",t[t.DEFLATE64=9]="DEFLATE64",t[t.TERSE_OLD=10]="TERSE_OLD",t[t.BZIP2=12]="BZIP2",t[t.LZMA=14]="LZMA",t[t.TERSE_NEW=18]="TERSE_NEW",t[t.LZ77=19]="LZ77",t[t.WAVPACK=97]="WAVPACK",t[t.PPMD=98]="PPMD"}(e.CompressionMethod||(e.CompressionMethod={}));var g=e.CompressionMethod,w=function(){function t(t){if(this.data=t,67324752!==t.readUInt32LE(0))throw new d(9,"Invalid Zip file: Local file header has invalid signature: "+this.data.readUInt32LE(0))}return t.prototype.versionNeeded=function(){return this.data.readUInt16LE(4)},t.prototype.flags=function(){return this.data.readUInt16LE(6)},t.prototype.compressionMethod=function(){return this.data.readUInt16LE(8)},t.prototype.lastModFileTime=function(){return h(this.data.readUInt16LE(10),this.data.readUInt16LE(12))},t.prototype.crc32=function(){return this.data.readUInt32LE(14)},t.prototype.fileNameLength=function(){return this.data.readUInt16LE(26)},t.prototype.extraFieldLength=function(){return this.data.readUInt16LE(28)},t.prototype.fileName=function(){return l(this.data,this.useUTF8(),30,this.fileNameLength())},t.prototype.extraField=function(){var t=30+this.fileNameLength();return this.data.slice(t,t+this.extraFieldLength())},t.prototype.totalSize=function(){return 30+this.fileNameLength()+this.extraFieldLength()},t.prototype.useUTF8=function(){return 2048===(2048&this.flags())},t}();e.FileHeader=w;var m=function(){function t(t,e,n){this.header=t,this.record=e,this.data=n}return t.prototype.decompress=function(){var t=this.data,e=this.header.compressionMethod();switch(e){case 8:if(t.getBufferCore()instanceof c.BufferCoreArrayBuffer){var r=t.getBufferCore(),i=r.getDataView(),o=i.byteOffset+t.getOffset(),a=new Uint8Array(i.buffer).subarray(o,o+this.record.compressedSize()),s=new y(a).decompress();return new n.Buffer(new c.BufferCoreArrayBuffer(s.buffer),s.byteOffset,s.byteOffset+s.length)}var u=t.slice(0,this.record.compressedSize());return new n.Buffer(new y(u.toJSON().data).decompress());case 0:return t.sliceCopy(0,this.record.uncompressedSize());default:var f=g[e];throw f=f?f:"Unknown: "+e,new d(9,"Invalid compression method on file '"+this.header.fileName()+"': "+f)}},t}();e.FileData=m;var v=function(){function t(t){this.data=t}return t.prototype.crc32=function(){return this.data.readUInt32LE(0)},t.prototype.compressedSize=function(){return this.data.readUInt32LE(4)},t.prototype.uncompressedSize=function(){return this.data.readUInt32LE(8)},t}();e.DataDescriptor=v;var b=function(){function t(t){if(this.data=t,134630224!==this.data.readUInt32LE(0))throw new d(9,"Invalid archive extra data record signature: "+this.data.readUInt32LE(0))}return t.prototype.length=function(){return this.data.readUInt32LE(4)},t.prototype.extraFieldData=function(){return this.data.slice(8,8+this.length())},t}();e.ArchiveExtraDataRecord=b;var E=function(){function t(t){if(this.data=t,84233040!==this.data.readUInt32LE(0))throw new d(9,"Invalid digital signature signature: "+this.data.readUInt32LE(0))}return t.prototype.size=function(){return this.data.readUInt16LE(4)},t.prototype.signatureData=function(){return this.data.slice(6,6+this.size())},t}();e.DigitalSignature=E;var S=function(){function t(t,e){if(this.zipData=t,this.data=e,33639248!==this.data.readUInt32LE(0))throw new d(9,"Invalid Zip file: Central directory record has invalid signature: "+this.data.readUInt32LE(0))}return t.prototype.versionMadeBy=function(){return this.data.readUInt16LE(4)},t.prototype.versionNeeded=function(){return this.data.readUInt16LE(6)},t.prototype.flag=function(){return this.data.readUInt16LE(8)},t.prototype.compressionMethod=function(){return this.data.readUInt16LE(10)},t.prototype.lastModFileTime=function(){return h(this.data.readUInt16LE(12),this.data.readUInt16LE(14))},t.prototype.crc32=function(){return this.data.readUInt32LE(16)},t.prototype.compressedSize=function(){return this.data.readUInt32LE(20)},t.prototype.uncompressedSize=function(){return this.data.readUInt32LE(24)},t.prototype.fileNameLength=function(){return this.data.readUInt16LE(28)},t.prototype.extraFieldLength=function(){return this.data.readUInt16LE(30)},t.prototype.fileCommentLength=function(){return this.data.readUInt16LE(32)},t.prototype.diskNumberStart=function(){return this.data.readUInt16LE(34)},t.prototype.internalAttributes=function(){return this.data.readUInt16LE(36)},t.prototype.externalAttributes=function(){return this.data.readUInt32LE(38)},t.prototype.headerRelativeOffset=function(){return this.data.readUInt32LE(42)},t.prototype.fileName=function(){var t=l(this.data,this.useUTF8(),46,this.fileNameLength());return t.replace(/\\/g,"/")},t.prototype.extraField=function(){var t=44+this.fileNameLength();return this.data.slice(t,t+this.extraFieldLength())},t.prototype.fileComment=function(){var t=46+this.fileNameLength()+this.extraFieldLength();return l(this.data,this.useUTF8(),t,this.fileCommentLength())},t.prototype.totalSize=function(){return 46+this.fileNameLength()+this.extraFieldLength()+this.fileCommentLength()},t.prototype.isDirectory=function(){var t=this.fileName();return(16&this.externalAttributes()?!0:!1)||"/"===t.charAt(t.length-1)},t.prototype.isFile=function(){return!this.isDirectory()},t.prototype.useUTF8=function(){return 2048===(2048&this.flag())},t.prototype.isEncrypted=function(){return 1===(1&this.flag())},t.prototype.getData=function(){var t=this.headerRelativeOffset(),e=new w(this.zipData.slice(t)),n=new m(e,this,this.zipData.slice(t+e.totalSize()));return n.decompress()},t.prototype.getStats=function(){return new a.Stats(32768,this.uncompressedSize(),365,new Date,this.lastModFileTime())},t}();e.CentralDirectory=S;var I=function(){function t(t){if(this.data=t,101010256!==this.data.readUInt32LE(0))throw new d(9,"Invalid Zip file: End of central directory record has invalid signature: "+this.data.readUInt32LE(0))}return t.prototype.diskNumber=function(){return this.data.readUInt16LE(4)},t.prototype.cdDiskNumber=function(){return this.data.readUInt16LE(6)},t.prototype.cdDiskEntryCount=function(){return this.data.readUInt16LE(8)},t.prototype.cdTotalEntryCount=function(){return this.data.readUInt16LE(10)},t.prototype.cdSize=function(){return this.data.readUInt32LE(12)},t.prototype.cdOffset=function(){return this.data.readUInt32LE(16)},t.prototype.cdZipComment=function(){return l(this.data,!0,22,this.data.readUInt16LE(20))},t}();e.EndOfCentralDirectory=I;var _=function(t){function e(e,n){"undefined"==typeof n&&(n=""),t.call(this),this.data=e,this.name=n,this._index=new i.FileIndex,this.populateIndex()}return f(e,t),e.prototype.getName=function(){return"ZipFS"+(""!==this.name?" "+this.name:"")},e.isAvailable=function(){return!0},e.prototype.diskSpace=function(t,e){e(this.data.length,0)},e.prototype.isReadOnly=function(){return!0},e.prototype.supportsLinks=function(){return!1},e.prototype.supportsProps=function(){return!1},e.prototype.supportsSynch=function(){return!0},e.prototype.statSync=function(t){var e=this._index.getInode(t);if(null===e)throw new d(1,""+t+" not found.");var n;return n=e.isFile()?e.getData().getStats():e.getStats()},e.prototype.openSync=function(t,e){if(e.isWriteable())throw new d(0,t);var n=this._index.getInode(t);if(null===n)throw new d(1,""+t+" is not in the FileIndex.");if(n.isDir())throw new d(8,""+t+" is a directory.");var r=n.getData(),i=r.getStats();switch(e.pathExistsAction()){case 1:case 2:throw new d(6,""+t+" already exists.");case 0:return new p.NoSyncFile(this,t,e,i,r.getData());default:throw new d(9,"Invalid FileMode object.")}return null},e.prototype.readdirSync=function(t){var e=this._index.getInode(t);if(null===e)throw new d(1,""+t+" not found.");if(e.isFile())throw new d(7,""+t+" is a file, not a directory.");return e.getListing()},e.prototype.readFileSync=function(t,e,r){var i=this.openSync(t,r,420);try{var o=i,a=o._buffer;return null===e?a.length>0?a.sliceCopy():new n.Buffer(0):a.toString(e)}finally{i.closeSync()}},e.prototype.getEOCD=function(){for(var t=22,e=Math.min(t+65535,this.data.length-1),n=t;e>n;n++)if(101010256===this.data.readUInt32LE(this.data.length-n))return new I(this.data.slice(this.data.length-n));throw new d(9,"Invalid ZIP file: Could not locate End of Central Directory signature.")},e.prototype.populateIndex=function(){var t=this.getEOCD();if(t.diskNumber()!==t.cdDiskNumber())throw new d(9,"ZipFS does not support spanned zip files.");var e=t.cdOffset();if(4294967295===e)throw new d(9,"ZipFS does not support Zip64.");for(var n=e+t.cdSize();n>e;){var r=new S(this.data,this.data.slice(e));e+=r.totalSize();var o=r.fileName();if("/"===o.charAt(0))throw new Error("WHY IS THIS ABSOLUTE");"/"===o.charAt(o.length-1)&&(o=o.substr(0,o.length-1)),r.isDirectory()?this._index.addPath("/"+o,new i.DirInode):this._index.addPath("/"+o,new i.FileInode(r))}},e}(s.SynchronousFileSystem);e.ZipFS=_,o.registerFileSystem("ZipFS",_)}),s("core/global").BrowserFS=s("core/browserfs"),s("generic/emscripten_fs"),s("backend/IndexedDB"),s("backend/XmlHttpRequest"),s("backend/dropbox"),s("backend/html5fs"),s("backend/in_memory"),s("backend/localStorage"),s("backend/mountable_file_system"),s("backend/zipfs")}(); diff --git a/emdosbox-launcher.js b/emdosbox-launcher.js deleted file mode 100644 index a4f6aa4..0000000 --- a/emdosbox-launcher.js +++ /dev/null @@ -1,191 +0,0 @@ -var ar = new Array(33,34,35,36,37,38,39,40); - -function getfullscreenenabler() { - return canvas.webkitRequestFullScreen || canvas.mozRequestFullScreen || canvas.requestFullScreen; -} - -function getpointerlockenabler() { - return canvas.requestPointerLock || canvas.mozRequestPointerLock || canvas.webkitRequestPointerLock; -} - -function isfullscreensupported() { - return !!(getfullscreenenabler()); -} - -function gofullscreen() { - Module.requestFullScreen(1,0); -} - -function keypress(e) { - if (typeof(loader_game)=='object' && !loader_game.started) - return true; // Don't ignore certain keys yet (until game started by "click to play") - - var key = e.which; - if($.inArray(key,ar) > -1) { - e.preventDefault(); //Don't let arrow, pg up/down, home, end affect page position - return false; - } - return true; -} - -window.onkeydown = keypress; - -(function() { - function get(name) { - if (typeof(loader_game)=='object') - return loader_game[name]; //alternate case where dont have CGI args to parse... - if ((name = (new RegExp('[?&]'+encodeURIComponent(name)+'=([^&]*)')).exec(location.search))) { - return decodeURIComponent(name[1]); - } - } - - var games; - var emulator; - var module; - - function getmodule() { - module = get('module'); - module = module ? module : 'test'; - } - - function init() { - getmodule(); - ready(); - } - - function ready() { - var fullscreenbutton = document.getElementById('gofullscreen'); - if (fullscreenbutton) { - if (isfullscreensupported()) { - fullscreenbutton.addEventListener('click', gofullscreen); - if ('onfullscreenchange' in document) { - document.addEventListener('fullscreenchange', DOSBOX.fullScreenChangeHandler); - } else if ('onmozfullscreenchange' in document) { - document.addEventListener('mozfullscreenchange', DOSBOX.fullScreenChangeHandler); - } else if ('onwebkitfullscreenchange' in document) { - document.addEventListener('webkitfullscreenchange', DOSBOX.fullScreenChangeHandler); - } - } else { - fullscreenbutton.disabled = true; - } - } - var canvas = document.getElementById('canvas'); - emulator = new DOSBOX(canvas).setscale(get('scale') ? parseFloat(get('scale')) : 1) - .setmodule(module) - .setgame(getgameurl(loader_game)); - disableRightClickContextMenu(canvas); - - // Emscripten doesn't use the proper prefixed functions for fullscreen requests, - // so let's map the prefixed versions to the correct function. - canvas.requestPointerLock = getpointerlockenabler(); - - if (get('autostart')) { - emulator.start(); - } - // Gamepad text - if (detectgamepadsupport()) { - var gamepadDiv = document.getElementById('gamepadtext'); - gamepadDiv.innerHTML = "No gamepads detected. Press a button on a gamepad to use it."; - listenforgamepads(function(gamepads, newgamepad) { - var s = (gamepads.length === 1 ? '' : 's'); - gamepadDiv.innerHTML = gamepads.length + ' gamepad'+s+' detected. If the game does not ' + - 'respond to your gamepad'+s+', refresh the browser and try again.'; - if (emulator.hasStarted) { - gamepadDiv.innerHTML += "
Restart MESS to use new gamepads."; - } - }); - } - } - - function getgameurl(game) { - // NOTE: deliberately use cors.archive.org since this will 302 rewrite to iaXXXXX.us.archive.org/XX/items/... - // and need to keep that "artificial" extra domain-ish name to avoid CORS issues with IE/Safari - return (game === 'NONE') ? undefined - : ('//cors.archive.org/cors/'+ game); - } - - /** - * Disables the right click menu for the given element. - */ - function disableRightClickContextMenu(element) { - element.addEventListener('contextmenu', function(e) { - if (e.button == 2) { - // Block right-click menu thru preventing default action. - e.preventDefault(); - } - }); - } - - function switchgame(e) { - emulator.setgame(getgameurl(e.target.value)); - } - - // Firefox will not give us Joystick data unless we register this NOP - // callback. - // https://bugzilla.mozilla.org/show_bug.cgi?id=936104 - addEventListener("gamepadconnected", function() {}); - var getgamepads = navigator.getGamepads || navigator.webkitGamepads || - navigator.mozGamepads || navigator.gamepads || navigator.webkitGetGamepads; - /** - * Does the current browser support the Gamepad API? - * Returns a boolean. - */ - function detectgamepadsupport() { - return typeof getgamepads === 'function'; - } - // The timer that listens for gamepads, in case we ever want to stop it. - var gamepadlistener; - /** - * Listens for new gamepads, and triggers the callback when it detects a - * change. - * The callback is passed an array of active gamepads. - */ - function listenforgamepads(cb, freq) { - // NOP if the browser doesn't support gamepads. - if (!detectgamepadsupport()) return; - // Map from gamepad id to gamepad information. - var prevgamepads = {}; - // DEFAULT: Check gamepads every second. - if (typeof freq === 'undefined') freq = 1000; - gamepadlistener = setInterval(function() { - // Browsers get cranky when you don't apply this on the navigator object. - var gamepads = getgamepads.apply(navigator); - var currentgamepads = {}; - var i; - var hasChanged = false; - for (i = 0; i < gamepads.length; i++) { - var gamepad = gamepads[i]; - if (gamepad != null) { - currentgamepads[gamepad.id] = gamepad; - if (!prevgamepads.hasOwnProperty(gamepad.id)) { - // Gamepad has been added. - hasChanged = true; - } - } - } - - // Has a gamepad been removed? - if (!hasChanged) { - for (var gamepadid in prevgamepads) { - if (!currentgamepads.hasOwnProperty(gamepadid)) { - hasChanged = true; - } - } - } - - prevgamepads = currentgamepads; - - if (hasChanged) { - // Actual gamepads, filtered from gamepads. Chrome puts empty items into - // its gamepadlist. - var actualgamepads = []; - for (i = 0; i < gamepads.length; i++) { - if (gamepads[i] != null) actualgamepads.push(gamepads[i]); - } - cb(actualgamepads); - } - }, freq); - } - - window.addEventListener('load', init); -})(); diff --git a/emdosbox-loader.js b/emdosbox-loader.js deleted file mode 100644 index 2ba596d..0000000 --- a/emdosbox-loader.js +++ /dev/null @@ -1,437 +0,0 @@ -var Module = null; - -function DOSBOX(canvas, module, game, precallback, callback, scale) { - var js_url; - var moduledata; - var requests = []; - var drawloadingtimer; - var file_countdown; - var spinnerrot = 0; - var splashimg = new Image(); - var spinnerimg = new Image(); - // TODO: Have an enum value that communicates the current state of DOSBOX, e.g. 'initializing', 'loading', 'running'. - var has_started = false; - var loading = false; - var LOADING_TEXT; - var splash_inverse = getComputedStyle(document.getElementsByTagName("body")[0]).backgroundColor === 'rgb(0, 0, 0)'; - - var SAMPLE_RATE = (function () { - var audio_ctx = window.AudioContext || window.webkitAudioContext || false; - if (!audio_ctx) { - return false; - } - var sample = new audio_ctx; - return sample.sampleRate.toString(); - }()); - - // right off the bat we set the canvas's inner dimensions to - // whatever it's current css dimensions are; this isn't likely to be - // the same size that dosbox/jsmess will set it to, but it avoids - // the case where the size was left at the default 300x150 - if (!canvas.hasAttribute("width")) { - canvas.width = parseInt(getComputedStyle(canvas).width, 10); - canvas.height = parseInt(getComputedStyle(canvas).height, 10); - } - - var can_start = function () { - return !!canvas && !!module && !!game && !!scale && !has_started; - }; - - this.setscale = function(_scale) { - scale = _scale; - try_start(); - return this; - }; - - this.setprecallback = function(_precallback) { - precallback = _precallback; - return this; - }; - - this.setcallback = function(_callback) { - callback = _callback; - return this; - }; - - this.setmodule = function(_module) { - module = _module; - try_start(); - return this; - }; - - this.setgame = function(_game) { - game = _game; - try_start(); - return this; - }; - - var draw_loading_status = function() { - var context = canvas.getContext('2d'); - context.clearRect(0, 0, canvas.width, canvas.height); - context.drawImage(splashimg, canvas.width / 2 - (splashimg.width / 2), canvas.height / 3 - (splashimg.height / 2)); - var spinnerpos = (canvas.height / 2 + splashimg.height / 2) + 16; - context.save(); - context.translate((canvas.width / 2), spinnerpos); - context.rotate(spinnerrot); - context.drawImage(spinnerimg, -(64/2), -(64/2), 64, 64); - context.restore(); - context.save(); - context.font = '18px sans-serif'; - context.fillStyle = splash_inverse ? 'white' : 'black'; - context.textAlign = 'center'; - context.fillText(LOADING_TEXT, canvas.width / 2, (canvas.height / 2) + (splashimg.height / 4)); - context.restore(); - spinnerrot += .25; - }; - - var progress_fetch_file = function(e) { - if (e.lengthComputable) { - e.target.progress = e.loaded / e.total; - e.target.loaded = e.loaded; - e.target.total = e.total; - e.target.lengthComputable = e.lengthComputable; - } - }; - - var fetch_file = function(title, url, cb, rt, raw, unmanaged) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.responseType = rt ? rt : 'arraybuffer'; - xhr.onload = function(e) { - if (xhr.status != 200) { - return; - } - if (!unmanaged) { - xhr.progress = 1.0; - } - var ints = raw ? xhr.response : new Int8Array(xhr.response); - cb(ints); - }; - if (!unmanaged) { - xhr.onprogress = progress_fetch_file; - xhr.title = title; - xhr.progress = 0; - xhr.total = 0; - xhr.loaded = 0; - xhr.lengthComputable = false; - requests.push(xhr); - } - xhr.send(); - }; - - var update_countdown = function() { - file_countdown -= 1; - if (file_countdown <= 0) { - loading = false; - - if (js_url) { - var head = document.getElementsByTagName('head')[0]; - var newScript = document.createElement('script'); - newScript.type = 'text/javascript'; - newScript.src = get_js_url(js_url); - head.appendChild(newScript); - } - - // see archive.js for the mute/unmute button/JS - if (!($.cookie && $.cookie('unmute'))){ - setTimeout(function(){ - // someone moved it from 1st to 2nd! - if (DOSBOX && typeof(DOSBOX.sdl_pauseaudio)!='undefined') - DOSBOX.sdl_pauseaudio(1); - else if (typeof _SDL_PauseAudio !== "undefined") - _SDL_PauseAudio(1); - }, 3000); - } - } - }; - - var build_dosbox_arguments = function (config, emulator_start) { - LOADING_TEXT = 'Building arguments'; - return ['/dosprogram/'+ emulator_start]; - }; - - var get_game_name = function (game_path) { - return game_path.split('/').pop(); - }; - - var get_meta_url = function (game_path) { - var path = game_path.split('/'); - // NOTE: deliberately use cors.archive.org since this will 302 rewrite to iaXXXXX.us.archive.org/XX/items/... - // and need to keep that "artificial" extra domain-ish name to avoid CORS issues with IE/Safari - return "//cors.archive.org/cors/"+ path[4] +"/"+ path[4] +"_meta.xml"; - }; - - var get_js_url = function (js_filename) { - // NOTE: deliberately use cors.archive.org since this will 302 rewrite to iaXXXXX.us.archive.org/XX/items/... - // and need to keep that "artificial" extra domain-ish name to avoid CORS issues with IE/Safari - return "//cors.archive.org/cors/jsmess_engine_v2/"+ js_filename; - }; - - var init_module = function() { - if (moduledata == null) { - // HACK: Module data isn't ready yet. It'll call us once loaded. - return; - } - LOADING_TEXT = 'Loading Program'; - var modulecfg = JSON.parse(moduledata); - js_url = modulecfg['js_filename']; - - var game_file = null, - meta_file = null; - - var nr = modulecfg['native_resolution']; - DOSBOX.width = nr[0] * scale; - DOSBOX.height = nr[1] * scale; - - // Makes the keyboard 'focusable' to let the canvas accept keyboard input. - // http://gamedev.stackexchange.com/questions/50223/receiving-keyboard-events-on-a-canvas-in-javascript - canvas.setAttribute('tabindex', '0'); - // Emscripten blocks the 'default action' of all mouse events, which - // prevents users from selecting the canvas for keyboard input! - // Prevent Emscripten from blocking users from selecting the canvas by - // manually 'focusing' the canvas when it is clicked. - canvas.addEventListener('mousedown', function() { - canvas.focus(); - }); - // Start the canvas focused. - canvas.focus(); - - Module = { - arguments: undefined, - screenIsReadOnly: true, - print: (function() { - return function(text) { - console.log(text); - }; - })(), - canvas: canvas, - // Prevent Emscripten from listening / blocking key events to the rest of the page by - // isolating keyboard input to the canvas. - keyboardListeningElement: canvas, - noInitialRun: false, - locateFile: function (file) { - if ("file_locations" in modulecfg && file in modulecfg.file_locations) { - return get_js_url(modulecfg.file_locations[file]); - } - throw new Error("Don't know how to find file: "+ file); - }, - preInit: function() { - Module.arguments = build_dosbox_arguments(modulecfg, - meta_file.getElementsByTagName("emulator_start") - .item(0) - .textContent);; - LOADING_TEXT = 'Loading game file into file system'; - DOSBOX.BFSMountZip(game_file); - DOSBOX.moveConfigToRoot(); - window.clearInterval(drawloadingtimer); - if (callback) { - modulecfg.canvas = canvas; - window.setTimeout(function() { callback(modulecfg); }, 0); - } - } - }; - - file_countdown = 2; - - fetch_file('Metadata', - get_meta_url(game), - function(data) { - meta_file = data; - update_countdown(); - }, - 'document', true); - fetch_file('Game', - game, - function(data) { - game_file = new BrowserFS.BFSRequire('buffer').Buffer(data); - update_countdown(); - }); - }; - - var keyevent = function(e) { - if (typeof(loader_game)=='object') return; // game will start with click-to-play instead of [SPACE] char - if (e.which == 32) { - e.preventDefault(); - start(); - } - }; - - var start = function() { - // Prevent loading the game multiple times. - if (loading) { - return false; - } - window.removeEventListener('keypress', keyevent); - canvas.removeEventListener('click', start); - loading = true; - drawloadingtimer = window.setInterval(draw_loading_status, 1000/60); - if (precallback) { - window.setTimeout(precallback, 0); - } - init_module(); - return this; - }; - this.start = start; - window.DOSBOXstart = start;//global hook to method (so can be invoked with a "click to play" image being clicked) - - var drawsplash = function() { - var context = canvas.getContext('2d'); - splashimg.onload = function(){ - context.clearRect(0, 0, canvas.width, canvas.height); - context.save(); - context.drawImage(splashimg, canvas.width / 2 - (splashimg.width / 2), canvas.height / 3 - (splashimg.height / 2)); - context.font = '18px sans-serif'; - context.fillStyle = splash_inverse ? 'white' : 'black'; - context.textAlign = 'center'; - context.fillText('Click here to start', canvas.width / 2, (canvas.height / 2) + (splashimg.height / 2)); - context.textAlign = 'start'; - context.restore(); - }; - spinnerimg.onload = function() { - splashimg.src = '/images/dosbox.png';; - }; - spinnerimg.src = '/images/spinner.png'; - }; - - var configLoaded = function (data) { - moduledata = data; - window.addEventListener('keypress', keyevent); - canvas.addEventListener('click', start); - drawsplash(); - if (loading) { - // HACK: User clicked play before module metadata loaded, and play aborted. - // Now that metadata is ready, begin playing. - init_module(); - } - }; - - function try_start () { - if (!can_start()) { - return; - } - LOADING_TEXT = "Fetching item metadata..."; - has_started = true; - // NOTE: deliberately use cors.archive.org since this will 302 rewrite to iaXXXXX.us.archive.org/XX/items/jsmess_engine_v2/...json - // and need to keep that "artificial" extra domain-ish name to avoid CORS issues with IE/Safari - fetch_file('ModuleInfo', '//cors.archive.org/cors/jsmess_engine_v2/' + module + '.json', configLoaded, 'text', true, true); - } - - try_start(); -} - -DOSBOX._readySet = false; - -DOSBOX._readyList = []; - -DOSBOX._runReadies = function() { - if (DOSBOX._readyList) { - for (var r=0; r < DOSBOX._readyList.length; r++) { - DOSBOX._readyList[r].call(window, []); - }; - DOSBOX._readyList = []; - }; -}; - -DOSBOX._readyCheck = function() { - if (DOSBOX.running) { - DOSBOX._runReadies(); - } else { - DOSBOX._readySet = setTimeout(DOSBOX._readyCheck, 10); - }; -}; - -DOSBOX.ready = function(r) { - if (DOSBOX.running) { - r.call(window, []); - } else { - DOSBOX._readyList.push(function() { canvas.style.width = DOSBOX.width + 'px'; canvas.style.height = DOSBOX.height + 'px'; } ); - if (!(DOSBOX._readySet)) { - DOSBOX._readyCheck(); - } - }; -} - -DOSBOX.setScale = function() { - Module.canvas.style.width = DOSBOX.width + 'px'; - Module.canvas.style.height = DOSBOX.height + 'px'; -}; - -DOSBOX.fullScreenChangeHandler = function() { - if (!(document.mozFullScreenElement || document.fullScreenElement)) { - setTimeout(DOSBOX.setScale, 0); - } -}; - -DOSBOX.BFSMountZip = function BFSMount(loadedData) { - var zipfs = new BrowserFS.FileSystem.ZipFS(loadedData), - mfs = new BrowserFS.FileSystem.MountableFileSystem(), - memfs = new BrowserFS.FileSystem.InMemory(); - mfs.mount('/zip', zipfs); - mfs.mount('/mem', memfs); - BrowserFS.initialize(mfs); - // Copy the read-only zip file contents to a writable in-memory storage. - this.recursiveCopy('/zip', '/mem'); - // Re-initialize BFS to just use the writable in-memory storage. - BrowserFS.initialize(memfs); - // Mount the file system into Emscripten. - var BFS = new BrowserFS.EmscriptenFS(); - FS.mkdir('/dosprogram'); - FS.mount(BFS, {root: '/'}, '/dosprogram'); -}; - -// Helper function: Recursively copies contents from one folder to another. -DOSBOX.recursiveCopy = function recursiveCopy(oldDir, newDir) { - var path = BrowserFS.BFSRequire('path'), - fs = BrowserFS.BFSRequire('fs'); - copyDirectory(oldDir, newDir); - function copyDirectory(oldDir, newDir) { - if (!fs.existsSync(newDir)) { - fs.mkdirSync(newDir); - } - fs.readdirSync(oldDir).forEach(function(item) { - var p = path.resolve(oldDir, item), - newP = path.resolve(newDir, item); - if (fs.statSync(p).isDirectory()) { - copyDirectory(p, newP); - } else { - copyFile(p, newP); - } - }); - } - function copyFile(oldFile, newFile) { - fs.writeFileSync(newFile, fs.readFileSync(oldFile)); - } -}; - -/** - * Searches for dosbox.conf, and moves it to '/dosbox.conf' so dosbox uses it. - */ -DOSBOX.moveConfigToRoot = function moveConfigToRoot() { - if (typeof FS !== 'undefined') { - var dosboxConfPath = null; - // Recursively search for dosbox.conf. - function searchDirectory(dirPath) { - FS.readdir(dirPath).forEach(function(item) { - // Avoid infinite recursion by ignoring these entries, which exist at - // the root. - if (item === '.' || item === '..') { - return; - } - // Append '/' between dirPath and the item's name... unless dirPath - // already ends in it (which always occurs if dirPath is the root, '/'). - var itemPath = dirPath + (dirPath[dirPath.length - 1] !== '/' ? "/" : "") + item, - itemStat = FS.stat(itemPath); - if (FS.isDir(itemStat.mode)) { - searchDirectory(itemPath); - } else if (item === 'dosbox.conf') { - dosboxConfPath = itemPath; - } - }); - } - searchDirectory('/'); - - if (dosboxConfPath !== null) { - FS.writeFile('/dosbox.conf', FS.readFile(dosboxConfPath), { encoding: 'binary' }); - } - } -}; diff --git a/es6-promise.js b/es6-promise.js new file mode 100644 index 0000000..ee1ba96 --- /dev/null +++ b/es6-promise.js @@ -0,0 +1,960 @@ +/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE + * @version 2.0.0 + */ + +(function() { + "use strict"; + + function $$utils$$objectOrFunction(x) { + return typeof x === 'function' || (typeof x === 'object' && x !== null); + } + + function $$utils$$isFunction(x) { + return typeof x === 'function'; + } + + function $$utils$$isMaybeThenable(x) { + return typeof x === 'object' && x !== null; + } + + var $$utils$$_isArray; + + if (!Array.isArray) { + $$utils$$_isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + $$utils$$_isArray = Array.isArray; + } + + var $$utils$$isArray = $$utils$$_isArray; + var $$utils$$now = Date.now || function() { return new Date().getTime(); }; + function $$utils$$F() { } + + var $$utils$$o_create = (Object.create || function (o) { + if (arguments.length > 1) { + throw new Error('Second argument not supported'); + } + if (typeof o !== 'object') { + throw new TypeError('Argument must be an object'); + } + $$utils$$F.prototype = o; + return new $$utils$$F(); + }); + + var $$asap$$len = 0; + + var $$asap$$default = function asap(callback, arg) { + $$asap$$queue[$$asap$$len] = callback; + $$asap$$queue[$$asap$$len + 1] = arg; + $$asap$$len += 2; + if ($$asap$$len === 2) { + // If len is 1, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + $$asap$$scheduleFlush(); + } + }; + + var $$asap$$browserGlobal = (typeof window !== 'undefined') ? window : {}; + var $$asap$$BrowserMutationObserver = $$asap$$browserGlobal.MutationObserver || $$asap$$browserGlobal.WebKitMutationObserver; + + // test for web worker but not in IE10 + var $$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + + // node + function $$asap$$useNextTick() { + return function() { + process.nextTick($$asap$$flush); + }; + } + + function $$asap$$useMutationObserver() { + var iterations = 0; + var observer = new $$asap$$BrowserMutationObserver($$asap$$flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function() { + node.data = (iterations = ++iterations % 2); + }; + } + + // web worker + function $$asap$$useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = $$asap$$flush; + return function () { + channel.port2.postMessage(0); + }; + } + + function $$asap$$useSetTimeout() { + return function() { + setTimeout($$asap$$flush, 1); + }; + } + + var $$asap$$queue = new Array(1000); + + function $$asap$$flush() { + for (var i = 0; i < $$asap$$len; i+=2) { + var callback = $$asap$$queue[i]; + var arg = $$asap$$queue[i+1]; + + callback(arg); + + $$asap$$queue[i] = undefined; + $$asap$$queue[i+1] = undefined; + } + + $$asap$$len = 0; + } + + var $$asap$$scheduleFlush; + + // Decide what async method to use to triggering processing of queued callbacks: + if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { + $$asap$$scheduleFlush = $$asap$$useNextTick(); + } else if ($$asap$$BrowserMutationObserver) { + $$asap$$scheduleFlush = $$asap$$useMutationObserver(); + } else if ($$asap$$isWorker) { + $$asap$$scheduleFlush = $$asap$$useMessageChannel(); + } else { + $$asap$$scheduleFlush = $$asap$$useSetTimeout(); + } + + function $$$internal$$noop() {} + var $$$internal$$PENDING = void 0; + var $$$internal$$FULFILLED = 1; + var $$$internal$$REJECTED = 2; + var $$$internal$$GET_THEN_ERROR = new $$$internal$$ErrorObject(); + + function $$$internal$$selfFullfillment() { + return new TypeError("You cannot resolve a promise with itself"); + } + + function $$$internal$$cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.') + } + + function $$$internal$$getThen(promise) { + try { + return promise.then; + } catch(error) { + $$$internal$$GET_THEN_ERROR.error = error; + return $$$internal$$GET_THEN_ERROR; + } + } + + function $$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch(e) { + return e; + } + } + + function $$$internal$$handleForeignThenable(promise, thenable, then) { + $$asap$$default(function(promise) { + var sealed = false; + var error = $$$internal$$tryThen(then, thenable, function(value) { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + $$$internal$$resolve(promise, value); + } else { + $$$internal$$fulfill(promise, value); + } + }, function(reason) { + if (sealed) { return; } + sealed = true; + + $$$internal$$reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + $$$internal$$reject(promise, error); + } + }, promise); + } + + function $$$internal$$handleOwnThenable(promise, thenable) { + if (thenable._state === $$$internal$$FULFILLED) { + $$$internal$$fulfill(promise, thenable._result); + } else if (promise._state === $$$internal$$REJECTED) { + $$$internal$$reject(promise, thenable._result); + } else { + $$$internal$$subscribe(thenable, undefined, function(value) { + $$$internal$$resolve(promise, value); + }, function(reason) { + $$$internal$$reject(promise, reason); + }); + } + } + + function $$$internal$$handleMaybeThenable(promise, maybeThenable) { + if (maybeThenable.constructor === promise.constructor) { + $$$internal$$handleOwnThenable(promise, maybeThenable); + } else { + var then = $$$internal$$getThen(maybeThenable); + + if (then === $$$internal$$GET_THEN_ERROR) { + $$$internal$$reject(promise, $$$internal$$GET_THEN_ERROR.error); + } else if (then === undefined) { + $$$internal$$fulfill(promise, maybeThenable); + } else if ($$utils$$isFunction(then)) { + $$$internal$$handleForeignThenable(promise, maybeThenable, then); + } else { + $$$internal$$fulfill(promise, maybeThenable); + } + } + } + + function $$$internal$$resolve(promise, value) { + if (promise === value) { + $$$internal$$reject(promise, $$$internal$$selfFullfillment()); + } else if ($$utils$$objectOrFunction(value)) { + $$$internal$$handleMaybeThenable(promise, value); + } else { + $$$internal$$fulfill(promise, value); + } + } + + function $$$internal$$publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + $$$internal$$publish(promise); + } + + function $$$internal$$fulfill(promise, value) { + if (promise._state !== $$$internal$$PENDING) { return; } + + promise._result = value; + promise._state = $$$internal$$FULFILLED; + + if (promise._subscribers.length === 0) { + } else { + $$asap$$default($$$internal$$publish, promise); + } + } + + function $$$internal$$reject(promise, reason) { + if (promise._state !== $$$internal$$PENDING) { return; } + promise._state = $$$internal$$REJECTED; + promise._result = reason; + + $$asap$$default($$$internal$$publishRejection, promise); + } + + function $$$internal$$subscribe(parent, child, onFulfillment, onRejection) { + var subscribers = parent._subscribers; + var length = subscribers.length; + + parent._onerror = null; + + subscribers[length] = child; + subscribers[length + $$$internal$$FULFILLED] = onFulfillment; + subscribers[length + $$$internal$$REJECTED] = onRejection; + + if (length === 0 && parent._state) { + $$asap$$default($$$internal$$publish, parent); + } + } + + function $$$internal$$publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (subscribers.length === 0) { return; } + + var child, callback, detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + $$$internal$$invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; + } + + function $$$internal$$ErrorObject() { + this.error = null; + } + + var $$$internal$$TRY_CATCH_ERROR = new $$$internal$$ErrorObject(); + + function $$$internal$$tryCatch(callback, detail) { + try { + return callback(detail); + } catch(e) { + $$$internal$$TRY_CATCH_ERROR.error = e; + return $$$internal$$TRY_CATCH_ERROR; + } + } + + function $$$internal$$invokeCallback(settled, promise, callback, detail) { + var hasCallback = $$utils$$isFunction(callback), + value, error, succeeded, failed; + + if (hasCallback) { + value = $$$internal$$tryCatch(callback, detail); + + if (value === $$$internal$$TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value = null; + } else { + succeeded = true; + } + + if (promise === value) { + $$$internal$$reject(promise, $$$internal$$cannotReturnOwn()); + return; + } + + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== $$$internal$$PENDING) { + // noop + } else if (hasCallback && succeeded) { + $$$internal$$resolve(promise, value); + } else if (failed) { + $$$internal$$reject(promise, error); + } else if (settled === $$$internal$$FULFILLED) { + $$$internal$$fulfill(promise, value); + } else if (settled === $$$internal$$REJECTED) { + $$$internal$$reject(promise, value); + } + } + + function $$$internal$$initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value){ + $$$internal$$resolve(promise, value); + }, function rejectPromise(reason) { + $$$internal$$reject(promise, reason); + }); + } catch(e) { + $$$internal$$reject(promise, e); + } + } + + function $$$enumerator$$makeSettledResult(state, position, value) { + if (state === $$$internal$$FULFILLED) { + return { + state: 'fulfilled', + value: value + }; + } else { + return { + state: 'rejected', + reason: value + }; + } + } + + function $$$enumerator$$Enumerator(Constructor, input, abortOnReject, label) { + this._instanceConstructor = Constructor; + this.promise = new Constructor($$$internal$$noop, label); + this._abortOnReject = abortOnReject; + + if (this._validateInput(input)) { + this._input = input; + this.length = input.length; + this._remaining = input.length; + + this._init(); + + if (this.length === 0) { + $$$internal$$fulfill(this.promise, this._result); + } else { + this.length = this.length || 0; + this._enumerate(); + if (this._remaining === 0) { + $$$internal$$fulfill(this.promise, this._result); + } + } + } else { + $$$internal$$reject(this.promise, this._validationError()); + } + } + + $$$enumerator$$Enumerator.prototype._validateInput = function(input) { + return $$utils$$isArray(input); + }; + + $$$enumerator$$Enumerator.prototype._validationError = function() { + return new Error('Array Methods must be provided an Array'); + }; + + $$$enumerator$$Enumerator.prototype._init = function() { + this._result = new Array(this.length); + }; + + var $$$enumerator$$default = $$$enumerator$$Enumerator; + + $$$enumerator$$Enumerator.prototype._enumerate = function() { + var length = this.length; + var promise = this.promise; + var input = this._input; + + for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) { + this._eachEntry(input[i], i); + } + }; + + $$$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) { + var c = this._instanceConstructor; + if ($$utils$$isMaybeThenable(entry)) { + if (entry.constructor === c && entry._state !== $$$internal$$PENDING) { + entry._onerror = null; + this._settledAt(entry._state, i, entry._result); + } else { + this._willSettleAt(c.resolve(entry), i); + } + } else { + this._remaining--; + this._result[i] = this._makeResult($$$internal$$FULFILLED, i, entry); + } + }; + + $$$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) { + var promise = this.promise; + + if (promise._state === $$$internal$$PENDING) { + this._remaining--; + + if (this._abortOnReject && state === $$$internal$$REJECTED) { + $$$internal$$reject(promise, value); + } else { + this._result[i] = this._makeResult(state, i, value); + } + } + + if (this._remaining === 0) { + $$$internal$$fulfill(promise, this._result); + } + }; + + $$$enumerator$$Enumerator.prototype._makeResult = function(state, i, value) { + return value; + }; + + $$$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) { + var enumerator = this; + + $$$internal$$subscribe(promise, undefined, function(value) { + enumerator._settledAt($$$internal$$FULFILLED, i, value); + }, function(reason) { + enumerator._settledAt($$$internal$$REJECTED, i, reason); + }); + }; + + var $$promise$all$$default = function all(entries, label) { + return new $$$enumerator$$default(this, entries, true /* abort on reject */, label).promise; + }; + + var $$promise$race$$default = function race(entries, label) { + /*jshint validthis:true */ + var Constructor = this; + + var promise = new Constructor($$$internal$$noop, label); + + if (!$$utils$$isArray(entries)) { + $$$internal$$reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } + + var length = entries.length; + + function onFulfillment(value) { + $$$internal$$resolve(promise, value); + } + + function onRejection(reason) { + $$$internal$$reject(promise, reason); + } + + for (var i = 0; promise._state === $$$internal$$PENDING && i < length; i++) { + $$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); + } + + return promise; + }; + + var $$promise$resolve$$default = function resolve(object, label) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor($$$internal$$noop, label); + $$$internal$$resolve(promise, object); + return promise; + }; + + var $$promise$reject$$default = function reject(reason, label) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor($$$internal$$noop, label); + $$$internal$$reject(promise, reason); + return promise; + }; + + var $$es6$promise$promise$$counter = 0; + + function $$es6$promise$promise$$needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } + + function $$es6$promise$promise$$needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); + } + + var $$es6$promise$promise$$default = $$es6$promise$promise$$Promise; + + /** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise’s eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class Promise + @param {function} resolver + Useful for tooling. + @constructor + */ + function $$es6$promise$promise$$Promise(resolver) { + this._id = $$es6$promise$promise$$counter++; + this._state = undefined; + this._result = undefined; + this._subscribers = []; + + if ($$$internal$$noop !== resolver) { + if (!$$utils$$isFunction(resolver)) { + $$es6$promise$promise$$needsResolver(); + } + + if (!(this instanceof $$es6$promise$promise$$Promise)) { + $$es6$promise$promise$$needsNew(); + } + + $$$internal$$initializePromise(this, resolver); + } + } + + $$es6$promise$promise$$Promise.all = $$promise$all$$default; + $$es6$promise$promise$$Promise.race = $$promise$race$$default; + $$es6$promise$promise$$Promise.resolve = $$promise$resolve$$default; + $$es6$promise$promise$$Promise.reject = $$promise$reject$$default; + + $$es6$promise$promise$$Promise.prototype = { + constructor: $$es6$promise$promise$$Promise, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + var result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + var author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: function(onFulfillment, onRejection) { + var parent = this; + var state = parent._state; + + if (state === $$$internal$$FULFILLED && !onFulfillment || state === $$$internal$$REJECTED && !onRejection) { + return this; + } + + var child = new this.constructor($$$internal$$noop); + var result = parent._result; + + if (state) { + var callback = arguments[state - 1]; + $$asap$$default(function(){ + $$$internal$$invokeCallback(state, child, callback, result); + }); + } else { + $$$internal$$subscribe(parent, child, onFulfillment, onRejection); + } + + return child; + }, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + 'catch': function(onRejection) { + return this.then(null, onRejection); + } + }; + + var $$es6$promise$polyfill$$default = function polyfill() { + var local; + + if (typeof global !== 'undefined') { + local = global; + } else if (typeof window !== 'undefined' && window.document) { + local = window; + } else { + local = self; + } + + var es6PromiseSupport = + "Promise" in local && + // Some of these methods are missing from + // Firefox/Chrome experimental implementations + "resolve" in local.Promise && + "reject" in local.Promise && + "all" in local.Promise && + "race" in local.Promise && + // Older version of the spec had a resolver object + // as the arg rather than a function + (function() { + var resolve; + new local.Promise(function(r) { resolve = r; }); + return $$utils$$isFunction(resolve); + }()); + + if (!es6PromiseSupport) { + local.Promise = $$es6$promise$promise$$default; + } + }; + + var es6$promise$umd$$ES6Promise = { + 'Promise': $$es6$promise$promise$$default, + 'polyfill': $$es6$promise$polyfill$$default + }; + + /* global define:true module:true window: true */ + if (typeof define === 'function' && define['amd']) { + define(function() { return es6$promise$umd$$ES6Promise; }); + } else if (typeof module !== 'undefined' && module['exports']) { + module['exports'] = es6$promise$umd$$ES6Promise; + } else if (typeof this !== 'undefined') { + this['ES6Promise'] = es6$promise$umd$$ES6Promise; + } +}).call(this); \ No newline at end of file diff --git a/example_arcade.html b/example_arcade.html new file mode 100644 index 0000000..078eb5c --- /dev/null +++ b/example_arcade.html @@ -0,0 +1,24 @@ + + + + example arcade game + + + + + + + + + diff --git a/example_console.html b/example_console.html new file mode 100644 index 0000000..5f03ceb --- /dev/null +++ b/example_console.html @@ -0,0 +1,27 @@ + + + + example console game + + + + + + + + + diff --git a/example_dosbox.html b/example_dosbox.html new file mode 100644 index 0000000..8eeb261 --- /dev/null +++ b/example_dosbox.html @@ -0,0 +1,23 @@ + + + + example dos game + + + + + + + + + diff --git a/jsmess-launcher.js b/jsmess-launcher.js deleted file mode 100644 index 0e76982..0000000 --- a/jsmess-launcher.js +++ /dev/null @@ -1,170 +0,0 @@ -var ar = new Array(33,34,35,36,37,38,39,40); - -function getfullscreenenabler() { - return canvas.webkitRequestFullScreen || canvas.mozRequestFullScreen || canvas.requestFullScreen; -} - -function isfullscreensupported() { - return !!(getfullscreenenabler()); -} - -function gofullscreen() { - Module.requestFullScreen(1,0); -} - -function keypress(e) { - if (typeof(loader_game)=='object' && !loader_game.started) - return true; // Don't ignore certain keys yet (until game started by "click to play") - - var key = e.which; - if($.inArray(key,ar) > -1) { - e.preventDefault(); //Don't let arrow, pg up/down, home, end affect page position - return false; - } - return true; -} - -window.onkeydown = keypress; - -(function() { - function get(name) { - if(typeof(loader_game)=='object') - return loader_game[name]; //alternate case where dont have CGI args to parse... - if(name=(new RegExp('[?&]'+encodeURIComponent(name)+'=([^&]*)')).exec(location.search)) { - return decodeURIComponent(name[1]); - } - } - - var games; - var mess; - var module; - - function getmodule() { - module = get('module'); - module = module ? module : 'test'; - } - - function init() { - getmodule(); - ready(); - } - - function ready() { - var fullscreenbutton = document.getElementById('gofullscreen') - if (fullscreenbutton) { - if (isfullscreensupported()) { - fullscreenbutton.addEventListener('click', gofullscreen); - if ('onfullscreenchange' in document) { - document.addEventListener('fullscreenchange', JSMESS.fullScreenChangeHandler); - } else if ('onmozfullscreenchange' in document) { - document.addEventListener('mozfullscreenchange', JSMESS.fullScreenChangeHandler); - } else if ('onwebkitfullscreenchange' in document) { - document.addEventListener('webkitfullscreenchange', JSMESS.fullScreenChangeHandler); - } - } else { - fullscreenbutton.disabled = true; - } - } - var canvas = document.getElementById('canvas'); - mess = new JSMESS(canvas) - .setscale(get('scale') ? parseFloat(get('scale')) : 1) - .setmodule(module) - setgame(loader_game); - if (get('autostart')) { - mess.start(); - } - // Gamepad text - if (detectgamepadsupport()) { - var gamepadDiv = document.getElementById('gamepadtext'); - gamepadDiv.innerHTML = "No gamepads detected. Press a button on a gamepad to use it."; - listenforgamepads(function(gamepads, newgamepad) { - var s = (gamepads.length === 1 ? '' : 's'); - gamepadDiv.innerHTML = gamepads.length + ' gamepad'+s+' detected. If the game does not ' + - 'respond to your gamepad'+s+', refresh the browser and try again.'; - if (mess.hasStarted) { - gamepadDiv.innerHTML += "
Restart MESS to use new gamepads."; - } - }); - } - } - - function setgame(game) { - game = (game == 'NONE') ? undefined : game; - // NOTE: deliberately use cors.archive.org since this will 302 rewrite to iaXXXXX.us.archive.org/XX/items/... - // and need to keep that "artificial" extra domain-ish name to avoid CORS issues with IE/Safari - mess.setgame(game ? '//cors.archive.org/cors/'+ game : undefined); - } - - function switchgame(e) { - setgame(e.target.value); - } - - // Firefox will not give us Joystick data unless we register this NOP - // callback. - // https://bugzilla.mozilla.org/show_bug.cgi?id=936104 - addEventListener("gamepadconnected", function() {}); - var getgamepads = navigator.getGamepads || navigator.webkitGamepads || - navigator.mozGamepads || navigator.gamepads || navigator.webkitGetGamepads; - /** - * Does the current browser support the Gamepad API? - * Returns a boolean. - */ - function detectgamepadsupport() { - return typeof getgamepads === 'function'; - } - // The timer that listens for gamepads, in case we ever want to stop it. - var gamepadlistener; - /** - * Listens for new gamepads, and triggers the callback when it detects a - * change. - * The callback is passed an array of active gamepads. - */ - function listenforgamepads(cb, freq) { - // NOP if the browser doesn't support gamepads. - if (!detectgamepadsupport()) return; - // Map from gamepad id to gamepad information. - var prevgamepads = {}; - // DEFAULT: Check gamepads every second. - if (typeof freq === 'undefined') freq = 1000; - gamepadlistener = setInterval(function() { - // Browsers get cranky when you don't apply this on the navigator object. - var gamepads = getgamepads.apply(navigator); - var currentgamepads = {}; - var i; - var hasChanged = false; - for (i = 0; i < gamepads.length; i++) { - var gamepad = gamepads[i]; - if (gamepad != null) { - currentgamepads[gamepad.id] = gamepad; - if (!prevgamepads.hasOwnProperty(gamepad.id)) { - // Gamepad has been added. - hasChanged = true; - } - } - } - - // Has a gamepad been removed? - if (!hasChanged) { - for (var gamepadid in prevgamepads) { - if (!currentgamepads.hasOwnProperty(gamepadid)) { - hasChanged = true; - } - } - } - - prevgamepads = currentgamepads; - - if (hasChanged) { - // Actual gamepads, filtered from gamepads. Chrome puts empty items into - // its gamepadlist. - var actualgamepads = []; - for (i = 0; i < gamepads.length; i++) { - if (gamepads[i] != null) actualgamepads.push(gamepads[i]); - } - cb(actualgamepads); - } - }, freq); - } - - window.addEventListener('load', init); -})(); diff --git a/jsmess-loader.js b/jsmess-loader.js deleted file mode 100644 index 7a0ef1b..0000000 --- a/jsmess-loader.js +++ /dev/null @@ -1,404 +0,0 @@ -var Module = null; - -function JSMESS(canvas, module, game, precallback, callback, scale) { - var js_data; - var moduledata; - var requests = []; - var drawloadingtimer; - var file_countdown; - var spinnerrot = 0; - var splashimg = new Image(); - var spinnerimg = new Image(); - var has_started = false; - var loading = false; - var LOADING_TEXT; - var splash_inverse = getComputedStyle(document.getElementsByTagName("body")[0]).backgroundColor === 'rgb(0, 0, 0)'; - - var SAMPLE_RATE = (function () { - var audio_ctx = window.AudioContext || window.webkitAudioContext || false; - if (!audio_ctx) { - return false; - } - var sample = new audio_ctx; - return sample.sampleRate.toString(); - }()); - - // right off the bat we set the canvas's inner dimensions to - // whatever it's current css dimensions are; this isn't likely to be - // the same size that dosbox/jsmess will set it to, but it avoids - // the case where the size was left at the default 300x150 - if (!canvas.hasAttribute("width")) { - canvas.width = parseInt(getComputedStyle(canvas).width, 10); - canvas.height = parseInt(getComputedStyle(canvas).height, 10); - } - - var can_start = function () { - return !!canvas && !!module && !!game && !!scale && !has_started - }; - - this.setscale = function(_scale) { - scale = _scale; - try_start(); - return this; - } - - this.setprecallback = function(_precallback) { - precallback = _precallback; - return this; - } - - this.setcallback = function(_callback) { - callback = _callback; - return this; - } - - this.setmodule = function(_module) { - module = _module; - try_start(); - return this; - } - - this.setgame = function(_game) { - game = _game; - try_start(); - return this; - } - - var draw_loading_status = function() { - var context = canvas.getContext('2d'); - context.clearRect(0, 0, canvas.width, canvas.height); - context.drawImage(splashimg, canvas.width / 2 - (splashimg.width / 2), canvas.height / 3 - (splashimg.height / 2)); - var spinnerpos = (canvas.height / 2 + splashimg.height / 2) + 16; - context.save(); - context.translate((canvas.width / 2), spinnerpos); - context.rotate(spinnerrot); - context.drawImage(spinnerimg, -(64/2), -(64/2), 64, 64); - context.restore(); - context.save(); - context.font = '18px sans-serif'; - context.fillStyle = splash_inverse ? 'white' : 'black'; - context.textAlign = 'center'; - context.fillText(LOADING_TEXT, canvas.width / 2, (canvas.height / 2) + (splashimg.height / 4)); - context.restore(); - spinnerrot += .25; - }; - - var progress_fetch_file = function(e) { - if (e.lengthComputable) { - e.target.progress = e.loaded / e.total; - e.target.loaded = e.loaded; - e.target.total = e.total; - e.target.lengthComputable = e.lengthComputable; - } - }; - - var fetch_file = function(title, url, cb, rt, raw, unmanaged) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.responseType = rt ? rt : 'arraybuffer'; - xhr.onload = function(e) { - if (xhr.status != 200) { - return; - } - if (!unmanaged) { - xhr.progress = 1.0; - } - var ints = raw ? xhr.response : new Int8Array(xhr.response); - cb(ints); - }; - if (!unmanaged) { - xhr.onprogress = progress_fetch_file; - xhr.title = title; - xhr.progress = 0; - xhr.total = 0; - xhr.loaded = 0; - xhr.lengthComputable = false; - requests.push(xhr); - } - xhr.send(); - }; - - var update_countdown = function() { - file_countdown -= 1 - if (file_countdown <= 0) { - loading = false; - var headID = document.getElementsByTagName('head')[0]; - var newScript = document.createElement('script'); - newScript.type = 'text/javascript'; - newScript.text = js_data; - headID.appendChild(newScript); - - // see archive.js for the mute/unmute button/JS - if (!($.cookie && $.cookie('unmute'))){ - setTimeout(function(){ - // someone moved it from 1st to 2nd! - if (JSMESS && typeof(JSMESS.sdl_pauseaudio)!='undefined') - JSMESS.sdl_pauseaudio(1); - else if (_SDL_PauseAudio) - _SDL_PauseAudio(1); - - }, 3000); - } - } - }; - - var build_mess_arguments = function (config) { - LOADING_TEXT = 'Building arguments'; - var nr = config['native_resolution']; - // see archive.js for the mute/unmute button/JS - var muted = (!(typeof($.cookie)!='undefined' && $.cookie('unmute'))); - - var args = [ - config['driver'], - '-verbose', - '-rompath','.', - '-window', - '-resolution', nr[0]+'x' + nr[1], - '-nokeepaspect' - ]; - - if (config.autoboot) { - args.push('-autoboot_command'); - } - - if (muted){ - args.push('-sound', 'none'); - } else if (SAMPLE_RATE) { - args.push('-samplerate', SAMPLE_RATE); - } - - if (game) { - args.push('-' + config['peripherals'][0], game.replace(/\//g,'_')) - } - - if (config['extra_args']) { - args = args.concat(config['extra_args']) - } - - return args - }; - - var build_mame_arguments = function (config) { - LOADING_TEXT = 'Building arguments'; - var nr = config['native_resolution']; - // see archive.js for the mute/unmute button/JS - var muted = (!(typeof($.cookie)!='undefined' && $.cookie('unmute'))); - - var args = [ - config['driver'], - '-verbose', - '-rompath','.', - '-window', - '-resolution', nr[0]+'x' + nr[1], - '-nokeepaspect' - ]; - - if (muted){ - args.push('-sound', 'none'); - } else if (SAMPLE_RATE) { - args.push('-samplerate', SAMPLE_RATE); - } - - if (config['extra_args']) { - args = args.concat(config['extra_args']) - } - - return args - }; - - get_game_name = function (game_path) { - return game_path.split('/').pop(); - }; - - var init_module = function() { - LOADING_TEXT = 'Parsing config'; - var modulecfg = JSON.parse(moduledata); - - var game_file = null; - var keymap = null; - var bios_filenames = modulecfg['bios_filenames']; - var bios_files = {}; - - var nr = modulecfg['native_resolution']; - - JSMESS.width = nr[0] * scale; - JSMESS.height = nr[1] * scale; - - var use_mame = parseInt(modulecfg['arcade'], 10); - var arguments; - - if (use_mame) { - arguments = build_mame_arguments(modulecfg); - } else { - arguments = build_mess_arguments(modulecfg); - } - - Module = { - arguments: arguments, - screenIsReadOnly: true, - print: (function() { - return function(text) { - console.log(text); - }; - })(), - canvas: canvas, - noInitialRun: false, - preInit: function() { - LOADING_TEXT = 'Loading binary files into file system'; - // Load the downloaded binary files into the filesystem. - for (var bios_fname in bios_files) { - if (bios_files.hasOwnProperty(bios_fname)) { - Module['FS_createDataFile']('/', bios_fname, bios_files[bios_fname], true, true); - } - } - if (game && !use_mame) { - LOADING_TEXT = 'Loading game file into file system'; - Module['FS_createDataFile']('/', game.replace(/\//g,'_'), game_file, true, true); - } - Module['FS_createFolder']('/', 'cfg', true, true); - Module['FS_createDataFile']('/cfg', modulecfg['driver'] + '.cfg', keymap, true, true); - window.clearInterval(drawloadingtimer); - if (callback) { - modulecfg.canvas = canvas; - window.setTimeout(function() {callback(modulecfg)}, 0); - } - } - }; - - bios_filenames = bios_filenames.filter(String); - file_countdown = bios_filenames.length + (game ? 1 : 0) + 2 - - // Fetch the BIOS and the game we want to run. - LOADING_TEXT = 'Fetching BIOS and Game'; - if (!use_mame) { - for (var i=0; i < bios_filenames.length; i++) { - var fname = bios_filenames[i]; - // NOTE: deliberately use cors.archive.org since this will 302 rewrite to iaXXXXX.us.archive.org/XX/items/... - // and need to keep that "artificial" extra domain-ish name to avoid CORS issues with IE/Safari - fetch_file('Bios', '//cors.archive.org/cors/jsmess_bios_v2/' + fname, function(data) { bios_files[fname] = data; update_countdown(); }); - } - } else { - fetch_file('Bios', game, function (data) { bios_files[get_game_name(game)] = data; update_countdown(); }); - } - - if (game && !use_mame) { - fetch_file('Game', game, function(data) { game_file = data; update_countdown(); }); - } - - // NOTE: deliberately use cors.archive.org since this will 302 rewrite to iaXXXXX.us.archive.org/XX/items/... - // and need to keep that "artificial" extra domain-ish name to avoid CORS issues with IE/Safari - fetch_file('Keymap', '//cors.archive.org/cors/jsmess_config_v2/' + modulecfg['driver'] + '.cfg', function(data) { keymap = data; update_countdown(); }, 'text', true, true); - fetch_file('Javascript', '//cors.archive.org/cors/jsmess_engine_v2/' + modulecfg['js_filename'], function(data) { js_data = data; update_countdown(); }, 'text', true); - - }; - - var keyevent = function(e) { - if (typeof(loader_game)=='object') return; // game will start with click-to-play instead of [SPACE] char - if (e.which == 32) { - e.preventDefault(); - start(); - } - } - - var start = function() { - window.removeEventListener('keypress', keyevent); - canvas.removeEventListener('click', start); - loading = true; - drawloadingtimer = window.setInterval(draw_loading_status, 1000/60); - if (precallback) { - window.setTimeout(function() {precallback()}, 0); - } - init_module(); - return this; - } - this.start = start; - window.JSMESSstart = start;//global hook to method (so can be invoked with a "click to play" image being clicked) - - var drawsplash = function() { - var context = canvas.getContext('2d'); - splashimg.onload = function(){ - context.clearRect(0, 0, canvas.width, canvas.height); - context.save(); - context.drawImage(splashimg, canvas.width / 2 - (splashimg.width / 2), canvas.height / 3 - (splashimg.height / 2)); - context.font = '18px sans-serif'; - context.fillStyle = splash_inverse ? 'white' : 'black'; - context.textAlign = 'center'; - context.fillText('Click here to start', canvas.width / 2, (canvas.height / 2) + (splashimg.height / 2)); - context.textAlign = 'start'; - context.restore(); - }; - spinnerimg.onload = function() { - var use_mame = parseInt(JSON.parse(moduledata).arcade, 10); - var src; - if (use_mame) { - src = '/images/mame.png'; - } else { - src = '/images/mess.png'; - } - splashimg.src = src; - } - spinnerimg.src = '/images/spinner.png'; - } - - var configLoaded = function (data) { - moduledata = data; - window.addEventListener('keypress', keyevent); - canvas.addEventListener('click', start); - drawsplash(); - }; - - function try_start () { - if (!can_start()) { - return; - } - has_started = true; - // NOTE: deliberately use cors.archive.org since this will 302 rewrite to iaXXXXX.us.archive.org/XX/items/jsmess_engine_v2/...json - // and need to keep that "artificial" extra domain-ish name to avoid CORS issues with IE/Safari - fetch_file('ModuleInfo', '//cors.archive.org/cors/jsmess_engine_v2/' + module + '.json', configLoaded, 'text', true, true); - } - - try_start(); -} - -JSMESS._readySet = false; - -JSMESS._readyList = []; - -JSMESS._runReadies = function() { - if (JSMESS._readyList) { - for (var r=0; r < JSMESS._readyList.length; r++) { - JSMESS._readyList[r].call(window, []); - }; - JSMESS._readyList = []; - }; -}; - -JSMESS._readyCheck = function() { - if (JSMESS.running) { - JSMESS._runReadies(); - } else { - JSMESS._readySet = setTimeout(JSMESS._readyCheck, 10); - }; -}; - -JSMESS.ready = function(r) { - if (JSMESS.running) { - r.call(window, []); - } else { - JSMESS._readyList.push(function() { canvas.style.width = JSMESS.width + 'px'; canvas.style.height = JSMESS.height + 'px'; } ); - if (!(JSMESS._readySet)) { - JSMESS._readyCheck(); - } - }; -} - -JSMESS.setScale = function() { - Module.canvas.style.width = JSMESS.width + 'px'; - Module.canvas.style.height = JSMESS.height + 'px'; -}; - -JSMESS.fullScreenChangeHandler = function() { - if (!(document.mozFullScreenElement || document.fullScreenElement)) { - setTimeout(JSMESS.setScale, 0); - } -} diff --git a/loader.js b/loader.js new file mode 100644 index 0000000..f35caa7 --- /dev/null +++ b/loader.js @@ -0,0 +1,1179 @@ +var Module = null; + +(function (Promise) { + function IALoader(canvas, game, callback, scale, splashimg) { + if (typeof game !== 'string') { + game = game.toString(); + } + + var SAMPLE_RATE = (function () { + var audio_ctx = window.AudioContext || window.webkitAudioContext || false; + if (!audio_ctx) { + return false; + } + var sample = new audio_ctx; + return sample.sampleRate.toString(); + }()); + + var metadata, module, modulecfg, config_args, + emulator = new Emulator(canvas).setScale(scale) + .setSplashImage(splashimg) + .setLoad(loadFiles) + .setcallback(callback); + var cfgr; + function loadFiles(fetch_file, splash) { + splash.loading_text = 'Downloading game metadata...'; + return new Promise(function (resolve, reject) { + var loading = fetch_file('Game Metadata', + get_meta_url(game), + 'document'); + loading.then(function (data) { + metadata = data; + splash.loading_text = 'Downloading emulator metadata...'; + module = metadata.getElementsByTagName("emulator") + .item(0) + .textContent; + return fetch_file('Emulator Metadata', + get_emulator_config_url(module), + 'text', true); + }, + function () { + splash.loading_text = 'Failed to download metadata!'; + splash.failed_loading = true; + reject(1); + }) + .then(function (data) { + modulecfg = JSON.parse(data); + var mame = 'arcade' in modulecfg && parseInt(modulecfg['arcade'], 10); + var get_files; + + if (module && module.indexOf("dosbox") === 0) { + cfgr = DosBoxLoader; + get_files = get_dosbox_files; + } + else if (module) { + if (mame) { + cfgr = JSMAMELoader; + get_files = get_mame_files; + } else { + cfgr = JSMESSLoader; + get_files = get_mess_files; + } + } + else { + throw new Error("Unknown module type "+ module +"; cannot configure the emulator."); + } + + var nr = modulecfg['native_resolution']; + config_args = [cfgr.emulatorJS(get_js_url(modulecfg.js_filename)), + cfgr.locateAdditionalEmulatorJS(locateAdditionalJS), + cfgr.nativeResolution(nr[0], nr[1]), + cfgr.aspectRatio(nr[0] / nr[1]), + cfgr.sampleRate(SAMPLE_RATE), + cfgr.muted(!($.cookie && $.cookie('unmute')))]; + + if (module && module.indexOf("dosbox") === 0) { + config_args.push(cfgr.startExe(metadata.getElementsByTagName("emulator_start") + .item(0) + .textContent)); + } else if (module) { + config_args.push(cfgr.driver(modulecfg.driver), + cfgr.extraArgs(modulecfg.extra_args)); + if (modulecfg.peripherals && modulecfg.peripherals[0]) { + config_args.push(cfgr.peripheral(modulecfg.peripherals[0], + get_game_name(game))); + } + } + + splash.loading_text = 'Downloading game data...'; + return Promise.all(get_files(cfgr, metadata, modulecfg)); + }, + function () { + splash.loading_text = 'Failed to download metadata!'; + splash.failed_loading = true; + reject(2); + }) + .then(function (game_files) { + resolve(cfgr.apply(null, extend(config_args, game_files))); + }, + function () { + splash.loading_text = 'Failed to download game data!'; + splash.failed_loading = true; + reject(3); + }); + }); + } + + function locateAdditionalJS(filename) { + if ("file_locations" in modulecfg && filename in modulecfg.file_locations) { + return get_js_url(modulecfg.file_locations[filename]); + } + throw new Error("Don't know how to find file: "+ filename); + } + + function get_dosbox_files(cfgr, emulator, modulecfg) { + // first get the urls + var urls = [], files = []; + var len = metadata.documentElement.childNodes.length, i; + for (i = 0; i < len; i++) { + var node = metadata.documentElement.childNodes[i]; + var m = node.nodeName.match(/^dosbox_drive_[a-zA-Z]$/); + if (m) { + urls.push(node); + } + } + + // and a count, then fetch them in + var len = urls.length; + for (i = 0; i < len; i++) { + var node = urls[i], + drive = node.nodeName.split('_')[2], + title = 'Game File ('+ (i+1) +' of '+ (game ? len+1 : len) +')', + url = get_zip_url(node.textContent); + files.push(cfgr.mountZip(drive, cfgr.fetchFile(title, url))); + } + + if (game) { + var drive = 'c', + title = 'Game File ('+ (i+1) +' of '+ (game ? len+1 : len) +')', + url = get_zip_url(game); + files.push(cfgr.mountZip(drive, cfgr.fetchFile(title, url))); + } + + return files; + } + + function get_mess_files(cfgr, metadata, modulecfg) { + var files = [], + bios_files = modulecfg['bios_filenames']; + bios_files.forEach(function (fname, i) { + if (fname) { + var title = "Bios File ("+ (i+1) +" of "+ bios_files.length +")"; + files.push(cfgr.mountFile('/'+ fname, + cfgr.fetchFile(title, + get_bios_url(fname)))); + } + }); + files.push(cfgr.mountFile('/'+ get_game_name(game), + cfgr.fetchFile("Game File", + get_zip_url(game)))); + files.push(cfgr.mountFile('/'+ modulecfg['driver'] + '.cfg', + cfgr.fetchOptionalFile("CFG File", + get_other_emulator_config_url(module)))); + return files; + } + + function get_mame_files(cfgr, metadata, modulecfg) { + var files = [], + bios_files = modulecfg['bios_filenames']; + bios_files.forEach(function (fname, i) { + if (fname) { + var title = "Bios File ("+ (i+1) +" of "+ bios_files.length +")"; + files.push(cfgr.mountFile('/'+ fname, + cfgr.fetchFile(title, + get_bios_url(fname)))); + } + }); + files.push(cfgr.mountFile('/'+ get_game_name(game), + cfgr.fetchFile("Game File", + get_zip_url(game)))); + files.push(cfgr.mountFile('/'+ modulecfg['driver'] + '.cfg', + cfgr.fetchOptionalFile("CFG File", + get_other_emulator_config_url(module)))); + return files; + } + + var get_item_name = function (game_path) { + return game_path.split('/').shift(); + }; + + var get_game_name = function (game_path) { + return game_path.split('/').pop(); + }; + + // NOTE: deliberately use cors.archive.org since this will 302 rewrite to iaXXXXX.us.archive.org/XX/items/... + // and need to keep that "artificial" extra domain-ish name to avoid CORS issues with IE/Safari + var get_emulator_config_url = function (module) { + return '//archive.org/cors/jsmess_engine_v2/' + module + '.json'; + }; + + var get_other_emulator_config_url = function (module) { + return '//archive.org/cors/jsmess_config_v2/' + module + '.cfg'; + }; + + var get_meta_url = function (game_path) { + var path = game_path.split('/'); + return "//cors.archive.org/cors/"+ path[0] +"/"+ path[0] +"_meta.xml"; + }; + + var get_zip_url = function (game_path) { + return "//cors.archive.org/cors/"+ game_path; + }; + + var get_js_url = function (js_filename) { + return "//cors.archive.org/cors/jsmess_engine_v2/"+ js_filename; + }; + + var get_bios_url = function (bios_filename) { + return "//cors.archive.org/cors/jsmess_bios_v2/"+ bios_filename; + }; + + function mountat (drive) { + return function (data) { + return { drive: drive, + mountpoint: "/" + drive, + data: data + }; + }; + } + + return emulator; + } + + function BaseLoader() { + return Array.prototype.reduce.call(arguments, extend); + } + + BaseLoader.canvas = function (id) { + var elem = id instanceof Element ? id : document.getElementById(id); + return { canvas: elem }; + }; + + BaseLoader.emulatorJS = function (url) { + return { emulatorJS: url }; + }; + + BaseLoader.locateAdditionalEmulatorJS = function (func) { + return { locateAdditionalJS: func }; + }; + + BaseLoader.nativeResolution = function (width, height) { + if (typeof width !== 'number' || typeof height !== 'number') + throw new Error("Width and height must be numbers"); + return { nativeResolution: { width: Math.floor(width), height: Math.floor(height) } }; + }; + + BaseLoader.aspectRatio = function (ratio) { + if (typeof ratio !== 'number') + throw new Error("Aspect ratio must be a number"); + return { aspectRatio: ratio }; + }; + + BaseLoader.sampleRate = function (rate) { + return { sample_rate: rate }; + }; + + BaseLoader.muted = function (muted) { + return { muted: muted }; + }; + + BaseLoader.mountZip = function (drive, file) { + return { files: [{ drive: drive, + mountpoint: "/" + drive, + file: file + }] }; + }; + + BaseLoader.mountFile = function (filename, file) { + return { files: [{ mountpoint: filename, + file: file + }] }; + }; + + BaseLoader.fetchFile = function (title, url) { + return { title: title, url: url }; + }; + + BaseLoader.fetchOptionalFile = function (title, url) { + return { title: title, url: url, optional: true }; + }; + + BaseLoader.localFile = function (title, data) { + return { title: title, data: data }; + }; + + function DosBoxLoader() { + var config = Array.prototype.reduce.call(arguments, extend); + config.emulator_arguments = build_dosbox_arguments(config.emulatorStart, config.files); + return config; + } + DosBoxLoader.__proto__ = BaseLoader; + + DosBoxLoader.startExe = function (path) { + return { emulatorStart: path }; + }; + + function JSMESSLoader() { + var config = Array.prototype.reduce.call(arguments, extend); + config.emulator_arguments = build_mess_arguments(config.muted, config.mess_driver, + config.nativeResolution, config.sample_rate, + config.peripheral, config.extra_mess_args); + config.needs_jsmess_webaudio = true; + return config; + } + JSMESSLoader.__proto__ = BaseLoader; + + JSMESSLoader.driver = function (driver) { + return { mess_driver: driver }; + }; + + JSMESSLoader.peripheral = function (peripheral, game) { + return { peripheral: [peripheral, game] }; + }; + + JSMESSLoader.extraArgs = function (args) { + return { extra_mess_args: args }; + }; + + function JSMAMELoader() { + var config = Array.prototype.reduce.call(arguments, extend); + config.emulator_arguments = build_mame_arguments(config.muted, config.mess_driver, + config.nativeResolution, config.sample_rate, + config.extra_mess_args); + config.needs_jsmess_webaudio = true; + return config; + } + JSMAMELoader.__proto__ = BaseLoader; + + JSMAMELoader.driver = function (driver) { + return { mess_driver: driver }; + }; + + JSMAMELoader.extraArgs = function (args) { + return { extra_mess_args: args }; + }; + + var build_mess_arguments = function (muted, driver, native_resolution, sample_rate, peripheral, extra_args) { + var args = [driver, + '-verbose', + '-rompath', 'emulator', + '-window', + '-nokeepaspect']; + + if (native_resolution && "width" in native_resolution && "height" in native_resolution) { + args.push('-resolution', [native_resolution.width, native_resolution.height].join('x')); + } + + if (muted) { + args.push('-sound', 'none'); + } else if (sample_rate) { + args.push('-samplerate', sample_rate); + } + + if (peripheral && peripheral[0]) { + args.push('-' + peripheral[0], + '/emulator/'+ (peripheral[1].replace(/\//g,'_'))); + } + + if (extra_args) { + args = args.concat(extra_args); + } + + return args; + }; + + var build_mame_arguments = function (muted, driver, native_resolution, sample_rate, extra_args) { + var args = [driver, + '-verbose', + '-rompath', 'emulator', + '-window', + '-nokeepaspect']; + + if (native_resolution && "width" in native_resolution && "height" in native_resolution) { + args.push('-resolution', [native_resolution.width, native_resolution.height].join('x')); + } + + if (muted) { + args.push('-sound', 'none'); + } else if (sample_rate) { + args.push('-samplerate', sample_rate); + } + + if (extra_args) { + args = args.concat(extra_args); + } + + return args; + }; + + var build_dosbox_arguments = function (emulator_start, files) { + var args = ['-conf', '/emulator/dosbox.conf']; + + var len = files.length; + for (var i = 0; i < len; i++) { + if ('mountpoint' in files[i]) { + args.push('-c', 'mount '+ files[i].drive +' /emulator'+ files[i].mountpoint); + } + } + + var path = emulator_start.split(/\\|\//); // I have LTS already + args.push('-c', /^[a-zA-Z]:$/.test(path[0]) ? path.shift() : 'c:'); + var prog = path.pop(); + if (path && path.length) + args.push('-c', 'cd '+ path.join('/')); + args.push('-c', prog); + + return args; + }; + + function Emulator(canvas, callback, loadFiles) { + var js_url; + var requests = []; + var drawloadingtimer; + var splashimg = new Image(); + var spinnerimg = new Image(); + spinnerimg.src = '/images/spinner.png'; + // TODO: Have an enum value that communicates the current state of the emulator, e.g. 'initializing', 'loading', 'running'. + var has_started = false; + var loading = false; + var splash = { loading_text: "", + spinning: true, + spinner_rotation: 0, + finished_loading: false, + colors: { foreground: 'white', + background: 'black' } }; + + var SDL_PauseAudio; + this.mute = function (state) { + try { + if (!SDL_PauseAudio) + SDL_PauseAudio = Module.cwrap('SDL_PauseAudio', '', ['number']); + SDL_PauseAudio(state); + } catch (x) { + console.log("Unable to change audio state:", x); + } + return this; + }; + + var css_resolution, scale, aspectRatio; + // right off the bat we set the canvas's inner dimensions to + // whatever it's current css dimensions are; this isn't likely to be + // the same size that dosbox/jsmess will set it to, but it avoids + // the case where the size was left at the default 300x150 + if (!canvas.hasAttribute("width")) { + canvas.width = parseInt(getComputedStyle(canvas).width, 10); + canvas.height = parseInt(getComputedStyle(canvas).height, 10); + } + + this.setScale = function(_scale) { + scale = _scale; + return this; + }; + + this.setSplashImage = function(_splashimg) { + if (_splashimg) { + splashimg.src = _splashimg; + } + return this; + }; + + this.setCSSResolution = function(_resolution) { + css_resolution = _resolution; + return this; + }; + + this.setAspectRatio = function(_aspectRatio) { + aspectRatio = _aspectRatio; + return this; + }; + + this.setcallback = function(_callback) { + callback = _callback; + return this; + }; + + this.setSplashColors = function (colors) { + splash.colors = colors; + return this; + }; + + this.setLoad = function (loadFunc) { + loadFiles = loadFunc; + return this; + }; + + var start = function (options) { + if (has_started) + return false; + has_started = true; + if (typeof options !== 'object') { + options = { waitAfterDownloading: false }; + } + + var k, c, game_data; + drawsplash(); + + var loading; + + if (typeof loadFiles === 'function') { + loading = loadFiles(fetch_file, splash); + } else { + loading = Promise.resolve(loadFiles); + } + loading.then(function (_game_data) { + game_data = _game_data; + game_data.fs = new BrowserFS.FileSystem.MountableFileSystem(); + var Buffer = BrowserFS.BFSRequire('buffer').Buffer; + + function fetch(file) { + if ('data' in file && file.data !== null && typeof file.data !== 'undefined') { + return Promise.resolve(file.data); + } + return fetch_file(file.title, file.url, 'arraybuffer', file.optional); + } + + function mountat(drive) { + return function (data) { + if (data !== null) { + drive = drive.toLowerCase(); + var mountpoint = '/'+ drive; + game_data.fs.mount(mountpoint, BFSOpenZip(new Buffer(data))); + } + }; + } + + function saveat(filename) { + return function (data) { + if (data !== null) { + game_data.fs.writeFileSync('/'+ filename, new Buffer(data), null, flag_w, 0x1a4); + } + }; + } + + return Promise.all(game_data.files.map(function (f) { + if (f && f.file) + if (f.drive) { + return fetch(f.file).then(mountat(f.drive)); + } else if (f.mountpoint) { + return fetch(f.file).then(saveat(f.mountpoint)); + } + return null; + })); + }) + .then(function (game_files) { + if (options.waitAfterDownloading) { + return new Promise(function (resolve, reject) { + splash.loading_text = 'Press any key to continue...'; + splash.spinning = false; + + // stashes these event listeners so that we can remove them after + window.addEventListener('keypress', k = keyevent(resolve)); + canvas.addEventListener('click', c = resolve); + }); + } + return Promise.resolve(); + }, + function () { + splash.loading_text = 'Failed to download game data!'; + splash.failed_loading = true; + }) + .then(function () { + splash.spinning = true; + window.removeEventListener('keypress', k); + canvas.removeEventListener('click', c); + + // Don't let arrow, pg up/down, home, end affect page position + blockSomeKeys(); + setupFullScreen(); + disableRightClickContextMenu(canvas); + if (game_data.needs_jsmess_webaudio) + setup_jsmess_webaudio(); + + // Emscripten doesn't use the proper prefixed functions for fullscreen requests, + // so let's map the prefixed versions to the correct function. + canvas.requestPointerLock = getpointerlockenabler(); + + moveConfigToRoot(game_data.fs); + Module = init_module(game_data.emulator_arguments, game_data.fs, game_data.locateAdditionalJS, + game_data.nativeResolution, game_data.aspectRatio); + + if (game_data.emulatorJS) { + splash.loading_text = 'Launching Emulator'; + attach_script(game_data.emulatorJS); + } else { + splash.loading_text = 'Non-system disk or disk error'; + } + }, + function () { + splash.loading_text = 'Invalid media, track 0 bad or unusable'; + splash.failed_loading = true; + }); + return this; + }; + this.start = start; + + var init_module = function(args, fs, locateAdditionalJS, nativeResolution, aspectRatio) { + return { arguments: args, + screenIsReadOnly: true, + print: function (text) { console.log(text); }, + canvas: canvas, + noInitialRun: false, + locateFile: locateAdditionalJS, + preInit: function () { + splash.loading_text = 'Loading game file(s) into file system'; + // Re-initialize BFS to just use the writable in-memory storage. + BrowserFS.initialize(fs); + var BFS = new BrowserFS.EmscriptenFS(); + // Mount the file system into Emscripten. + FS.mkdir('/emulator'); + FS.mount(BFS, {root: '/'}, '/emulator'); + splash.finished_loading = true; + setTimeout(function () { + resizeCanvas(canvas, + scale = scale || scale, + css_resolution = nativeResolution || css_resolution, + aspectRatio = aspectRatio || aspectRatio); + }); + if (callback) { + window.setTimeout(function() { callback(this); }, 0); + } + } + }; + }; + + var formatSize = function (event) { + if (event.lengthComputable) + return "("+ (event.total ? (event.loaded / event.total * 100).toFixed(0) + : "100") + + "%; "+ formatBytes(event.loaded) + + " of "+ formatBytes(event.total) +")"; + return "("+ formatBytes(event.loaded) +")"; + }; + + var formatBytes = function (bytes, base10) { + if (bytes === 0) + return "0 B"; + var unit = base10 ? 1000 : 1024, + units = base10 ? ["B", "kB","MB","GB","TB","PB","EB","ZB","YB"] + : ["B", "KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"], + exp = parseInt((Math.log(bytes) / Math.log(unit))), + size = bytes / Math.pow(unit, exp); + return size.toFixed(1) +' '+ units[exp]; + }; + + var fetch_file = function (title, url, rt, optional) { + var table = document.getElementById("dosbox-progress-indicator"); + var row, statusCell, titleCell, sizeCell; + if (!table) { + table = document.createElement('table'); + table.setAttribute('id', "dosbox-progress-indicator"); + table.style.position = 'absolute'; + table.style.top = (canvas.offsetTop + (canvas.height / 2 + splashimg.height / 2) + 16 - (64/2)) +'px'; + table.style.left = canvas.offsetLeft + (64 + 32) +'px'; + table.style.color = 'foreground' in splash.colors ? splash.colors.foreground : 'black'; + canvas.parentElement.appendChild(table); + } + row = table.insertRow(-1); + statusCell = row.insertCell(-1); + statusCell.textContent = '—'; + statusCell.style.width = "1.5em"; + titleCell = row.insertCell(-1); + titleCell.textContent = title; + titleCell.style.paddingRight = "1em"; + sizeCell = row.insertCell(-1); + sizeCell.textContent = '—'; + sizeCell.style.fontSize = "smaller"; + + return new Promise(function (resolve, reject) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = rt ? rt : 'arraybuffer'; + xhr.onprogress = function (e) { + sizeCell.textContent = formatSize(e); + }; + xhr.onload = function (e) { + sizeCell.textContent = formatSize(e); + if (xhr.status === 200) { + statusCell.textContent = '✔'; + resolve(xhr.response); + } + }; + xhr.onerror = function (e) { + sizeCell.textContent = formatSize(e); + if (optional) { + statusCell.textContent = '?'; + resolve(null); + } else { + statusCell.textContent = '✘'; + reject(); + } + }; + xhr.send(); + }); + }; + + function keyevent(resolve) { + return function (e) { + if (typeof loader_game === 'object') + return; // game will start with click-to-play instead of [SPACE] char + if (e.which == 32) { + e.preventDefault(); + resolve(); + } + }; + }; + + var resizeCanvas = function (canvas, scale, resolution, aspectRatio) { + if (scale && resolution) { + canvas.style.imageRendering = 'optimizeSpeed'; + canvas.style.imageRendering = '-moz-crisp-edges'; + canvas.style.imageRendering = '-o-crisp-edges'; + canvas.style.imageRendering = '-webkit-optimize-contrast'; + canvas.style.imageRendering = 'optimize-contrast'; + canvas.style.imageRendering = 'crisp-edges'; + canvas.style.imageRendering = 'pixelated'; + + canvas.style.width = resolution.width * scale +'px'; + canvas.style.height = resolution.height * scale +'px'; + canvas.width = resolution.width; + canvas.height = resolution.height; + } + }; + + var drawsplash = function () { + canvas.setAttribute('moz-opaque', ''); + var context = canvas.getContext('2d'); + if (splashimg.src && splashimg.complete) { + draw_loading_status(0); + animLoop(draw_loading_status); + } else { + splashimg.onload = function () { + draw_loading_status(0); + animLoop(draw_loading_status); + }; + if (!splashimg.src) { + splashimg.src = '/images/dosbox.png'; + } + } + }; + + var draw_loading_status = function (deltaT) { + var context = canvas.getContext('2d'); + context.fillStyle = "background" in splash.colors ? splash.colors.background : 'white'; + context.fillRect(0, 0, canvas.width, canvas.height); + context.drawImage(splashimg, canvas.width / 2 - (splashimg.width / 2), canvas.height / 3 - (splashimg.height / 2)); + + var spinnerpos = (canvas.height / 2 + splashimg.height / 2) + 16; + context.save(); + context.translate((64/2) + 16, spinnerpos); + context.rotate(splash.spinning ? (splash.spinner_rotation += 2 * (2*Math.PI/1000) * deltaT) + : 0); + context.drawImage(spinnerimg, -(64/2), -(64/2), 64, 64); + context.restore(); + + context.save(); + context.font = '18px sans-serif'; + context.fillStyle = "foreground" in splash.colors ? splash.colors.foreground : 'black'; + context.textAlign = 'center'; + context.fillText(splash.loading_text, canvas.width / 2, (canvas.height / 2) + (splashimg.height / 4)); + + context.restore(); + + var table = document.getElementById("dosbox-progress-indicator"); + if (table) { + table.style.top = (canvas.offsetTop + (canvas.height / 2 + splashimg.height / 2) + 16 - (64/2)) +'px'; + table.style.left = canvas.offsetLeft + (64 + 32) +'px'; + table.style.color = "foreground" in splash.colors ? splash.colors.foreground : 'black'; + } + + if (splash.finished_loading && table) { + table.style.display = 'none'; + } + if (splash.finished_loading || splash.failed_loading) { + return false; + } + return true; + }; + + function attach_script(js_url) { + if (js_url) { + var head = document.getElementsByTagName('head')[0]; + var newScript = document.createElement('script'); + newScript.type = 'text/javascript'; + newScript.src = js_url; + head.appendChild(newScript); + } + } + + function getpointerlockenabler() { + return canvas.requestPointerLock || canvas.mozRequestPointerLock || canvas.webkitRequestPointerLock; + } + + function getfullscreenenabler() { + return canvas.webkitRequestFullScreen || canvas.mozRequestFullScreen || canvas.requestFullScreen; + } + + this.isfullscreensupported = function () { + return !!(getfullscreenenabler()); + }; + + function setupFullScreen() { + var self = this; + var fullScreenChangeHandler = function() { + if (!(document.mozFullScreenElement || document.fullScreenElement)) { + resizeCanvas(canvas, scale, css_resolution, aspectRatio); + } + }; + if ('onfullscreenchange' in document) { + document.addEventListener('fullscreenchange', fullScreenChangeHandler); + } else if ('onmozfullscreenchange' in document) { + document.addEventListener('mozfullscreenchange', fullScreenChangeHandler); + } else if ('onwebkitfullscreenchange' in document) { + document.addEventListener('webkitfullscreenchange', fullScreenChangeHandler); + } + }; + + this.requestFullScreen = function () { + Module.requestFullScreen(1, 0); + }; + + /** + * Prevents page navigation keys such as page up/page down from + * moving the page while the user is playing. + */ + function blockSomeKeys() { + var blocked_keys = [33, 34, 35, 36, 37, 38, 39, 40]; + function keypress (e) { + if (blocked_keys.indexOf(e.which) >= 0) { + e.preventDefault(); + return false; + } + return true; + } + window.onkeydown = keypress; + } + + /** + * Disables the right click menu for the given element. + */ + function disableRightClickContextMenu(element) { + element.addEventListener('contextmenu', + function (e) { + if (e.button == 2) { + // Block right-click menu thru preventing default action. + e.preventDefault(); + } + }); + } + }; + + function BFSOpenZip(loadedData) { + var zipfs = new BrowserFS.FileSystem.ZipFS(loadedData), + mfs = new BrowserFS.FileSystem.MountableFileSystem(), + memfs = new BrowserFS.FileSystem.InMemory(); + mfs.mount('/zip', zipfs); + mfs.mount('/mem', memfs); + // Copy the read-only zip file contents to a writable in-memory storage. + recursiveCopy(mfs, '/zip', '/mem'); + return memfs; + }; + + // This is such a hack. We're not calling the BrowserFS api + // "correctly", so we have to synthesize these flags ourselves + var flag_r = { isReadable: function() { return true; }, + isWriteable: function() { return false; }, + isTruncating: function() { return false; }, + isAppendable: function() { return false; }, + isSynchronous: function() { return false; }, + isExclusive: function() { return false; }, + pathExistsAction: function() { return 0; }, + pathNotExistsAction: function() { return 1; } + }; + var flag_w = { isReadable: function() { return false; }, + isWriteable: function() { return true; }, + isTruncating: function() { return false; }, + isAppendable: function() { return false; }, + isSynchronous: function() { return false; }, + isExclusive: function() { return false; }, + pathExistsAction: function() { return 0; }, + pathNotExistsAction: function() { return 3; } + }; + + // Helper function: Recursively copies contents from one folder to another. + function recursiveCopy(fs, oldDir, newDir) { + var path = BrowserFS.BFSRequire('path'); + copyDirectory(oldDir, newDir); + function copyDirectory(oldDir, newDir) { + if (!fs.existsSync(newDir)) { + fs.mkdirSync(newDir, 0777); + } + fs.readdirSync(oldDir).forEach(function(item) { + var p = path.resolve(oldDir, item), + newP = path.resolve(newDir, item); + if (fs.statSync(p).isDirectory()) { + copyDirectory(p, newP); + } else { + copyFile(p, newP); + } + }); + } + function copyFile(oldFile, newFile) { + fs.writeFileSync(newFile, + fs.readFileSync(oldFile, null, flag_r), + null, flag_w, 0644); + } + }; + + /** + * Searches for dosbox.conf, and moves it to '/dosbox.conf' so dosbox uses it. + */ + function moveConfigToRoot(fs) { + var dosboxConfPath = null; + // Recursively search for dosbox.conf. + function searchDirectory(dirPath) { + fs.readdirSync(dirPath).forEach(function(item) { + // Avoid infinite recursion by ignoring these entries, which exist at + // the root. + if (item === '.' || item === '..') { + return; + } + // Append '/' between dirPath and the item's name... unless dirPath + // already ends in it (which always occurs if dirPath is the root, '/'). + var itemPath = dirPath + (dirPath[dirPath.length - 1] !== '/' ? "/" : "") + item, + itemStat = fs.statSync(itemPath); + if (itemStat.isDirectory(itemStat.mode)) { + searchDirectory(itemPath); + } else if (item === 'dosbox.conf') { + dosboxConfPath = itemPath; + } + }); + } + + searchDirectory('/'); + + if (dosboxConfPath !== null) { + fs.writeFileSync('/dosbox.conf', + fs.readFileSync(dosboxConfPath, null, flag_r), + null, flag_w, 0x1a4); + } + }; + + function extend(a, b) { + if (a === null) + return b; + if (b === null) + return a; + var ta = typeof a, + tb = typeof b; + if (ta !== tb) { + if (ta === 'undefined') + return b; + if (tb === 'undefined') + return a; + throw new Error("Cannot extend an "+ ta +" with an "+ tb); + } + if (Array.isArray(a)) + return a.concat(b); + if (ta === 'object') { + Object.keys(b).forEach(function (k) { + a[k] = extend(a[k], b[k]); + }); + return a; + } + return b; + } + + window.IALoader = IALoader; + window.DosBoxLoader = DosBoxLoader; + window.JSMESSLoader = JSMESSLoader; + window.JSMAMELoader = JSMAMELoader; + window.Emulator = Emulator; + })(typeof Promise === 'undefined' ? ES6Promise.Promise : Promise); + +// Cross browser, backward compatible solution +(function(window, Date) { + // feature testing + var raf = window.requestAnimationFrame || + window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame || + window.msRequestAnimationFrame || + window.oRequestAnimationFrame; + + window.animLoop = function (render, element) { + var running, lastFrame = +new Date; + function loop (now) { + if (running !== false) { + // fallback to setTimeout if requestAnimationFrame wasn't found + raf ? raf(loop, element) + : setTimeout(loop, 1000 / 60); + // Make sure to use a valid time, since: + // - Chrome 10 doesn't return it at all + // - setTimeout returns the actual timeout + now = now && now > 1E4 ? now : +new Date; + var deltaT = now - lastFrame; + // do not render frame when deltaT is too high + if (deltaT < 160) { + running = render(deltaT, now); + } + lastFrame = now; + } + } + loop(); + }; +})(window, Date); + +// Usage +//animLoop(function (deltaT, now) { +// // rendering code goes here +// // return false; will stop the loop +// }, +// animWrapper); + +// legacy +var JSMESS = JSMESS || {}; +JSMESS.ready = function (f) { f(); }; + +function setup_jsmess_webaudio() { + // jsmess web audio backend v0.2 + // katelyn gadd - kg at luminance dot org ; @antumbral on twitter + + var jsmess_web_audio = (function () { + + var context = null; + var gain_node = null; + var buffer_insert_point = null; + var pending_buffers = []; + + var numChannels = 2; // constant in jsmess + var sampleScale = 32766; + var prebufferDuration = 100 / 1000; + + function lazy_init () { + if (context || typeof AudioContext == 'undefined') + return; + + context = new AudioContext(); + + gain_node = context.createGain(); + gain_node.gain.value = 1.0; + gain_node.connect(context.destination); + }; + + function set_mastervolume ( + // even though it's 'attenuation' the value is negative, so... + attenuation_in_decibels + ) { + lazy_init(); + if (!context) return; + + // http://stackoverflow.com/questions/22604500/web-audio-api-working-with-decibels + // seemingly incorrect/broken. figures. welcome to Web Audio + // var gain_web_audio = 1.0 - Math.pow(10, 10 / attenuation_in_decibels); + + // HACK: Max attenuation in JSMESS appears to be 32. + // Hit ' then left/right arrow to test. + // FIXME: This is linear instead of log10 scale. + var gain_web_audio = 1.0 + (+attenuation_in_decibels / +32); + if (gain_web_audio < +0) + gain_web_audio = +0; + else if (gain_web_audio > +1) + gain_web_audio = +1; + + gain_node.gain.value = gain_web_audio; + }; + + function update_audio_stream ( + pBuffer, // pointer into emscripten heap. int16 samples + samples_this_frame // int. number of samples at pBuffer address. + ) { + lazy_init(); + if (!context) return; + + var buffer = context.createBuffer( + numChannels, samples_this_frame, + // JSMESS already initializes its mixer to use the context sampling rate. + context.sampleRate + ); + + for ( + var channel_left = buffer.getChannelData(0), + channel_right = buffer.getChannelData(1), + i = 0, + l = samples_this_frame | 0; + i < l; + i++ + ) { + var offset = + // divide by sizeof(INT16) since pBuffer is offset + // in bytes + ((pBuffer / 2) | 0) + + ((i * 2) | 0); + + var left_sample = HEAP16[offset]; + var right_sample = HEAP16[(offset + 1) | 0]; + + // normalize from signed int16 to signed float + var left_sample_float = left_sample / sampleScale; + var right_sample_float = right_sample / sampleScale; + + channel_left[i] = left_sample_float; + channel_right[i] = right_sample_float; + } + + pending_buffers.push(buffer); + + tick(); + }; + + function tick () { + // Note: this is the time the web audio mixer has mixed up to, + // not the actual current time. + var now = context.currentTime; + + // prebuffering + if (buffer_insert_point === null) { + var total_buffered_seconds = 0; + + for (var i = 0, l = pending_buffers.length; i < l; i++) { + var buffer = pending_buffers[i]; + total_buffered_seconds += buffer.duration; + } + + // Buffer not full enough? abort + if (total_buffered_seconds < prebufferDuration) + return; + } + + // FIXME/TODO: It's possible for us to burn through the whole + // chunk of prebuffered audio. At that point it seems like + // JSMESS never catches up and our sound glitches forever. + + var insert_point = (buffer_insert_point === null) + ? now + : buffer_insert_point; + + if (pending_buffers.length) { + for (var i = 0, l = pending_buffers.length; i < l; i++) { + var buffer = pending_buffers[i]; + + var source_node = context.createBufferSource(); + source_node.buffer = buffer; + source_node.connect(gain_node); + source_node.start(insert_point); + + insert_point += buffer.duration; + } + + pending_buffers.length = 0; + buffer_insert_point = insert_point; + + if (buffer_insert_point <= now) + buffer_insert_point = now; + } + }; + function get_context() { + return context; + }; + + return { + set_mastervolume: set_mastervolume, + update_audio_stream: update_audio_stream, + get_context: get_context + }; + + })(); + + window.jsmess_set_mastervolume = jsmess_web_audio.set_mastervolume; + window.jsmess_update_audio_stream = jsmess_web_audio.update_audio_stream; + window.jsmess_web_audio = jsmess_web_audio; +} diff --git a/testcases.md b/testcases.md new file mode 100644 index 0000000..d0815e8 --- /dev/null +++ b/testcases.md @@ -0,0 +1,20 @@ + [19:14] if you've got a list then I'll be happy to run through it + [19:15] Yeah, I think that's smart going forward. + https://archive.org/details/arcade_astrob + [19:16] Tests: Works with arcade machine, presentation + [19:17] https://archive.org/details/sg_Wiz_n_Liz_1993_Psygnosis_US + Tests: Game Console (Sega Genesis), Very intense processing needs + [19:18] https://archive.org/details/a2_Castle_Smurfenstein_1981_Dead_Smurf_cr + Tests: Apple II performance (computer), sound + [19:19] https://archive.org/details/msdos_Wolfenstein_3D_1992 + Tests: EM-DOSBOX Side, sound, etc. + also parrallel file loads in Smurfenstein + So, at the VERY LEAST + These all shouldwork + If something blows up, there's something wrong. + [19:20] That's a solid test set. + Obviously, Dragon's Lair is our go-to for "holy fuck, large ROM" + [20:31] I'm going to add snack attack to that list, since it's easy to tell when it's running too fast + [01:51] Yes! + +https://archive.org/details/msdos_Snack_Attack_II_1982&external_js=1