text: 'use strict';
  
  Object.defineProperty(exports, "__esModule", {
      value: true
  });
  
  var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  
  var _mp4Generator = require('./mp4-generator');
  
  var _mp4Generator2 = _interopRequireDefault(_mp4Generator);
  
  var _yuvrenderMin = require('./yuvrender.min.js');
  
  var _yuvrenderMin2 = _interopRequireDefault(_yuvrenderMin);
  
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  var HevcDecoder = function () {
      function HevcDecoder(config) {
          _classCallCheck(this, HevcDecoder);
  
          this.TAG = 'mccree-remuxer-hevc';
          this.type = 'remuxer';
          this._config = config || {};
          this._isLive = this._config.isLive;
          this._dtsBase = 0;
          this._dtsBaseInited = false;
          this._audioDtsBase = Infinity;
          this._videoDtsBase = Infinity;
          this._audioNextDts = undefined;
          this._videoNextDts = undefined;
          this._audioMeta = null;
          this._videoMeta = null;
          this.canvas = null;
          this.images = [];
          this.needWait = true;
          this.frame = null;
          this.inits = false;
          this.ifDecodeTime = -1;
          this.worker = null;
          this.webGLCanvas = null;
          this.ylen = 0;
          this.uvlen = 0;
      }
  
      _createClass(HevcDecoder, [{
          key: 'init',
          value: function init(mccree) {
              this.mccree = mccree;
              this.logger = mccree.logger;
              this.observer = mccree.observer;
              this.events = mccree.events;
              this.onMediaSegment = mccree.onMediaSegment;
              this.mccree.initSegment = {};
              this.mccree.remuxBuffer = {
                  audio: [],
                  video: []
              };
              this.canvas = document.getElementById(this.mccree.config.canvasid);
              this.initHevcDecoder.call(this);
          }
      }, {
          key: 'initHevcDecoder',
          value: function initHevcDecoder() {
              var workerText = 'function EventEmitter() {\n  this._events = this._events || {};\n  this._maxListeners = this._maxListeners || undefined;\n}\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nEventEmitter.defaultMaxListeners = 10;\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function(n) {\n  if (!isNumber(n) || n < 0 || isNaN(n))\n    throw TypeError(\'n must be a positive number\');\n  this._maxListeners = n;\n  return this;\n};\n\nEventEmitter.prototype.emit = function(type) {\n  var er, handler, len, args, i, listeners;\n\n  if (!this._events)\n    this._events = {};\n\n  // If there is no \'error\' event listener then throw.\n  if (type === \'error\') {\n    if (!this._events.error ||\n        (isObject(this._events.error) && !this._events.error.length)) {\n      er = arguments[1];\n      if (er instanceof Error) {\n        throw er; // Unhandled \'error\' event\n      } else {\n        // At least give some kind of context to the user\n        var err = new Error(\'Uncaught, unspecified "error" event. (\' + er + \')\');\n        err.context = er;\n        throw err;\n      }\n    }\n  }\n\n  handler = this._events[type];\n\n  if (isUndefined(handler))\n    return false;\n\n  if (isFunction(handler)) {\n    switch (arguments.length) {\n      // fast cases\n      case 1:\n        handler.call(this);\n        break;\n      case 2:\n        handler.call(this, arguments[1]);\n        break;\n      case 3:\n        handler.call(this, arguments[1], arguments[2]);\n        break;\n      // slower\n      default:\n        args = Array.prototype.slice.call(arguments, 1);\n        handler.apply(this, args);\n    }\n  } else if (isObject(handler)) {\n    args = Array.prototype.slice.call(arguments, 1);\n    listeners = handler.slice();\n    len = listeners.length;\n    for (i = 0; i < len; i++)\n      listeners[i].apply(this, args);\n  }\n\n  return true;\n};\n\nEventEmitter.prototype.addListener = function(type, listener) {\n  var m;\n\n  if (!isFunction(listener))\n    throw TypeError(\'listener must be a function\');\n\n  if (!this._events)\n    this._events = {};\n\n  // To avoid recursion in the case that type === "newListener"! Before\n  // adding it to the listeners, first emit "newListener".\n  if (this._events.newListener)\n    this.emit(\'newListener\', type,\n              isFunction(listener.listener) ?\n              listener.listener : listener);\n\n  if (!this._events[type])\n    // Optimize the case of one listener. Don\'t need the extra array object.\n    this._events[type] = listener;\n  else if (isObject(this._events[type]))\n    // If we\'ve already got an array, just append.\n    this._events[type].push(listener);\n  else\n    // Adding the second element, need to change to array.\n    this._events[type] = [this._events[type], listener];\n\n  // Check for listener leak\n  if (isObject(this._events[type]) && !this._events[type].warned) {\n    if (!isUndefined(this._maxListeners)) {\n      m = this._maxListeners;\n    } else {\n      m = EventEmitter.defaultMaxListeners;\n    }\n\n    if (m && m > 0 && this._events[type].length > m) {\n      this._events[type].warned = true;\n      console.error(\'(node) warning: possible EventEmitter memory \' +\n                    \'leak detected. %d listeners added. \' +\n                    \'Use emitter.setMaxListeners() to increase limit.\',\n                    this._events[type].length);\n      if (typeof console.trace === \'function\') {\n        // not supported in IE 10\n        console.trace();\n      }\n    }\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n  if (!isFunction(listener))\n    throw TypeError(\'listener must be a function\');\n\n  var fired = false;\n\n  function g() {\n    this.removeListener(type, g);\n\n    if (!fired) {\n      fired = true;\n      listener.apply(this, arguments);\n    }\n  }\n\n  g.listener = listener;\n  this.on(type, g);\n\n  return this;\n};\n\n// emits a \'removeListener\' event iff the listener was removed\nEventEmitter.prototype.removeListener = function(type, listener) {\n  var list, position, length, i;\n\n  if (!isFunction(listener))\n    throw TypeError(\'listener must be a function\');\n\n  if (!this._events || !this._events[type])\n    return this;\n\n  list = this._events[type];\n  length = list.length;\n  position = -1;\n\n  if (list === listener ||\n      (isFunction(list.listener) && list.listener === listener)) {\n    delete this._events[type];\n    if (this._events.removeListener)\n      this.emit(\'removeListener\', type, listener);\n\n  } else if (isObject(list)) {\n    for (i = length; i-- > 0;) {\n      if (list[i] === listener ||\n          (list[i].listener && list[i].listener === listener)) {\n        position = i;\n        break;\n      }\n    }\n\n    if (position < 0)\n      return this;\n\n    if (list.length === 1) {\n      list.length = 0;\n      delete this._events[type];\n    } else {\n      list.splice(position, 1);\n    }\n\n    if (this._events.removeListener)\n      this.emit(\'removeListener\', type, listener);\n  }\n\n  return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n  var key, listeners;\n\n  if (!this._events)\n    return this;\n\n  // not listening for removeListener, no need to emit\n  if (!this._events.removeListener) {\n    if (arguments.length === 0)\n      this._events = {};\n    else if (this._events[type])\n      delete this._events[type];\n    return this;\n  }\n\n  // emit removeListener for all listeners on all events\n  if (arguments.length === 0) {\n    for (key in this._events) {\n      if (key === \'removeListener\') continue;\n      this.removeAllListeners(key);\n    }\n    this.removeAllListeners(\'removeListener\');\n    this._events = {};\n    return this;\n  }\n\n  listeners = this._events[type];\n\n  if (isFunction(listeners)) {\n    this.removeListener(type, listeners);\n  } else if (listeners) {\n    // LIFO order\n    while (listeners.length)\n      this.removeListener(type, listeners[listeners.length - 1]);\n  }\n  delete this._events[type];\n\n  return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n  var ret;\n  if (!this._events || !this._events[type])\n    ret = [];\n  else if (isFunction(this._events[type]))\n    ret = [this._events[type]];\n  else\n    ret = this._events[type].slice();\n  return ret;\n};\n\nEventEmitter.prototype.listenerCount = function(type) {\n  if (this._events) {\n    var evlistener = this._events[type];\n\n    if (isFunction(evlistener))\n      return 1;\n    else if (evlistener)\n      return evlistener.length;\n  }\n  return 0;\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n  return emitter.listenerCount(type);\n};\n\nfunction isFunction(arg) {\n  return typeof arg === \'function\';\n}\n\nfunction isNumber(arg) {\n  return typeof arg === \'number\';\n}\n\nfunction isObject(arg) {\n  return typeof arg === \'object\' && arg !== null;\n}\n\nfunction isUndefined(arg) {\n  return arg === void 0;\n}\n\nvar Module = {\n    print: function(text) {\n        text = Array.prototype.slice.call(arguments).join(\' \');\n        console.log(text);\n    },\n    printErr: function(text) {\n        text = Array.prototype.slice.call(arguments).join(\' \');\n        console.error(text);\n    },\n    canvas: {},\n    noInitialRun: true\n};\n\n// The Module object: Our interface to the outside world. We import\n// and export values on it, and do the work to get that through\n// closure compiler if necessary. There are various ways Module can be used:\n// 1. Not defined. We create it here\n// 2. A function parameter, function(Module) { ..generated code.. }\n// 3. pre-run appended it, var Module = {}; ..generated code..\n// 4. External script tag defines var Module.\n// We need to do an eval in order to handle the closure compiler\n// case, where this code here is minified but Module was defined\n// elsewhere (e.g. case 4 above). We also need to check if Module\n// already exists (e.g. case 3 above).\n// Note that if you want to run closure, and also to use Module\n// after the generated code, you will need to define   var Module = {};\n// before the code. Then that object will be used in the code, and you\n// can continue to use Module afterwards as well.\nvar Module;\nif (!Module) Module = (typeof Module !== \'undefined\' ? Module : null) || {};\n\n// Sometimes an existing Module object exists with properties\n// meant to overwrite the default module functionality. Here\n// we collect those properties and reapply _after_ we configure\n// the current environment\'s defaults to avoid having to be so\n// defensive during initialization.\nvar moduleOverrides = {};\nfor (var key in Module) {\n    if (Module.hasOwnProperty(key)) {\n        moduleOverrides[key] = Module[key];\n    }\n}\n\n// The environment setup code below is customized to use Module.\n// *** Environment setup code ***\nvar ENVIRONMENT_IS_WEB = false;\nvar ENVIRONMENT_IS_WORKER = false;\nvar ENVIRONMENT_IS_NODE = false;\nvar ENVIRONMENT_IS_SHELL = false;\n\n// Three configurations we can be running in:\n// 1) We could be the application main() thread running in the main JS UI thread. (ENVIRONMENT_IS_WORKER == false and ENVIRONMENT_IS_PTHREAD == false)\n// 2) We could be the application main() thread proxied to worker. (with Emscripten -s PROXY_TO_WORKER=1) (ENVIRONMENT_IS_WORKER == true, ENVIRONMENT_IS_PTHREAD == false)\n// 3) We could be an application pthread running in a worker. (ENVIRONMENT_IS_WORKER == true and ENVIRONMENT_IS_PTHREAD == true)\n\nif (Module[\'ENVIRONMENT\']) {\n    if (Module[\'ENVIRONMENT\'] === \'WEB\') {\n        ENVIRONMENT_IS_WEB = true;\n    } else if (Module[\'ENVIRONMENT\'] === \'WORKER\') {\n        ENVIRONMENT_IS_WORKER = true;\n    } else if (Module[\'ENVIRONMENT\'] === \'NODE\') {\n        ENVIRONMENT_IS_NODE = true;\n    } else if (Module[\'ENVIRONMENT\'] === \'SHELL\') {\n        ENVIRONMENT_IS_SHELL = true;\n    } else {\n        throw new Error(\'The provided Module[\\\'ENVIRONMENT\\\'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.\');\n    }\n} else {\n    ENVIRONMENT_IS_WEB = typeof window === \'object\';\n    ENVIRONMENT_IS_WORKER = typeof importScripts === \'function\';\n    ENVIRONMENT_IS_NODE = typeof process === \'object\' && typeof require === \'function\' && !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_WORKER;\n    ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;\n}\n\n\nif (ENVIRONMENT_IS_NODE) {\n    // Expose functionality in the same simple way that the shells work\n    // Note that we pollute the global namespace here, otherwise we break in node\n    if (!Module[\'print\']) Module[\'print\'] = console.log;\n    if (!Module[\'printErr\']) Module[\'printErr\'] = console.warn;\n\n    var nodeFS;\n    var nodePath;\n\n    Module[\'read\'] = function shell_read(filename, binary) {\n        if (!nodeFS) nodeFS = require(\'fs\');\n        if (!nodePath) nodePath = require(\'path\');\n        filename = nodePath[\'normalize\'](filename);\n        var ret = nodeFS[\'readFileSync\'](filename);\n        return binary ? ret : ret.toString();\n    };\n\n    Module[\'readBinary\'] = function readBinary(filename) {\n        var ret = Module[\'read\'](filename, true);\n        if (!ret.buffer) {\n            ret = new Uint8Array(ret);\n        }\n        assert(ret.buffer);\n        return ret;\n    };\n\n    Module[\'load\'] = function load(f) {\n        globalEval(read(f));\n    };\n\n    if (!Module[\'thisProgram\']) {\n        if (process[\'argv\'].length > 1) {\n            Module[\'thisProgram\'] = process[\'argv\'][1].replace(/\\\\/g, \'/\');\n        } else {\n            Module[\'thisProgram\'] = \'unknown-program\';\n        }\n    }\n\n    Module[\'arguments\'] = process[\'argv\'].slice(2);\n\n    if (typeof module !== \'undefined\') {\n        module[\'exports\'] = Module;\n    }\n\n    process[\'on\'](\'uncaughtException\', function(ex) {\n        // suppress ExitStatus exceptions from showing an error\n        if (!(ex instanceof ExitStatus)) {\n            throw ex;\n        }\n    });\n\n    Module[\'inspect\'] = function () { return \'[Emscripten Module object]\'; };\n}\nelse if (ENVIRONMENT_IS_SHELL) {\n    if (!Module[\'print\']) Module[\'print\'] = print;\n    if (typeof printErr != \'undefined\') Module[\'printErr\'] = printErr; // not present in v8 or older sm\n\n    if (typeof read != \'undefined\') {\n        Module[\'read\'] = read;\n    } else {\n        Module[\'read\'] = function shell_read() { throw \'no read() available\' };\n    }\n\n    Module[\'readBinary\'] = function readBinary(f) {\n        if (typeof readbuffer === \'function\') {\n            return new Uint8Array(readbuffer(f));\n        }\n        var data = read(f, \'binary\');\n        assert(typeof data === \'object\');\n        return data;\n    };\n\n    if (typeof scriptArgs != \'undefined\') {\n        Module[\'arguments\'] = scriptArgs;\n    } else if (typeof arguments != \'undefined\') {\n        Module[\'arguments\'] = arguments;\n    }\n\n    if (typeof quit === \'function\') {\n        Module[\'quit\'] = function(status, toThrow) {\n            quit(status);\n        }\n    }\n\n}\nelse if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n    Module[\'read\'] = function shell_read(url) {\n        var xhr = new XMLHttpRequest();\n        xhr.open(\'GET\', url, false);\n        xhr.send(null);\n        return xhr.responseText;\n    };\n\n    if (ENVIRONMENT_IS_WORKER) {\n        Module[\'readBinary\'] = function readBinary(url) {\n            var xhr = new XMLHttpRequest();\n            xhr.open(\'GET\', url, false);\n            xhr.responseType = \'arraybuffer\';\n            xhr.send(null);\n            return new Uint8Array(xhr.response);\n        };\n    }\n\n    Module[\'readAsync\'] = function readAsync(url, onload, onerror) {\n        var xhr = new XMLHttpRequest();\n        xhr.open(\'GET\', url, true);\n        xhr.responseType = \'arraybuffer\';\n        xhr.onload = function xhr_onload() {\n            if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0\n                onload(xhr.response);\n            } else {\n                onerror();\n            }\n        };\n        xhr.onerror = onerror;\n        xhr.send(null);\n    };\n\n    if (typeof arguments != \'undefined\') {\n        Module[\'arguments\'] = arguments;\n    }\n\n    if (typeof console !== \'undefined\') {\n        if (!Module[\'print\']) Module[\'print\'] = function shell_print(x) {\n            console.log(x);\n        };\n        if (!Module[\'printErr\']) Module[\'printErr\'] = function shell_printErr(x) {\n            console.warn(x);\n        };\n    } else {\n        // Probably a worker, and without console.log. We can do very little here...\n        var TRY_USE_DUMP = false;\n        if (!Module[\'print\']) Module[\'print\'] = (TRY_USE_DUMP && (typeof(dump) !== "undefined") ? (function(x) {\n            dump(x);\n        }) : (function(x) {\n            // self.postMessage(x); // enable this if you want stdout to be sent as messages\n        }));\n    }\n\n    if (ENVIRONMENT_IS_WORKER) {\n        Module[\'load\'] = importScripts;\n    }\n\n    if (typeof Module[\'setWindowTitle\'] === \'undefined\') {\n        Module[\'setWindowTitle\'] = function(title) { document.title = title };\n    }\n}\nelse {\n    // Unreachable because SHELL is dependant on the others\n    throw \'Unknown runtime environment. Where are we?\';\n}\n\nfunction globalEval(x) {\n    eval.call(null, x);\n}\nif (!Module[\'load\'] && Module[\'read\']) {\n    Module[\'load\'] = function load(f) {\n        globalEval(Module[\'read\'](f));\n    };\n}\nif (!Module[\'print\']) {\n    Module[\'print\'] = function(){};\n}\nif (!Module[\'printErr\']) {\n    Module[\'printErr\'] = Module[\'print\'];\n}\nif (!Module[\'arguments\']) {\n    Module[\'arguments\'] = [];\n}\nif (!Module[\'thisProgram\']) {\n    Module[\'thisProgram\'] = \'./this.program\';\n}\nif (!Module[\'quit\']) {\n    Module[\'quit\'] = function(status, toThrow) {\n        throw toThrow;\n    }\n}\n\n// *** Environment setup code ***\n\n// Closure helpers\nModule.print = Module[\'print\'];\nModule.printErr = Module[\'printErr\'];\n\n// Callbacks\nModule[\'preRun\'] = [];\nModule[\'postRun\'] = [];\n\n// Merge back in the overrides\nfor (var key in moduleOverrides) {\n    if (moduleOverrides.hasOwnProperty(key)) {\n        Module[key] = moduleOverrides[key];\n    }\n}\n// Free the object hierarchy contained in the overrides, this lets the GC\n// reclaim data used e.g. in memoryInitializerRequest, which is a large typed array.\nmoduleOverrides = undefined;\n\n\n\n// {{PREAMBLE_ADDITIONS}}\n\n// === Preamble library stuff ===\n\n// Documentation for the public APIs defined in this file must be updated in:\n//    site/source/docs/api_reference/preamble.js.rst\n// A prebuilt local version of the documentation is available at:\n//    site/build/text/docs/api_reference/preamble.js.txt\n// You can also build docs locally as HTML or other formats in site/\n// An online HTML version (which may be of a different version of Emscripten)\n//    is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html\n\n//========================================\n// Runtime code shared with compiler\n//========================================\n\nvar Runtime = {\n    setTempRet0: function (value) {\n        tempRet0 = value;\n        return value;\n    },\n    getTempRet0: function () {\n        return tempRet0;\n    },\n    stackSave: function () {\n        return STACKTOP;\n    },\n    stackRestore: function (stackTop) {\n        STACKTOP = stackTop;\n    },\n    getNativeTypeSize: function (type) {\n        switch (type) {\n            case \'i1\': case \'i8\': return 1;\n            case \'i16\': return 2;\n            case \'i32\': return 4;\n            case \'i64\': return 8;\n            case \'float\': return 4;\n            case \'double\': return 8;\n            default: {\n                if (type[type.length-1] === \'*\') {\n                    return Runtime.QUANTUM_SIZE; // A pointer\n                } else if (type[0] === \'i\') {\n                    var bits = parseInt(type.substr(1));\n                    assert(bits % 8 === 0);\n                    return bits/8;\n                } else {\n                    return 0;\n                }\n            }\n        }\n    },\n    getNativeFieldSize: function (type) {\n        return Math.max(Runtime.getNativeTypeSize(type), Runtime.QUANTUM_SIZE);\n    },\n    STACK_ALIGN: 16,\n    prepVararg: function (ptr, type) {\n        if (type === \'double\' || type === \'i64\') {\n            // move so the load is aligned\n            if (ptr & 7) {\n                assert((ptr & 7) === 4);\n                ptr += 4;\n            }\n        } else {\n            assert((ptr & 3) === 0);\n        }\n        return ptr;\n    },\n    getAlignSize: function (type, size, vararg) {\n        // we align i64s and doubles on 64-bit boundaries, unlike x86\n        if (!vararg && (type == \'i64\' || type == \'double\')) return 8;\n        if (!type) return Math.min(size, 8); // align structures internally to 64 bits\n        return Math.min(size || (type ? Runtime.getNativeFieldSize(type) : 0), Runtime.QUANTUM_SIZE);\n    },\n    dynCall: function (sig, ptr, args) {\n        if (args && args.length) {\n            return Module[\'dynCall_\' + sig].apply(null, [ptr].concat(args));\n        } else {\n            return Module[\'dynCall_\' + sig].call(null, ptr);\n        }\n    },\n    functionPointers: [],\n    addFunction: function (func) {\n        for (var i = 0; i < Runtime.functionPointers.length; i++) {\n            if (!Runtime.functionPointers[i]) {\n                Runtime.functionPointers[i] = func;\n                return 2*(1 + i);\n            }\n        }\n        throw \'Finished up all reserved function pointers. Use a higher value for RESERVED_FUNCTION_POINTERS.\';\n    },\n    removeFunction: function (index) {\n        Runtime.functionPointers[(index-2)/2] = null;\n    },\n    warnOnce: function (text) {\n        if (!Runtime.warnOnce.shown) Runtime.warnOnce.shown = {};\n        if (!Runtime.warnOnce.shown[text]) {\n            Runtime.warnOnce.shown[text] = 1;\n            Module.printErr(text);\n        }\n    },\n    funcWrappers: {},\n    getFuncWrapper: function (func, sig) {\n        assert(sig);\n        if (!Runtime.funcWrappers[sig]) {\n            Runtime.funcWrappers[sig] = {};\n        }\n        var sigCache = Runtime.funcWrappers[sig];\n        if (!sigCache[func]) {\n            // optimize away arguments usage in common cases\n            if (sig.length === 1) {\n                sigCache[func] = function dynCall_wrapper() {\n                    return Runtime.dynCall(sig, func);\n                };\n            } else if (sig.length === 2) {\n                sigCache[func] = function dynCall_wrapper(arg) {\n                    return Runtime.dynCall(sig, func, [arg]);\n                };\n            } else {\n                // general case\n                sigCache[func] = function dynCall_wrapper() {\n                    return Runtime.dynCall(sig, func, Array.prototype.slice.call(arguments));\n                };\n            }\n        }\n        return sigCache[func];\n    },\n    getCompilerSetting: function (name) {\n        throw \'You must build with -s RETAIN_COMPILER_SETTINGS=1 for Runtime.getCompilerSetting or emscripten_get_compiler_setting to work\';\n    },\n    stackAlloc: function (size) { var ret = STACKTOP;STACKTOP = (STACKTOP + size)|0;STACKTOP = (((STACKTOP)+15)&-16); return ret; },\n    staticAlloc: function (size) { var ret = STATICTOP;STATICTOP = (STATICTOP + size)|0;STATICTOP = (((STATICTOP)+15)&-16); return ret; },\n    dynamicAlloc: function (size) { var ret = HEAP32[DYNAMICTOP_PTR>>2];var end = (((ret + size + 15)|0) & -16);HEAP32[DYNAMICTOP_PTR>>2] = end;if (end >= TOTAL_MEMORY) {var success = enlargeMemory();if (!success) {HEAP32[DYNAMICTOP_PTR>>2] = ret;return 0;}}return ret;},\n    alignMemory: function (size,quantum) { var ret = size = Math.ceil((size)/(quantum ? quantum : 16))*(quantum ? quantum : 16); return ret; },\n    makeBigInt: function (low,high,unsigned) { var ret = (unsigned ? ((+((low>>>0)))+((+((high>>>0)))*(+4294967296))) : ((+((low>>>0)))+((+((high|0)))*(+4294967296)))); return ret; },\n    GLOBAL_BASE: 1024,\n    QUANTUM_SIZE: 4,\n    __dummy__: 0\n}\n\n\n\nModule["Runtime"] = Runtime;\n\n\n\n//========================================\n// Runtime essentials\n//========================================\n\nvar ABORT = 0; // whether we are quitting the application. no code should run after this. set in exit() and abort()\nvar EXITSTATUS = 0;\n\n/** @type {function(*, string=)} */\nfunction assert(condition, text) {\n    if (!condition) {\n        abort(\'Assertion failed: \' + text);\n    }\n}\n\nvar globalScope = this;\n\n// Returns the C function with a specified identifier (for C++, you need to do manual name mangling)\nfunction getCFunc(ident) {\n    var func = Module[\'_\' + ident]; // closure exported function\n    if (!func) {\n        try { func = eval(\'_\' + ident); } catch(e) {}\n    }\n    assert(func, \'Cannot call unknown function \' + ident + \' (perhaps LLVM optimizations or closure removed it?)\');\n    return func;\n}\n\nvar cwrap, ccall;\n(function(){\n    var JSfuncs = {\n        // Helpers for cwrap -- it can\'t refer to Runtime directly because it might\n        // be renamed by closure, instead it calls JSfuncs[\'stackSave\'].body to find\n        // out what the minified function name is.\n        \'stackSave\': function() {\n            Runtime.stackSave()\n        },\n        \'stackRestore\': function() {\n            Runtime.stackRestore()\n        },\n        // type conversion from js to c\n        \'arrayToC\' : function(arr) {\n            var ret = Runtime.stackAlloc(arr.length);\n            writeArrayToMemory(arr, ret);\n            return ret;\n        },\n        \'stringToC\' : function(str) {\n            var ret = 0;\n            if (str !== null && str !== undefined && str !== 0) { // null string\n                // at most 4 bytes per UTF-8 code point, +1 for the trailing \'\\0\'\n                var len = (str.length << 2) + 1;\n                ret = Runtime.stackAlloc(len);\n                stringToUTF8(str, ret, len);\n            }\n            return ret;\n        }\n    };\n    // For fast lookup of conversion functions\n    var toC = {\'string\' : JSfuncs[\'stringToC\'], \'array\' : JSfuncs[\'arrayToC\']};\n\n    // C calling interface.\n    ccall = function ccallFunc(ident, returnType, argTypes, args, opts) {\n        var func = getCFunc(ident);\n        var cArgs = [];\n        var stack = 0;\n        if (args) {\n            for (var i = 0; i < args.length; i++) {\n                var converter = toC[argTypes[i]];\n                if (converter) {\n                    if (stack === 0) stack = Runtime.stackSave();\n                    cArgs[i] = converter(args[i]);\n                } else {\n                    cArgs[i] = args[i];\n                }\n            }\n        }\n        var ret = func.apply(null, cArgs);\n        if (returnType === \'string\') ret = Pointer_stringify(ret);\n        if (stack !== 0) {\n            if (opts && opts.async) {\n                EmterpreterAsync.asyncFinalizers.push(function() {\n                    Runtime.stackRestore(stack);\n                });\n                return;\n            }\n            Runtime.stackRestore(stack);\n        }\n        return ret;\n    }\n\n    var sourceRegex = /^function\\s*[a-zA-Z$_0-9]*\\s*\\(([^)]*)\\)\\s*{\\s*([^*]*?)[\\s;]*(?:return\\s*(.*?)[;\\s]*)?}$/;\n    function parseJSFunc(jsfunc) {\n        // Match the body and the return value of a javascript function source\n        var parsed = jsfunc.toString().match(sourceRegex).slice(1);\n        return {arguments : parsed[0], body : parsed[1], returnValue: parsed[2]}\n    }\n\n    // sources of useful functions. we create this lazily as it can trigger a source decompression on this entire file\n    var JSsource = null;\n    function ensureJSsource() {\n        if (!JSsource) {\n            JSsource = {};\n            for (var fun in JSfuncs) {\n                if (JSfuncs.hasOwnProperty(fun)) {\n                    // Elements of toCsource are arrays of three items:\n                    // the code, and the return value\n                    JSsource[fun] = parseJSFunc(JSfuncs[fun]);\n                }\n            }\n        }\n    }\n\n    cwrap = function cwrap(ident, returnType, argTypes) {\n        argTypes = argTypes || [];\n        var cfunc = getCFunc(ident);\n        // When the function takes numbers and returns a number, we can just return\n        // the original function\n        var numericArgs = argTypes.every(function(type){ return type === \'number\'});\n        var numericRet = (returnType !== \'string\');\n        if ( numericRet && numericArgs) {\n            return cfunc;\n        }\n        // Creation of the arguments list (["$1","$2",...,"$nargs"])\n        var argNames = argTypes.map(function(x,i){return \'$\'+i});\n        var funcstr = "(function(" + argNames.join(\',\') + ") {";\n        var nargs = argTypes.length;\n        if (!numericArgs) {\n            // Generate the code needed to convert the arguments from javascript\n            // values to pointers\n            ensureJSsource();\n            funcstr += \'var stack = \' + JSsource[\'stackSave\'].body + \';\';\n            for (var i = 0; i < nargs; i++) {\n                var arg = argNames[i], type = argTypes[i];\n                if (type === \'number\') continue;\n                var convertCode = JSsource[type + \'ToC\']; // [code, return]\n                funcstr += \'var \' + convertCode.arguments + \' = \' + arg + \';\';\n                funcstr += convertCode.body + \';\';\n                funcstr += arg + \'=(\' + convertCode.returnValue + \');\';\n            }\n        }\n\n        // When the code is compressed, the name of cfunc is not literally \'cfunc\' anymore\n        var cfuncname = parseJSFunc(function(){return cfunc}).returnValue;\n        // Call the function\n        funcstr += \'var ret = \' + cfuncname + \'(\' + argNames.join(\',\') + \');\';\n        if (!numericRet) { // Return type can only by \'string\' or \'number\'\n            // Convert the result to a string\n            var strgfy = parseJSFunc(function(){return Pointer_stringify}).returnValue;\n            funcstr += \'ret = \' + strgfy + \'(ret);\';\n        }\n        if (!numericArgs) {\n            // If we had a stack, restore it\n            ensureJSsource();\n            funcstr += JSsource[\'stackRestore\'].body.replace(\'()\', \'(stack)\') + \';\';\n        }\n        funcstr += \'return ret})\';\n        return eval(funcstr);\n    };\n})();\nModule["ccall"] = ccall;\nModule["cwrap"] = cwrap;\n\n/** @type {function(number, number, string, boolean=)} */\nfunction setValue(ptr, value, type, noSafe) {\n    type = type || \'i8\';\n    if (type.charAt(type.length-1) === \'*\') type = \'i32\'; // pointers are 32-bit\n    switch(type) {\n        case \'i1\': HEAP8[((ptr)>>0)]=value; break;\n        case \'i8\': HEAP8[((ptr)>>0)]=value; break;\n        case \'i16\': HEAP16[((ptr)>>1)]=value; break;\n        case \'i32\': HEAP32[((ptr)>>2)]=value; break;\n        case \'i64\': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= (+1) ? (tempDouble > (+0) ? ((Math_min((+(Math_floor((tempDouble)/(+4294967296)))), (+4294967295)))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/(+4294967296))))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;\n        case \'float\': HEAPF32[((ptr)>>2)]=value; break;\n        case \'double\': HEAPF64[((ptr)>>3)]=value; break;\n        default: abort(\'invalid type for setValue: \' + type);\n    }\n}\nModule["setValue"] = setValue;\n\n/** @type {function(number, string, boolean=)} */\nfunction getValue(ptr, type, noSafe) {\n    type = type || \'i8\';\n    if (type.charAt(type.length-1) === \'*\') type = \'i32\'; // pointers are 32-bit\n    switch(type) {\n        case \'i1\': return HEAP8[((ptr)>>0)];\n        case \'i8\': return HEAP8[((ptr)>>0)];\n        case \'i16\': return HEAP16[((ptr)>>1)];\n        case \'i32\': return HEAP32[((ptr)>>2)];\n        case \'i64\': return HEAP32[((ptr)>>2)];\n        case \'float\': return HEAPF32[((ptr)>>2)];\n        case \'double\': return HEAPF64[((ptr)>>3)];\n        default: abort(\'invalid type for setValue: \' + type);\n    }\n    return null;\n}\nModule["getValue"] = getValue;\n\nvar ALLOC_NORMAL = 0; // Tries to use _malloc()\nvar ALLOC_STACK = 1; // Lives for the duration of the current function call\nvar ALLOC_STATIC = 2; // Cannot be freed\nvar ALLOC_DYNAMIC = 3; // Cannot be freed except through sbrk\nvar ALLOC_NONE = 4; // Do not allocate\nModule["ALLOC_NORMAL"] = ALLOC_NORMAL;\nModule["ALLOC_STACK"] = ALLOC_STACK;\nModule["ALLOC_STATIC"] = ALLOC_STATIC;\nModule["ALLOC_DYNAMIC"] = ALLOC_DYNAMIC;\nModule["ALLOC_NONE"] = ALLOC_NONE;\n\n// allocate(): This is for internal use. You can use it yourself as well, but the interface\n//             is a little tricky (see docs right below). The reason is that it is optimized\n//             for multiple syntaxes to save space in generated code. So you should\n//             normally not use allocate(), and instead allocate memory using _malloc(),\n//             initialize it with setValue(), and so forth.\n// @slab: An array of data, or a number. If a number, then the size of the block to allocate,\n//        in *bytes* (note that this is sometimes confusing: the next parameter does not\n//        affect this!)\n// @types: Either an array of types, one for each byte (or 0 if no type at that position),\n//         or a single type which is used for the entire block. This only matters if there\n//         is initial data - if @slab is a number, then this does not matter at all and is\n//         ignored.\n// @allocator: How to allocate memory, see ALLOC_*\n/** @type {function((TypedArray|Array<number>|number), string, number, number=)} */\nfunction allocate(slab, types, allocator, ptr) {\n    var zeroinit, size;\n    if (typeof slab === \'number\') {\n        zeroinit = true;\n        size = slab;\n    } else {\n        zeroinit = false;\n        size = slab.length;\n    }\n\n    var singleType = typeof types === \'string\' ? types : null;\n\n    var ret;\n    if (allocator == ALLOC_NONE) {\n        ret = ptr;\n    } else {\n        ret = [typeof _malloc === \'function\' ? _malloc : Runtime.staticAlloc, Runtime.stackAlloc, Runtime.staticAlloc, Runtime.dynamicAlloc][allocator === undefined ? ALLOC_STATIC : allocator](Math.max(size, singleType ? 1 : types.length));\n    }\n\n    if (zeroinit) {\n        var ptr = ret, stop;\n        assert((ret & 3) == 0);\n        stop = ret + (size & ~3);\n        for (; ptr < stop; ptr += 4) {\n            HEAP32[((ptr)>>2)]=0;\n        }\n        stop = ret + size;\n        while (ptr < stop) {\n            HEAP8[((ptr++)>>0)]=0;\n        }\n        return ret;\n    }\n\n    if (singleType === \'i8\') {\n        if (slab.subarray || slab.slice) {\n            HEAPU8.set(/** @type {!Uint8Array} */ (slab), ret);\n        } else {\n            HEAPU8.set(new Uint8Array(slab), ret);\n        }\n        return ret;\n    }\n\n    var i = 0, type, typeSize, previousType;\n    while (i < size) {\n        var curr = slab[i];\n\n        if (typeof curr === \'function\') {\n            curr = Runtime.getFunctionIndex(curr);\n        }\n\n        type = singleType || types[i];\n        if (type === 0) {\n            i++;\n            continue;\n        }\n\n        if (type == \'i64\') type = \'i32\'; // special case: we have one i32 here, and one i32 later\n\n        setValue(ret+i, curr, type);\n\n        // no need to look up size unless type changes, so cache it\n        if (previousType !== type) {\n            typeSize = Runtime.getNativeTypeSize(type);\n            previousType = type;\n        }\n        i += typeSize;\n    }\n\n    return ret;\n}\nModule["allocate"] = allocate;\n\n// Allocate memory during any stage of startup - static memory early on, dynamic memory later, malloc when ready\nfunction getMemory(size) {\n    if (!staticSealed) return Runtime.staticAlloc(size);\n    if (!runtimeInitialized) return Runtime.dynamicAlloc(size);\n    return _malloc(size);\n}\nModule["getMemory"] = getMemory;\n\n/** @type {function(number, number=)} */\nfunction Pointer_stringify(ptr, length) {\n    if (length === 0 || !ptr) return \'\';\n    // TODO: use TextDecoder\n    // Find the length, and check for UTF while doing so\n    var hasUtf = 0;\n    var t;\n    var i = 0;\n    while (1) {\n        t = HEAPU8[(((ptr)+(i))>>0)];\n        hasUtf |= t;\n        if (t == 0 && !length) break;\n        i++;\n        if (length && i == length) break;\n    }\n    if (!length) length = i;\n\n    var ret = \'\';\n\n    if (hasUtf < 128) {\n        var MAX_CHUNK = 1024; // split up into chunks, because .apply on a huge string can overflow the stack\n        var curr;\n        while (length > 0) {\n            curr = String.fromCharCode.apply(String, HEAPU8.subarray(ptr, ptr + Math.min(length, MAX_CHUNK)));\n            ret = ret ? ret + curr : curr;\n            ptr += MAX_CHUNK;\n            length -= MAX_CHUNK;\n        }\n        return ret;\n    }\n    return Module[\'UTF8ToString\'](ptr);\n}\nModule["Pointer_stringify"] = Pointer_stringify;\n\n// Given a pointer \'ptr\' to a null-terminated ASCII-encoded string in the emscripten HEAP, returns\n// a copy of that string as a Javascript String object.\n\nfunction AsciiToString(ptr) {\n    var str = \'\';\n    while (1) {\n        var ch = HEAP8[((ptr++)>>0)];\n        if (!ch) return str;\n        str += String.fromCharCode(ch);\n    }\n}\nModule["AsciiToString"] = AsciiToString;\n\n// Copies the given Javascript String object \'str\' to the emscripten HEAP at address \'outPtr\',\n// null-terminated and encoded in ASCII form. The copy will require at most str.length+1 bytes of space in the HEAP.\n\nfunction stringToAscii(str, outPtr) {\n    return writeAsciiToMemory(str, outPtr, false);\n}\nModule["stringToAscii"] = stringToAscii;\n\n// Given a pointer \'ptr\' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns\n// a copy of that string as a Javascript String object.\n\nvar UTF8Decoder = typeof TextDecoder !== \'undefined\' ? new TextDecoder(\'utf8\') : undefined;\nfunction UTF8ArrayToString(u8Array, idx) {\n    var endPtr = idx;\n    // TextDecoder needs to know the byte length in advance, it doesn\'t stop on null terminator by itself.\n    // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.\n    while (u8Array[endPtr]) ++endPtr;\n\n    if (endPtr - idx > 16 && u8Array.subarray && UTF8Decoder) {\n        return UTF8Decoder.decode(u8Array.subarray(idx, endPtr));\n    } else {\n        var u0, u1, u2, u3, u4, u5;\n\n        var str = \'\';\n        while (1) {\n            // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629\n            u0 = u8Array[idx++];\n            if (!u0) return str;\n            if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; }\n            u1 = u8Array[idx++] & 63;\n            if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; }\n            u2 = u8Array[idx++] & 63;\n            if ((u0 & 0xF0) == 0xE0) {\n                u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;\n            } else {\n                u3 = u8Array[idx++] & 63;\n                if ((u0 & 0xF8) == 0xF0) {\n                    u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | u3;\n                } else {\n                    u4 = u8Array[idx++] & 63;\n                    if ((u0 & 0xFC) == 0xF8) {\n                        u0 = ((u0 & 3) << 24) | (u1 << 18) | (u2 << 12) | (u3 << 6) | u4;\n                    } else {\n                        u5 = u8Array[idx++] & 63;\n                        u0 = ((u0 & 1) << 30) | (u1 << 24) | (u2 << 18) | (u3 << 12) | (u4 << 6) | u5;\n                    }\n                }\n            }\n            if (u0 < 0x10000) {\n                str += String.fromCharCode(u0);\n            } else {\n                var ch = u0 - 0x10000;\n                str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));\n            }\n        }\n    }\n}\nModule["UTF8ArrayToString"] = UTF8ArrayToString;\n\n// Given a pointer \'ptr\' to a null-terminated UTF8-encoded string in the emscripten HEAP, returns\n// a copy of that string as a Javascript String object.\n\nfunction UTF8ToString(ptr) {\n    return UTF8ArrayToString(HEAPU8,ptr);\n}\nModule["UTF8ToString"] = UTF8ToString;\n\n// Copies the given Javascript String object \'str\' to the given byte array at address \'outIdx\',\n// encoded in UTF8 form and null-terminated. The copy will require at most str.length*4+1 bytes of space in the HEAP.\n// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write.\n// Parameters:\n//   str: the Javascript string to copy.\n//   outU8Array: the array to copy to. Each index in this array is assumed to be one 8-byte element.\n//   outIdx: The starting offset in the array to begin the copying.\n//   maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null\n//                    terminator, i.e. if maxBytesToWrite=1, only the null terminator will be written and nothing else.\n//                    maxBytesToWrite=0 does not write any bytes to the output, not even the null terminator.\n// Returns the number of bytes written, EXCLUDING the null terminator.\n\nfunction stringToUTF8Array(str, outU8Array, outIdx, maxBytesToWrite) {\n    if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don\'t write out any bytes.\n        return 0;\n\n    var startIdx = outIdx;\n    var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator.\n    for (var i = 0; i < str.length; ++i) {\n        // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8.\n        // See http://unicode.org/faq/utf_bom.html#utf16-3\n        // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description and https://www.ietf.org/rfc/rfc2279.txt and https://tools.ietf.org/html/rfc3629\n        var u = str.charCodeAt(i); // possibly a lead surrogate\n        if (u >= 0xD800 && u <= 0xDFFF) u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);\n        if (u <= 0x7F) {\n            if (outIdx >= endIdx) break;\n            outU8Array[outIdx++] = u;\n        } else if (u <= 0x7FF) {\n            if (outIdx + 1 >= endIdx) break;\n            outU8Array[outIdx++] = 0xC0 | (u >> 6);\n            outU8Array[outIdx++] = 0x80 | (u & 63);\n        } else if (u <= 0xFFFF) {\n            if (outIdx + 2 >= endIdx) break;\n            outU8Array[outIdx++] = 0xE0 | (u >> 12);\n            outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);\n            outU8Array[outIdx++] = 0x80 | (u & 63);\n        } else if (u <= 0x1FFFFF) {\n            if (outIdx + 3 >= endIdx) break;\n            outU8Array[outIdx++] = 0xF0 | (u >> 18);\n            outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63);\n            outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);\n            outU8Array[outIdx++] = 0x80 | (u & 63);\n        } else if (u <= 0x3FFFFFF) {\n            if (outIdx + 4 >= endIdx) break;\n            outU8Array[outIdx++] = 0xF8 | (u >> 24);\n            outU8Array[outIdx++] = 0x80 | ((u >> 18) & 63);\n            outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63);\n            outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);\n            outU8Array[outIdx++] = 0x80 | (u & 63);\n        } else {\n            if (outIdx + 5 >= endIdx) break;\n            outU8Array[outIdx++] = 0xFC | (u >> 30);\n            outU8Array[outIdx++] = 0x80 | ((u >> 24) & 63);\n            outU8Array[outIdx++] = 0x80 | ((u >> 18) & 63);\n            outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63);\n            outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);\n            outU8Array[outIdx++] = 0x80 | (u & 63);\n        }\n    }\n    // Null-terminate the pointer to the buffer.\n    outU8Array[outIdx] = 0;\n    return outIdx - startIdx;\n}\nModule["stringToUTF8Array"] = stringToUTF8Array;\n\n// Copies the given Javascript String object \'str\' to the emscripten HEAP at address \'outPtr\',\n// null-terminated and encoded in UTF8 form. The copy will require at most str.length*4+1 bytes of space in the HEAP.\n// Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write.\n// Returns the number of bytes written, EXCLUDING the null terminator.\n\nfunction stringToUTF8(str, outPtr, maxBytesToWrite) {\n    return stringToUTF8Array(str, HEAPU8,outPtr, maxBytesToWrite);\n}\nModule["stringToUTF8"] = stringToUTF8;\n\n// Returns the number of bytes the given Javascript string takes if encoded as a UTF8 byte array, EXCLUDING the null terminator byte.\n\nfunction lengthBytesUTF8(str) {\n    var len = 0;\n    for (var i = 0; i < str.length; ++i) {\n        // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! So decode UTF16->UTF32->UTF8.\n        // See http://unicode.org/faq/utf_bom.html#utf16-3\n        var u = str.charCodeAt(i); // possibly a lead surrogate\n        if (u >= 0xD800 && u <= 0xDFFF) u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);\n        if (u <= 0x7F) {\n            ++len;\n        } else if (u <= 0x7FF) {\n            len += 2;\n        } else if (u <= 0xFFFF) {\n            len += 3;\n        } else if (u <= 0x1FFFFF) {\n            len += 4;\n        } else if (u <= 0x3FFFFFF) {\n            len += 5;\n        } else {\n            len += 6;\n        }\n    }\n    return len;\n}\nModule["lengthBytesUTF8"] = lengthBytesUTF8;\n\n// Given a pointer \'ptr\' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns\n// a copy of that string as a Javascript String object.\n\nvar UTF16Decoder = typeof TextDecoder !== \'undefined\' ? new TextDecoder(\'utf-16le\') : undefined;\nfunction UTF16ToString(ptr) {\n    var endPtr = ptr;\n    // TextDecoder needs to know the byte length in advance, it doesn\'t stop on null terminator by itself.\n    // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.\n    var idx = endPtr >> 1;\n    while (HEAP16[idx]) ++idx;\n    endPtr = idx << 1;\n\n    if (endPtr - ptr > 32 && UTF16Decoder) {\n        return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr));\n    } else {\n        var i = 0;\n\n        var str = \'\';\n        while (1) {\n            var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];\n            if (codeUnit == 0) return str;\n            ++i;\n            // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.\n            str += String.fromCharCode(codeUnit);\n        }\n    }\n}\n\n\n// Copies the given Javascript String object \'str\' to the emscripten HEAP at address \'outPtr\',\n// null-terminated and encoded in UTF16 form. The copy will require at most str.length*4+2 bytes of space in the HEAP.\n// Use the function lengthBytesUTF16() to compute the exact number of bytes (excluding null terminator) that this function will write.\n// Parameters:\n//   str: the Javascript string to copy.\n//   outPtr: Byte address in Emscripten HEAP where to write the string to.\n//   maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null\n//                    terminator, i.e. if maxBytesToWrite=2, only the null terminator will be written and nothing else.\n//                    maxBytesToWrite<2 does not write any bytes to the output, not even the null terminator.\n// Returns the number of bytes written, EXCLUDING the null terminator.\n\nfunction stringToUTF16(str, outPtr, maxBytesToWrite) {\n    // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed.\n    if (maxBytesToWrite === undefined) {\n        maxBytesToWrite = 0x7FFFFFFF;\n    }\n    if (maxBytesToWrite < 2) return 0;\n    maxBytesToWrite -= 2; // Null terminator.\n    var startPtr = outPtr;\n    var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length;\n    for (var i = 0; i < numCharsToWrite; ++i) {\n        // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.\n        var codeUnit = str.charCodeAt(i); // possibly a lead surrogate\n        HEAP16[((outPtr)>>1)]=codeUnit;\n        outPtr += 2;\n    }\n    // Null-terminate the pointer to the HEAP.\n    HEAP16[((outPtr)>>1)]=0;\n    return outPtr - startPtr;\n}\n\n\n// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte.\n\nfunction lengthBytesUTF16(str) {\n    return str.length*2;\n}\n\n\nfunction UTF32ToString(ptr) {\n    var i = 0;\n\n    var str = \'\';\n    while (1) {\n        var utf32 = HEAP32[(((ptr)+(i*4))>>2)];\n        if (utf32 == 0)\n            return str;\n        ++i;\n        // Gotcha: fromCharCode constructs a character from a UTF-16 encoded code (pair), not from a Unicode code point! So encode the code point to UTF-16 for constructing.\n        // See http://unicode.org/faq/utf_bom.html#utf16-3\n        if (utf32 >= 0x10000) {\n            var ch = utf32 - 0x10000;\n            str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));\n        } else {\n            str += String.fromCharCode(utf32);\n        }\n    }\n}\n\n\n// Copies the given Javascript String object \'str\' to the emscripten HEAP at address \'outPtr\',\n// null-terminated and encoded in UTF32 form. The copy will require at most str.length*4+4 bytes of space in the HEAP.\n// Use the function lengthBytesUTF32() to compute the exact number of bytes (excluding null terminator) that this function will write.\n// Parameters:\n//   str: the Javascript string to copy.\n//   outPtr: Byte address in Emscripten HEAP where to write the string to.\n//   maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null\n//                    terminator, i.e. if maxBytesToWrite=4, only the null terminator will be written and nothing else.\n//                    maxBytesToWrite<4 does not write any bytes to the output, not even the null terminator.\n// Returns the number of bytes written, EXCLUDING the null terminator.\n\nfunction stringToUTF32(str, outPtr, maxBytesToWrite) {\n    // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed.\n    if (maxBytesToWrite === undefined) {\n        maxBytesToWrite = 0x7FFFFFFF;\n    }\n    if (maxBytesToWrite < 4) return 0;\n    var startPtr = outPtr;\n    var endPtr = startPtr + maxBytesToWrite - 4;\n    for (var i = 0; i < str.length; ++i) {\n        // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.\n        // See http://unicode.org/faq/utf_bom.html#utf16-3\n        var codeUnit = str.charCodeAt(i); // possibly a lead surrogate\n        if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {\n            var trailSurrogate = str.charCodeAt(++i);\n            codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);\n        }\n        HEAP32[((outPtr)>>2)]=codeUnit;\n        outPtr += 4;\n        if (outPtr + 4 > endPtr) break;\n    }\n    // Null-terminate the pointer to the HEAP.\n    HEAP32[((outPtr)>>2)]=0;\n    return outPtr - startPtr;\n}\n\n\n// Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte.\n\nfunction lengthBytesUTF32(str) {\n    var len = 0;\n    for (var i = 0; i < str.length; ++i) {\n        // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code unit, not a Unicode code point of the character! We must decode the string to UTF-32 to the heap.\n        // See http://unicode.org/faq/utf_bom.html#utf16-3\n        var codeUnit = str.charCodeAt(i);\n        if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate.\n        len += 4;\n    }\n\n    return len;\n}\n\n\nfunction demangle(func) {\n    var __cxa_demangle_func = Module[\'___cxa_demangle\'] || Module[\'__cxa_demangle\'];\n    if (__cxa_demangle_func) {\n        try {\n            var s =\n                func.substr(1);\n            var len = lengthBytesUTF8(s)+1;\n            var buf = _malloc(len);\n            stringToUTF8(s, buf, len);\n            var status = _malloc(4);\n            var ret = __cxa_demangle_func(buf, 0, 0, status);\n            if (getValue(status, \'i32\') === 0 && ret) {\n                return Pointer_stringify(ret);\n            }\n            // otherwise, libcxxabi failed\n        } catch(e) {\n            // ignore problems here\n        } finally {\n            if (buf) _free(buf);\n            if (status) _free(status);\n            if (ret) _free(ret);\n        }\n        // failure when using libcxxabi, don\'t demangle\n        return func;\n    }\n    Runtime.warnOnce(\'warning: build with  -s DEMANGLE_SUPPORT=1  to link in libcxxabi demangling\');\n    return func;\n}\n\nfunction demangleAll(text) {\n    var regex =\n        /__Z[\\w\\d_]+/g;\n    return text.replace(regex,\n        function(x) {\n            var y = demangle(x);\n            return x === y ? x : (x + \' [\' + y + \']\');\n        });\n}\n\nfunction jsStackTrace() {\n    var err = new Error();\n    if (!err.stack) {\n        // IE10+ special cases: It does have callstack info, but it is only populated if an Error object is thrown,\n        // so try that as a special-case.\n        try {\n            throw new Error(0);\n        } catch(e) {\n            err = e;\n        }\n        if (!err.stack) {\n            return \'(no stack trace available)\';\n        }\n    }\n    return err.stack.toString();\n}\n\nfunction stackTrace() {\n    var js = jsStackTrace();\n    if (Module[\'extraStackTrace\']) js += \'\\n\' + Module[\'extraStackTrace\']();\n    return demangleAll(js);\n}\nModule["stackTrace"] = stackTrace;\n\n// Memory management\n\nvar PAGE_SIZE = 16384;\nvar WASM_PAGE_SIZE = 65536;\nvar ASMJS_PAGE_SIZE = 16777216;\nvar MIN_TOTAL_MEMORY = 16777216;\n\nfunction alignUp(x, multiple) {\n    if (x % multiple > 0) {\n        x += multiple - (x % multiple);\n    }\n    return x;\n}\n\nvar HEAP,\n    /** @type {ArrayBuffer} */\n    buffer,\n    /** @type {Int8Array} */\n    HEAP8,\n    /** @type {Uint8Array} */\n    HEAPU8,\n    /** @type {Int16Array} */\n    HEAP16,\n    /** @type {Uint16Array} */\n    HEAPU16,\n    /** @type {Int32Array} */\n    HEAP32,\n    /** @type {Uint32Array} */\n    HEAPU32,\n    /** @type {Float32Array} */\n    HEAPF32,\n    /** @type {Float64Array} */\n    HEAPF64;\n\nfunction updateGlobalBuffer(buf) {\n    Module[\'buffer\'] = buffer = buf;\n}\n\nfunction updateGlobalBufferViews() {\n    Module[\'HEAP8\'] = HEAP8 = new Int8Array(buffer);\n    Module[\'HEAP16\'] = HEAP16 = new Int16Array(buffer);\n    Module[\'HEAP32\'] = HEAP32 = new Int32Array(buffer);\n    Module[\'HEAPU8\'] = HEAPU8 = new Uint8Array(buffer);\n    Module[\'HEAPU16\'] = HEAPU16 = new Uint16Array(buffer);\n    Module[\'HEAPU32\'] = HEAPU32 = new Uint32Array(buffer);\n    Module[\'HEAPF32\'] = HEAPF32 = new Float32Array(buffer);\n    Module[\'HEAPF64\'] = HEAPF64 = new Float64Array(buffer);\n}\n\nvar STATIC_BASE, STATICTOP, staticSealed; // static area\nvar STACK_BASE, STACKTOP, STACK_MAX; // stack area\nvar DYNAMIC_BASE, DYNAMICTOP_PTR; // dynamic area handled by sbrk\n\nSTATIC_BASE = STATICTOP = STACK_BASE = STACKTOP = STACK_MAX = DYNAMIC_BASE = DYNAMICTOP_PTR = 0;\nstaticSealed = false;\n\n\n\nfunction abortOnCannotGrowMemory() {\n    abort(\'Cannot enlarge memory arrays. Either (1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value \' + TOTAL_MEMORY + \', (2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with  -s ABORTING_MALLOC=0 \');\n}\n\nif (!Module[\'reallocBuffer\']) Module[\'reallocBuffer\'] = function(size) {\n    var ret;\n    try {\n        if (ArrayBuffer.transfer) {\n            ret = ArrayBuffer.transfer(buffer, size);\n        } else {\n            var oldHEAP8 = HEAP8;\n            ret = new ArrayBuffer(size);\n            var temp = new Int8Array(ret);\n            temp.set(oldHEAP8);\n        }\n    } catch(e) {\n        return false;\n    }\n    var success = _emscripten_replace_memory(ret);\n    if (!success) return false;\n    return ret;\n};\n\nfunction enlargeMemory() {\n    // TOTAL_MEMORY is the current size of the actual array, and DYNAMICTOP is the new top.\n\n\n    var PAGE_MULTIPLE = Module["usingWasm"] ? WASM_PAGE_SIZE : ASMJS_PAGE_SIZE; // In wasm, heap size must be a multiple of 64KB. In asm.js, they need to be multiples of 16MB.\n    var LIMIT = 2147483648 - PAGE_MULTIPLE; // We can do one page short of 2GB as theoretical maximum.\n\n    if (HEAP32[DYNAMICTOP_PTR>>2] > LIMIT) {\n        return false;\n    }\n\n    var OLD_TOTAL_MEMORY = TOTAL_MEMORY;\n    TOTAL_MEMORY = Math.max(TOTAL_MEMORY, MIN_TOTAL_MEMORY); // So the loop below will not be infinite, and minimum asm.js memory size is 16MB.\n\n    while (TOTAL_MEMORY < HEAP32[DYNAMICTOP_PTR>>2]) { // Keep incrementing the heap size as long as it\'s less than what is requested.\n        if (TOTAL_MEMORY <= 536870912) {\n            TOTAL_MEMORY = alignUp(2 * TOTAL_MEMORY, PAGE_MULTIPLE); // Simple heuristic: double until 1GB...\n        } else {\n            TOTAL_MEMORY = Math.min(alignUp((3 * TOTAL_MEMORY + 2147483648) / 4, PAGE_MULTIPLE), LIMIT); // ..., but after that, add smaller increments towards 2GB, which we cannot reach\n        }\n    }\n\n\n    var replacement = Module[\'reallocBuffer\'](TOTAL_MEMORY);\n    if (!replacement || replacement.byteLength != TOTAL_MEMORY) {\n        // restore the state to before this call, we failed\n        TOTAL_MEMORY = OLD_TOTAL_MEMORY;\n        return false;\n    }\n\n    // everything worked\n\n    updateGlobalBuffer(replacement);\n    updateGlobalBufferViews();\n\n    return true;\n}\n\nvar byteLength;\ntry {\n    byteLength = Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, \'byteLength\').get);\n    byteLength(new ArrayBuffer(4)); // can fail on older ie\n} catch(e) { // can fail on older node/v8\n    byteLength = function(buffer) { return buffer.byteLength; };\n}\n\nvar TOTAL_STACK = Module[\'TOTAL_STACK\'] || 5242880;\nvar TOTAL_MEMORY = Module[\'TOTAL_MEMORY\'] || 16777216;\nif (TOTAL_MEMORY < TOTAL_STACK) Module.printErr(\'TOTAL_MEMORY should be larger than TOTAL_STACK, was \' + TOTAL_MEMORY + \'! (TOTAL_STACK=\' + TOTAL_STACK + \')\');\n\n// Initialize the runtime\'s memory\n\n\n// Use a provided buffer, if there is one, or else allocate a new one\nif (Module[\'buffer\']) {\n    buffer = Module[\'buffer\'];\n} else {\n    // Use a WebAssembly memory where available\n    if (typeof WebAssembly === \'object\' && typeof WebAssembly.Memory === \'function\') {\n        Module[\'wasmMemory\'] = new WebAssembly.Memory({ \'initial\': TOTAL_MEMORY / WASM_PAGE_SIZE });\n        buffer = Module[\'wasmMemory\'].buffer;\n    } else\n    {\n        buffer = new ArrayBuffer(TOTAL_MEMORY);\n    }\n}\nupdateGlobalBufferViews();\n\n\nfunction getTotalMemory() {\n    return TOTAL_MEMORY;\n}\n\n// Endianness check (note: assumes compiler arch was little-endian)\nHEAP32[0] = 0x63736d65; /* \'emsc\' */\nHEAP16[1] = 0x6373;\nif (HEAPU8[2] !== 0x73 || HEAPU8[3] !== 0x63) throw \'Runtime error: expected the system to be little-endian!\';\n\nModule[\'HEAP\'] = HEAP;\nModule[\'buffer\'] = buffer;\nModule[\'HEAP8\'] = HEAP8;\nModule[\'HEAP16\'] = HEAP16;\nModule[\'HEAP32\'] = HEAP32;\nModule[\'HEAPU8\'] = HEAPU8;\nModule[\'HEAPU16\'] = HEAPU16;\nModule[\'HEAPU32\'] = HEAPU32;\nModule[\'HEAPF32\'] = HEAPF32;\nModule[\'HEAPF64\'] = HEAPF64;\n\nfunction callRuntimeCallbacks(callbacks) {\n    while(callbacks.length > 0) {\n        var callback = callbacks.shift();\n        if (typeof callback == \'function\') {\n            callback();\n            continue;\n        }\n        var func = callback.func;\n        if (typeof func === \'number\') {\n            if (callback.arg === undefined) {\n                Module[\'dynCall_v\'](func);\n            } else {\n                Module[\'dynCall_vi\'](func, callback.arg);\n            }\n        } else {\n            func(callback.arg === undefined ? null : callback.arg);\n        }\n    }\n}\n\nvar __ATPRERUN__  = []; // functions called before the runtime is initialized\nvar __ATINIT__    = []; // functions called during startup\nvar __ATMAIN__    = []; // functions called when main() is to be run\nvar __ATEXIT__    = []; // functions called during shutdown\nvar __ATPOSTRUN__ = []; // functions called after the runtime has exited\n\nvar runtimeInitialized = false;\nvar runtimeExited = false;\n\n\nfunction preRun() {\n    // compatibility - merge in anything from Module[\'preRun\'] at this time\n    if (Module[\'preRun\']) {\n        if (typeof Module[\'preRun\'] == \'function\') Module[\'preRun\'] = [Module[\'preRun\']];\n        while (Module[\'preRun\'].length) {\n            addOnPreRun(Module[\'preRun\'].shift());\n        }\n    }\n    callRuntimeCallbacks(__ATPRERUN__);\n}\n\nfunction ensureInitRuntime() {\n    if (runtimeInitialized) return;\n    runtimeInitialized = true;\n    callRuntimeCallbacks(__ATINIT__);\n}\n\nfunction preMain() {\n    callRuntimeCallbacks(__ATMAIN__);\n}\n\nfunction exitRuntime() {\n    callRuntimeCallbacks(__ATEXIT__);\n    runtimeExited = true;\n}\n\nfunction postRun() {\n    // compatibility - merge in anything from Module[\'postRun\'] at this time\n    if (Module[\'postRun\']) {\n        if (typeof Module[\'postRun\'] == \'function\') Module[\'postRun\'] = [Module[\'postRun\']];\n        while (Module[\'postRun\'].length) {\n            addOnPostRun(Module[\'postRun\'].shift());\n        }\n    }\n    callRuntimeCallbacks(__ATPOSTRUN__);\n}\n\nfunction addOnPreRun(cb) {\n    __ATPRERUN__.unshift(cb);\n}\nModule["addOnPreRun"] = addOnPreRun;\n\nfunction addOnInit(cb) {\n    __ATINIT__.unshift(cb);\n}\nModule["addOnInit"] = addOnInit;\n\nfunction addOnPreMain(cb) {\n    __ATMAIN__.unshift(cb);\n}\nModule["addOnPreMain"] = addOnPreMain;\n\nfunction addOnExit(cb) {\n    __ATEXIT__.unshift(cb);\n}\nModule["addOnExit"] = addOnExit;\n\nfunction addOnPostRun(cb) {\n    __ATPOSTRUN__.unshift(cb);\n}\nModule["addOnPostRun"] = addOnPostRun;\n\n// Tools\n\n/** @type {function(string, boolean=, number=)} */\nfunction intArrayFromString(stringy, dontAddNull, length) {\n    var len = length > 0 ? length : lengthBytesUTF8(stringy)+1;\n    var u8array = new Array(len);\n    var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);\n    if (dontAddNull) u8array.length = numBytesWritten;\n    return u8array;\n}\nModule["intArrayFromString"] = intArrayFromString;\n\nfunction intArrayToString(array) {\n    var ret = [];\n    for (var i = 0; i < array.length; i++) {\n        var chr = array[i];\n        if (chr > 0xFF) {\n            chr &= 0xFF;\n        }\n        ret.push(String.fromCharCode(chr));\n    }\n    return ret.join(\'\');\n}\nModule["intArrayToString"] = intArrayToString;\n\n// Deprecated: This function should not be called because it is unsafe and does not provide\n// a maximum length limit of how many bytes it is allowed to write. Prefer calling the\n// function stringToUTF8Array() instead, which takes in a maximum length that can be used\n// to be secure from out of bounds writes.\n/** @deprecated */\nfunction writeStringToMemory(string, buffer, dontAddNull) {\n    Runtime.warnOnce(\'writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!\');\n\n    var /** @type {number} */ lastChar, /** @type {number} */ end;\n    if (dontAddNull) {\n        // stringToUTF8Array always appends null. If we don\'t want to do that, remember the\n        // character that existed at the location where the null will be placed, and restore\n        // that after the write (below).\n        end = buffer + lengthBytesUTF8(string);\n        lastChar = HEAP8[end];\n    }\n    stringToUTF8(string, buffer, Infinity);\n    if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character.\n}\nModule["writeStringToMemory"] = writeStringToMemory;\n\nfunction writeArrayToMemory(array, buffer) {\n    HEAP8.set(array, buffer);\n}\nModule["writeArrayToMemory"] = writeArrayToMemory;\n\nfunction writeAsciiToMemory(str, buffer, dontAddNull) {\n    for (var i = 0; i < str.length; ++i) {\n        HEAP8[((buffer++)>>0)]=str.charCodeAt(i);\n    }\n    // Null-terminate the pointer to the HEAP.\n    if (!dontAddNull) HEAP8[((buffer)>>0)]=0;\n}\nModule["writeAsciiToMemory"] = writeAsciiToMemory;\n\nfunction unSign(value, bits, ignore) {\n    if (value >= 0) {\n        return value;\n    }\n    return bits <= 32 ? 2*Math.abs(1 << (bits-1)) + value // Need some trickery, since if bits == 32, we are right at the limit of the bits JS uses in bitshifts\n        : Math.pow(2, bits)         + value;\n}\nfunction reSign(value, bits, ignore) {\n    if (value <= 0) {\n        return value;\n    }\n    var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32\n        : Math.pow(2, bits-1);\n    if (value >= half && (bits <= 32 || value > half)) { // for huge values, we can hit the precision limit and always get true here. so don\'t do that\n        // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors\n        // TODO: In i64 mode 1, resign the two parts separately and safely\n        value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts\n    }\n    return value;\n}\n\n// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 )\nif (!Math[\'imul\'] || Math[\'imul\'](0xffffffff, 5) !== -5) Math[\'imul\'] = function imul(a, b) {\n    var ah  = a >>> 16;\n    var al = a & 0xffff;\n    var bh  = b >>> 16;\n    var bl = b & 0xffff;\n    return (al*bl + ((ah*bl + al*bh) << 16))|0;\n};\nMath.imul = Math[\'imul\'];\n\nif (!Math[\'fround\']) {\n    var froundBuffer = new Float32Array(1);\n    Math[\'fround\'] = function(x) { froundBuffer[0] = x; return froundBuffer[0] };\n}\nMath.fround = Math[\'fround\'];\n\nif (!Math[\'clz32\']) Math[\'clz32\'] = function(x) {\n    x = x >>> 0;\n    for (var i = 0; i < 32; i++) {\n        if (x & (1 << (31 - i))) return i;\n    }\n    return 32;\n};\nMath.clz32 = Math[\'clz32\']\n\nif (!Math[\'trunc\']) Math[\'trunc\'] = function(x) {\n    return x < 0 ? Math.ceil(x) : Math.floor(x);\n};\nMath.trunc = Math[\'trunc\'];\n\nvar Math_abs = Math.abs;\nvar Math_cos = Math.cos;\nvar Math_sin = Math.sin;\nvar Math_tan = Math.tan;\nvar Math_acos = Math.acos;\nvar Math_asin = Math.asin;\nvar Math_atan = Math.atan;\nvar Math_atan2 = Math.atan2;\nvar Math_exp = Math.exp;\nvar Math_log = Math.log;\nvar Math_sqrt = Math.sqrt;\nvar Math_ceil = Math.ceil;\nvar Math_floor = Math.floor;\nvar Math_pow = Math.pow;\nvar Math_imul = Math.imul;\nvar Math_fround = Math.fround;\nvar Math_round = Math.round;\nvar Math_min = Math.min;\nvar Math_clz32 = Math.clz32;\nvar Math_trunc = Math.trunc;\n\n// A counter of dependencies for calling run(). If we need to\n// do asynchronous work before running, increment this and\n// decrement it. Incrementing must happen in a place like\n// PRE_RUN_ADDITIONS (used by emcc to add file preloading).\n// Note that you can add dependencies in preRun, even though\n// it happens right before run - run will be postponed until\n// the dependencies are met.\nvar runDependencies = 0;\nvar runDependencyWatcher = null;\nvar dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled\n\nfunction getUniqueRunDependency(id) {\n    return id;\n}\n\nfunction addRunDependency(id) {\n    runDependencies++;\n    if (Module[\'monitorRunDependencies\']) {\n        Module[\'monitorRunDependencies\'](runDependencies);\n    }\n}\nModule["addRunDependency"] = addRunDependency;\n\nfunction removeRunDependency(id) {\n    runDependencies--;\n    if (Module[\'monitorRunDependencies\']) {\n        Module[\'monitorRunDependencies\'](runDependencies);\n    }\n    if (runDependencies == 0) {\n        if (runDependencyWatcher !== null) {\n            clearInterval(runDependencyWatcher);\n            runDependencyWatcher = null;\n        }\n        if (dependenciesFulfilled) {\n            var callback = dependenciesFulfilled;\n            dependenciesFulfilled = null;\n            callback(); // can add another dependenciesFulfilled\n        }\n    }\n}\nModule["removeRunDependency"] = removeRunDependency;\n\nModule["preloadedImages"] = {}; // maps url to image data\nModule["preloadedAudios"] = {}; // maps url to audio data\n\n\n\nvar memoryInitializer = null;\n\n\n\n\n\nfunction integrateWasmJS(Module, wasmFilePath, callback) {\n    // wasm.js has several methods for creating the compiled code module here:\n    //  * \'native-wasm\' : use native WebAssembly support in the browser\n    //  * \'interpret-s-expr\': load s-expression code from a .wast and interpret\n    //  * \'interpret-binary\': load binary wasm and interpret\n    //  * \'interpret-asm2wasm\': load asm.js code, translate to wasm, and interpret\n    //  * \'asmjs\': no wasm, just load the asm.js code and use that (good for testing)\n    // The method can be set at compile time (BINARYEN_METHOD), or runtime by setting Module[\'wasmJSMethod\'].\n    // The method can be a comma-separated list, in which case, we will try the\n    // options one by one. Some of them can fail gracefully, and then we can try\n    // the next.\n\n    // inputs\n\n    var method = Module[\'wasmJSMethod\'] || \'native-wasm\';\n    Module[\'wasmJSMethod\'] = method;\n\n    var wasmTextFile = Module[\'wasmTextFile\'] || \'libqydecoder.wast\';\n    var urlPrefix = /^[http|https]/.test(location.href) ?  location.href.substring(0, location.href.lastIndexOf(\'/\') +1): location.href.substring(5, location.href.lastIndexOf(\'/\') +1); //blob:domainName/xxxx\n\n    Module[\'wasmBinaryFile\']  = wasmFilePath;\n    var wasmBinaryFile = Module[\'wasmBinaryFile\'] || urlPrefix  + \'libqydecoder.wasm\';\n    var asmjsCodeFile = Module[\'asmjsCodeFile\'] || \'libqydecoder.temp.asm.js\';\n\n    if (typeof Module[\'locateFile\'] === \'function\') {\n        wasmTextFile = Module[\'locateFile\'](wasmTextFile);\n        wasmBinaryFile = Module[\'locateFile\'](wasmBinaryFile);\n        asmjsCodeFile = Module[\'locateFile\'](asmjsCodeFile);\n    }\n\n    // utilities\n\n    var wasmPageSize = 64*1024;\n\n    var asm2wasmImports = { // special asm2wasm imports\n        "f64-rem": function(x, y) {\n            return x % y;\n        },\n        "f64-to-int": function(x) {\n            return x | 0;\n        },\n        "i32s-div": function(x, y) {\n            return ((x | 0) / (y | 0)) | 0;\n        },\n        "i32u-div": function(x, y) {\n            return ((x >>> 0) / (y >>> 0)) >>> 0;\n        },\n        "i32s-rem": function(x, y) {\n            return ((x | 0) % (y | 0)) | 0;\n        },\n        "i32u-rem": function(x, y) {\n            return ((x >>> 0) % (y >>> 0)) >>> 0;\n        },\n        "debugger": function() {\n            debugger;\n        },\n    };\n\n    var info = {\n        \'global\': null,\n        \'env\': null,\n        \'asm2wasm\': asm2wasmImports,\n        \'parent\': Module // Module inside wasm-js.cpp refers to wasm-js.cpp; this allows access to the outside program.\n    };\n\n    var exports = null;\n\n    function lookupImport(mod, base) {\n        var lookup = info;\n        if (mod.indexOf(\'.\') < 0) {\n            lookup = (lookup || {})[mod];\n        } else {\n            var parts = mod.split(\'.\');\n            lookup = (lookup || {})[parts[0]];\n            lookup = (lookup || {})[parts[1]];\n        }\n        if (base) {\n            lookup = (lookup || {})[base];\n        }\n        if (lookup === undefined) {\n            abort(\'bad lookupImport to (\' + mod + \').\' + base);\n        }\n        return lookup;\n    }\n\n    function mergeMemory(newBuffer) {\n        // The wasm instance creates its memory. But static init code might have written to\n        // buffer already, including the mem init file, and we must copy it over in a proper merge.\n        // TODO: avoid this copy, by avoiding such static init writes\n        // TODO: in shorter term, just copy up to the last static init write\n        var oldBuffer = Module[\'buffer\'];\n        if (newBuffer.byteLength < oldBuffer.byteLength) {\n            Module[\'printErr\'](\'the new buffer in mergeMemory is smaller than the previous one. in native wasm, we should grow memory here\');\n        }\n        var oldView = new Int8Array(oldBuffer);\n        var newView = new Int8Array(newBuffer);\n\n        // If we have a mem init file, do not trample it\n        if (!memoryInitializer) {\n            oldView.set(newView.subarray(Module[\'STATIC_BASE\'], Module[\'STATIC_BASE\'] + Module[\'STATIC_BUMP\']), Module[\'STATIC_BASE\']);\n        }\n\n        newView.set(oldView);\n        updateGlobalBuffer(newBuffer);\n        updateGlobalBufferViews();\n    }\n\n    var WasmTypes = {\n        none: 0,\n        i32: 1,\n        i64: 2,\n        f32: 3,\n        f64: 4\n    };\n\n    function fixImports(imports) {\n        if (!0) return imports;\n        var ret = {};\n        for (var i in imports) {\n            var fixed = i;\n            if (fixed[0] == \'_\') fixed = fixed.substr(1);\n            ret[fixed] = imports[i];\n        }\n        return ret;\n    }\n\n    function getBinary() {\n        try {\n            var binary;\n            if (Module[\'wasmBinary\']) {\n                binary = Module[\'wasmBinary\'];\n                binary = new Uint8Array(binary);\n            } else if (Module[\'readBinary\']) {\n                binary = Module[\'readBinary\'](wasmBinaryFile);\n            } else {\n                throw "on the web, we need the wasm binary to be preloaded and set on Module[\'wasmBinary\']. emcc.py will do that for you when generating HTML (but not JS)";\n            }\n            return binary;\n        }\n        catch (err) {\n            abort(err);\n        }\n    }\n\n    function getBinaryPromise() {\n        // if we don\'t have the binary yet, and have the Fetch api, use that\n        if (!Module[\'wasmBinary\'] && typeof fetch === \'function\') {\n            return fetch(wasmBinaryFile, { credentials: \'same-origin\' }).then(function(response) {\n                if (!response[\'ok\']) {\n                    throw "failed to load wasm binary file at \'" + wasmBinaryFile + "\'";\n                }\n                return response[\'arrayBuffer\']();\n            });\n        }\n        // Otherwise, getBinary should be able to get it synchronously\n        return new Promise(function(resolve, reject) {\n            resolve(getBinary());\n        });\n    }\n\n    // do-method functions\n\n    function doJustAsm(global, env, providedBuffer) {\n        // if no Module.asm, or it\'s the method handler helper (see below), then apply\n        // the asmjs\n        if (typeof Module[\'asm\'] !== \'function\' || Module[\'asm\'] === methodHandler) {\n            if (!Module[\'asmPreload\']) {\n                // you can load the .asm.js file before this, to avoid this sync xhr and eval\n                eval(Module[\'read\'](asmjsCodeFile)); // set Module.asm\n            } else {\n                Module[\'asm\'] = Module[\'asmPreload\'];\n            }\n        }\n        if (typeof Module[\'asm\'] !== \'function\') {\n            Module[\'printErr\'](\'asm evalling did not set the module properly\');\n            return false;\n        }\n        return Module[\'asm\'](global, env, providedBuffer);\n    }\n\n    function doNativeWasm(global, env, providedBuffer) {\n    \n        if (typeof WebAssembly !== \'object\') {\n            Module[\'printErr\'](\'no native wasm support detected\');\n            return false;\n        }\n        // prepare memory import\n        if (!(Module[\'wasmMemory\'] instanceof WebAssembly.Memory)) {\n            Module[\'printErr\'](\'no native wasm Memory in use\');\n            return false;\n        }\n       \n        env[\'memory\'] = Module[\'wasmMemory\'];\n        // Load the wasm module and create an instance of using native support in the JS engine.\n        info[\'global\'] = {\n            \'NaN\': NaN,\n            \'Infinity\': Infinity\n        };\n        info[\'global.Math\'] = global.Math;\n        info[\'env\'] = env;\n        // handle a generated wasm instance, receiving its exports and\n        // performing other necessary setup\n        function receiveInstance(instance) {\n            exports = instance.exports;\n            if (exports.memory) mergeMemory(exports.memory);\n\n            Module[\'asm\'] = exports;\n            Module["usingWasm"] = true;\n            removeRunDependency(\'wasm-instantiate\');\n            //navigator.WasmIsLoaded = true;\n            callback();\n        }\n\n        addRunDependency(\'wasm-instantiate\'); // we can\'t run yet\n\n        // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback\n        // to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel\n        // to any other async startup actions they are performing.\n        if (Module[\'instantiateWasm\']) {\n            try {\n                return Module[\'instantiateWasm\'](info, receiveInstance);\n            } catch(e) {\n                Module[\'printErr\'](\'Module.instantiateWasm callback failed with error: \' + e);\n                return false;\n            }\n        }\n\n        getBinaryPromise().then(function(binary) {\n            return WebAssembly.instantiate(binary, info)\n        }).then(function(output) {\n            // receiveInstance() will swap in the exports (to Module.asm) so they can be called\n            receiveInstance(output[\'instance\']);\n        }).catch(function(reason) {\n            Module[\'printErr\'](\'failed to asynchronously prepare wasm: \' + reason);\n            abort(reason);\n        });\n        return {}; // no exports yet; we\'ll fill them in later\n    }\n\n    function doWasmPolyfill(global, env, providedBuffer, method) {\n        if (typeof WasmJS !== \'function\') {\n            Module[\'printErr\'](\'WasmJS not detected - polyfill not bundled?\');\n            return false;\n        }\n\n        // Use wasm.js to polyfill and execute code in a wasm interpreter.\n        var wasmJS = WasmJS({});\n\n        // XXX don\'t be confused. Module here is in the outside program. wasmJS is the inner wasm-js.cpp.\n        wasmJS[\'outside\'] = Module; // Inside wasm-js.cpp, Module[\'outside\'] reaches the outside module.\n\n        // Information for the instance of the module.\n        wasmJS[\'info\'] = info;\n\n        wasmJS[\'lookupImport\'] = lookupImport;\n\n        assert(providedBuffer === Module[\'buffer\']); // we should not even need to pass it as a 3rd arg for wasm, but that\'s the asm.js way.\n\n        info.global = global;\n        info.env = env;\n    \n\n        // polyfill interpreter expects an ArrayBuffer\n        assert(providedBuffer === Module[\'buffer\']);\n        env[\'memory\'] = providedBuffer;\n        assert(env[\'memory\'] instanceof ArrayBuffer);\n\n        wasmJS[\'providedTotalMemory\'] = Module[\'buffer\'].byteLength;\n\n        // Prepare to generate wasm, using either asm2wasm or s-exprs\n        var code;\n        if (method === \'interpret-binary\') {\n            code = getBinary();\n        } else {\n            code = Module[\'read\'](method == \'interpret-asm2wasm\' ? asmjsCodeFile : wasmTextFile);\n        }\n        var temp;\n        if (method == \'interpret-asm2wasm\') {\n            temp = wasmJS[\'_malloc\'](code.length + 1);\n            wasmJS[\'writeAsciiToMemory\'](code, temp);\n            wasmJS[\'_load_asm2wasm\'](temp);\n        } else if (method === \'interpret-s-expr\') {\n            temp = wasmJS[\'_malloc\'](code.length + 1);\n            wasmJS[\'writeAsciiToMemory\'](code, temp);\n            wasmJS[\'_load_s_expr2wasm\'](temp);\n        } else if (method === \'interpret-binary\') {\n            temp = wasmJS[\'_malloc\'](code.length);\n            wasmJS[\'HEAPU8\'].set(code, temp);\n            wasmJS[\'_load_binary2wasm\'](temp, code.length);\n        } else {\n            throw \'what? \' + method;\n        }\n        wasmJS[\'_free\'](temp);\n\n        wasmJS[\'_instantiate\'](temp);\n\n        if (Module[\'newBuffer\']) {\n            mergeMemory(Module[\'newBuffer\']);\n            Module[\'newBuffer\'] = null;\n        }\n\n        exports = wasmJS[\'asmExports\'];\n\n        return exports;\n    }\n\n    // We may have a preloaded value in Module.asm, save it\n    Module[\'asmPreload\'] = Module[\'asm\'];\n\n    // Memory growth integration code\n\n    var asmjsReallocBuffer = Module[\'reallocBuffer\'];\n\n    var wasmReallocBuffer = function(size) {\n        var PAGE_MULTIPLE = Module["usingWasm"] ? WASM_PAGE_SIZE : ASMJS_PAGE_SIZE; // In wasm, heap size must be a multiple of 64KB. In asm.js, they need to be multiples of 16MB.\n        size = alignUp(size, PAGE_MULTIPLE); // round up to wasm page size\n        var old = Module[\'buffer\'];\n        var oldSize = old.byteLength;\n        if (Module["usingWasm"]) {\n            // native wasm support\n            try {\n                var result = Module[\'wasmMemory\'].grow((size - oldSize) / wasmPageSize); // .grow() takes a delta compared to the previous size\n                if (result !== (-1 | 0)) {\n                    // success in native wasm memory growth, get the buffer from the memory\n                    return Module[\'buffer\'] = Module[\'wasmMemory\'].buffer;\n                } else {\n                    return null;\n                }\n            } catch(e) {\n                return null;\n            }\n        } else {\n            // wasm interpreter support\n            exports[\'__growWasmMemory\']((size - oldSize) / wasmPageSize); // tiny wasm method that just does grow_memory\n            // in interpreter, we replace Module.buffer if we allocate\n            return Module[\'buffer\'] !== old ? Module[\'buffer\'] : null; // if it was reallocated, it changed\n        }\n    };\n\n    Module[\'reallocBuffer\'] = function(size) {\n        if (finalMethod === \'asmjs\') {\n            return asmjsReallocBuffer(size);\n        } else {\n            return wasmReallocBuffer(size);\n        }\n    };\n\n    // we may try more than one; this is the final one, that worked and we are using\n    var finalMethod = \'\';\n\n    // Provide an "asm.js function" for the application, called to "link" the asm.js module. We instantiate\n    // the wasm module at that time, and it receives imports and provides exports and so forth, the app\n    // doesn\'t need to care that it is wasm or olyfilled wasm or asm.js.\n\n    Module[\'asm\'] = function(global, env, providedBuffer) {\n        global = fixImports(global);\n    \n        env = fixImports(env);\n\n        // import table\n        if (!env[\'table\']) {\n            var TABLE_SIZE = Module[\'wasmTableSize\'];\n            if (TABLE_SIZE === undefined) TABLE_SIZE = 1024; // works in binaryen interpreter at least\n            var MAX_TABLE_SIZE = Module[\'wasmMaxTableSize\'];\n            if (typeof WebAssembly === \'object\' && typeof WebAssembly.Table === \'function\') {\n                if (MAX_TABLE_SIZE !== undefined) {\n                    env[\'table\'] = new WebAssembly.Table({ \'initial\': TABLE_SIZE, \'maximum\': MAX_TABLE_SIZE, \'element\': \'anyfunc\' });\n                } else {\n                    env[\'table\'] = new WebAssembly.Table({ \'initial\': TABLE_SIZE, element: \'anyfunc\' });\n                }\n            } else {\n                env[\'table\'] = new Array(TABLE_SIZE); // works in binaryen interpreter at least\n            }\n            Module[\'wasmTable\'] = env[\'table\'];\n        }\n\n        if (!env[\'memoryBase\']) {\n            env[\'memoryBase\'] = Module[\'STATIC_BASE\']; // tell the memory segments where to place themselves\n        }\n        if (!env[\'tableBase\']) {\n            env[\'tableBase\'] = 0; // table starts at 0 by default, in dynamic linking this will change\n        }\n\n        // try the methods. each should return the exports if it succeeded\n\n        var exports;\n        exports = doNativeWasm(global, env, providedBuffer);\n\n\n        return exports;\n    };\n\n    var methodHandler = Module[\'asm\']; // note our method handler, as we may modify Module[\'asm\'] later\n}\n\n//integrateWasmJS(Module);\n\n// === Body ===\n\nvar ASM_CONSTS = [];\n\n\n\n\nSTATIC_BASE = Runtime.GLOBAL_BASE;\n\nSTATICTOP = STATIC_BASE + 57600;\n/* global initializers */  __ATINIT__.push({ func: function() { __GLOBAL__sub_I_DecParameterSetReader_cpp() } });\n\n\n//memoryInitializer = Module["wasmJSMethod"].indexOf("asmjs") >= 0 || Module["wasmJSMethod"].indexOf("interpret-asm2wasm") >= 0 ? "libqydecoder.js.mem" : null;\n\n\n\n\nvar STATIC_BUMP = 57600;\nModule["STATIC_BASE"] = STATIC_BASE;\nModule["STATIC_BUMP"] = STATIC_BUMP;\n\n/* no memory initializer */\nvar tempDoublePtr = STATICTOP; STATICTOP += 16;\n\nfunction copyTempFloat(ptr) { // functions, because inlining this code increases code size too much\n\n    HEAP8[tempDoublePtr] = HEAP8[ptr];\n\n    HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n\n    HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n\n    HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n\n}\n\nfunction copyTempDouble(ptr) {\n\n    HEAP8[tempDoublePtr] = HEAP8[ptr];\n\n    HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];\n\n    HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];\n\n    HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];\n\n    HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];\n\n    HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];\n\n    HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];\n\n    HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];\n\n}\n\n// {{PRE_LIBRARY}}\n\n\n\n\n\n\n\n\n\n\nfunction _pthread_mutexattr_settype() {}\n\nfunction _abort() {\n    Module[\'abort\']();\n}\n\nfunction _pthread_cond_destroy() { return 0; }\n\nfunction _pthread_mutex_destroy() {}\n\nfunction _pthread_once(ptr, func) {\n    if (!_pthread_once.seen) _pthread_once.seen = {};\n    if (ptr in _pthread_once.seen) return;\n    Module[\'dynCall_v\'](func);\n    _pthread_once.seen[ptr] = 1;\n}\n\nfunction _pthread_create() {\n    return 11;\n}\n\nfunction ___lock() {}\n\nfunction ___unlock() {}\n\nfunction _usleep(useconds) {\n    // int usleep(useconds_t useconds);\n    // http://pubs.opengroup.org/onlinepubs/000095399/functions/usleep.html\n    // We\'re single-threaded, so use a busy loop. Super-ugly.\n    var msec = useconds / 1000;\n    if ((ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && self[\'performance\'] && self[\'performance\'][\'now\']) {\n        var start = self[\'performance\'][\'now\']();\n        while (self[\'performance\'][\'now\']() - start < msec) {\n            // Do nothing.\n        }\n    } else {\n        var start = Date.now();\n        while (Date.now() - start < msec) {\n            // Do nothing.\n        }\n    }\n    return 0;\n}\n\nfunction _pthread_cond_wait() { return 0; }\n\n\nvar PTHREAD_SPECIFIC={};function _pthread_getspecific(key) {\n    return PTHREAD_SPECIFIC[key] || 0;\n}\n\n\nvar PTHREAD_SPECIFIC_NEXT_KEY=1;\n\nvar ERRNO_CODES={EPERM:1,ENOENT:2,ESRCH:3,EINTR:4,EIO:5,ENXIO:6,E2BIG:7,ENOEXEC:8,EBADF:9,ECHILD:10,EAGAIN:11,EWOULDBLOCK:11,ENOMEM:12,EACCES:13,EFAULT:14,ENOTBLK:15,EBUSY:16,EEXIST:17,EXDEV:18,ENODEV:19,ENOTDIR:20,EISDIR:21,EINVAL:22,ENFILE:23,EMFILE:24,ENOTTY:25,ETXTBSY:26,EFBIG:27,ENOSPC:28,ESPIPE:29,EROFS:30,EMLINK:31,EPIPE:32,EDOM:33,ERANGE:34,ENOMSG:42,EIDRM:43,ECHRNG:44,EL2NSYNC:45,EL3HLT:46,EL3RST:47,ELNRNG:48,EUNATCH:49,ENOCSI:50,EL2HLT:51,EDEADLK:35,ENOLCK:37,EBADE:52,EBADR:53,EXFULL:54,ENOANO:55,EBADRQC:56,EBADSLT:57,EDEADLOCK:35,EBFONT:59,ENOSTR:60,ENODATA:61,ETIME:62,ENOSR:63,ENONET:64,ENOPKG:65,EREMOTE:66,ENOLINK:67,EADV:68,ESRMNT:69,ECOMM:70,EPROTO:71,EMULTIHOP:72,EDOTDOT:73,EBADMSG:74,ENOTUNIQ:76,EBADFD:77,EREMCHG:78,ELIBACC:79,ELIBBAD:80,ELIBSCN:81,ELIBMAX:82,ELIBEXEC:83,ENOSYS:38,ENOTEMPTY:39,ENAMETOOLONG:36,ELOOP:40,EOPNOTSUPP:95,EPFNOSUPPORT:96,ECONNRESET:104,ENOBUFS:105,EAFNOSUPPORT:97,EPROTOTYPE:91,ENOTSOCK:88,ENOPROTOOPT:92,ESHUTDOWN:108,ECONNREFUSED:111,EADDRINUSE:98,ECONNABORTED:103,ENETUNREACH:101,ENETDOWN:100,ETIMEDOUT:110,EHOSTDOWN:112,EHOSTUNREACH:113,EINPROGRESS:115,EALREADY:114,EDESTADDRREQ:89,EMSGSIZE:90,EPROTONOSUPPORT:93,ESOCKTNOSUPPORT:94,EADDRNOTAVAIL:99,ENETRESET:102,EISCONN:106,ENOTCONN:107,ETOOMANYREFS:109,EUSERS:87,EDQUOT:122,ESTALE:116,ENOTSUP:95,ENOMEDIUM:123,EILSEQ:84,EOVERFLOW:75,ECANCELED:125,ENOTRECOVERABLE:131,EOWNERDEAD:130,ESTRPIPE:86};function _pthread_key_create(key, destructor) {\n    if (key == 0) {\n        return ERRNO_CODES.EINVAL;\n    }\n    HEAP32[((key)>>2)]=PTHREAD_SPECIFIC_NEXT_KEY;\n    // values start at 0\n    PTHREAD_SPECIFIC[PTHREAD_SPECIFIC_NEXT_KEY] = 0;\n    PTHREAD_SPECIFIC_NEXT_KEY++;\n    return 0;\n}\n\nfunction _pthread_mutex_init() {}\n\nvar _tzname=STATICTOP; STATICTOP += 16;;\nvar _daylight=STATICTOP; STATICTOP += 16;;\nvar _timezone=STATICTOP; STATICTOP += 16;;\n\nfunction _tzset() {\n    // TODO: Use (malleable) environment variables instead of system settings.\n    if (_tzset.called) return;\n    _tzset.called = true;\n\n    HEAP32[((_timezone)>>2)]=-(new Date()).getTimezoneOffset() * 60;\n\n    var winter = new Date(2000, 0, 1);\n    var summer = new Date(2000, 6, 1);\n    HEAP32[((_daylight)>>2)]=Number(winter.getTimezoneOffset() != summer.getTimezoneOffset());\n\n    function extractZone(date) {\n      var match = date.toTimeString().match(/\\(([A-Za-z ]+)\\)$/);\n      return match ? match[1] : "GMT";\n    };\n    var winterName = extractZone(winter);\n    var summerName = extractZone(summer);\n    var winterNamePtr = allocate(intArrayFromString(winterName), \'i8\', ALLOC_NORMAL);\n    var summerNamePtr = allocate(intArrayFromString(summerName), \'i8\', ALLOC_NORMAL);\n    if (summer.getTimezoneOffset() < winter.getTimezoneOffset()) {\n      // Northern hemisphere\n      HEAP32[((_tzname)>>2)]=winterNamePtr;\n      HEAP32[(((_tzname)+(4))>>2)]=summerNamePtr;\n    } else {\n      HEAP32[((_tzname)>>2)]=summerNamePtr;\n      HEAP32[(((_tzname)+(4))>>2)]=winterNamePtr;\n    }\n  }\n\nfunction _mktime(tmPtr) {\n    _tzset();\n    var date = new Date(HEAP32[(((tmPtr)+(20))>>2)] + 1900,\n                        HEAP32[(((tmPtr)+(16))>>2)],\n                        HEAP32[(((tmPtr)+(12))>>2)],\n                        HEAP32[(((tmPtr)+(8))>>2)],\n                        HEAP32[(((tmPtr)+(4))>>2)],\n                        HEAP32[((tmPtr)>>2)],\n                        0);\n\n    // There\'s an ambiguous hour when the time goes back; the tm_isdst field is\n    // used to disambiguate it.  Date() basically guesses, so we fix it up if it\n    // guessed wrong, or fill in tm_isdst with the guess if it\'s -1.\n    var dst = HEAP32[(((tmPtr)+(32))>>2)];\n    var guessedOffset = date.getTimezoneOffset();\n    var start = new Date(date.getFullYear(), 0, 1);\n    var summerOffset = new Date(2000, 6, 1).getTimezoneOffset();\n    var winterOffset = start.getTimezoneOffset();\n    var dstOffset = Math.min(winterOffset, summerOffset); // DST is in December in South\n    if (dst < 0) {\n      HEAP32[(((tmPtr)+(32))>>2)]=Number(dstOffset == guessedOffset);\n    } else if ((dst > 0) != (dstOffset == guessedOffset)) {\n      var nonDstOffset = Math.max(winterOffset, summerOffset);\n      var trueOffset = dst > 0 ? dstOffset : nonDstOffset;\n      // Don\'t try setMinutes(date.getMinutes() + ...) -- it\'s messed up.\n      date.setTime(date.getTime() + (trueOffset - guessedOffset)*60000);\n    }\n\n    HEAP32[(((tmPtr)+(24))>>2)]=date.getDay();\n    var yday = ((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24))|0;\n    HEAP32[(((tmPtr)+(28))>>2)]=yday;\n\n    return (date.getTime() / 1000)|0;\n  }\n\nfunction _pthread_setspecific(key, value) {\n    if (!(key in PTHREAD_SPECIFIC)) {\n        return ERRNO_CODES.EINVAL;\n    }\n    PTHREAD_SPECIFIC[key] = value;\n    return 0;\n}\n\n\n\n\nvar ERRNO_MESSAGES={0:"Success",1:"Not super-user",2:"No such file or directory",3:"No such process",4:"Interrupted system call",5:"I/O error",6:"No such device or address",7:"Arg list too long",8:"Exec format error",9:"Bad file number",10:"No children",11:"No more processes",12:"Not enough core",13:"Permission denied",14:"Bad address",15:"Block device required",16:"Mount device busy",17:"File exists",18:"Cross-device link",19:"No such device",20:"Not a directory",21:"Is a directory",22:"Invalid argument",23:"Too many open files in system",24:"Too many open files",25:"Not a typewriter",26:"Text file busy",27:"File too large",28:"No space left on device",29:"Illegal seek",30:"Read only file system",31:"Too many links",32:"Broken pipe",33:"Math arg out of domain of func",34:"Math result not representable",35:"File locking deadlock error",36:"File or path name too long",37:"No record locks available",38:"Function not implemented",39:"Directory not empty",40:"Too many symbolic links",42:"No message of desired type",43:"Identifier removed",44:"Channel number out of range",45:"Level 2 not synchronized",46:"Level 3 halted",47:"Level 3 reset",48:"Link number out of range",49:"Protocol driver not attached",50:"No CSI structure available",51:"Level 2 halted",52:"Invalid exchange",53:"Invalid request descriptor",54:"Exchange full",55:"No anode",56:"Invalid request code",57:"Invalid slot",59:"Bad font file fmt",60:"Device not a stream",61:"No data (for no delay io)",62:"Timer expired",63:"Out of streams resources",64:"Machine is not on the network",65:"Package not installed",66:"The object is remote",67:"The link has been severed",68:"Advertise error",69:"Srmount error",70:"Communication error on send",71:"Protocol error",72:"Multihop attempted",73:"Cross mount point (not really error)",74:"Trying to read unreadable message",75:"Value too large for defined data type",76:"Given log. name not unique",77:"f.d. invalid for this operation",78:"Remote address changed",79:"Can   access a needed shared lib",80:"Accessing a corrupted shared lib",81:".lib section in a.out corrupted",82:"Attempting to link in too many libs",83:"Attempting to exec a shared library",84:"Illegal byte sequence",86:"Streams pipe error",87:"Too many users",88:"Socket operation on non-socket",89:"Destination address required",90:"Message too long",91:"Protocol wrong type for socket",92:"Protocol not available",93:"Unknown protocol",94:"Socket type not supported",95:"Not supported",96:"Protocol family not supported",97:"Address family not supported by protocol family",98:"Address already in use",99:"Address not available",100:"Network interface is not configured",101:"Network is unreachable",102:"Connection reset by network",103:"Connection aborted",104:"Connection reset by peer",105:"No buffer space available",106:"Socket is already connected",107:"Socket is not connected",108:"Can\'t send after socket shutdown",109:"Too many references",110:"Connection timed out",111:"Connection refused",112:"Host is down",113:"Host is unreachable",114:"Socket already connected",115:"Connection already in progress",116:"Stale file handle",122:"Quota exceeded",123:"No medium (in tape drive)",125:"Operation canceled",130:"Previous owner died",131:"State not recoverable"};\n\nfunction ___setErrNo(value) {\n    if (Module[\'___errno_location\']) HEAP32[((Module[\'___errno_location\']())>>2)]=value;\n    return value;\n}\n\nvar PATH={splitPath:function (filename) {\n    var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/;\n    return splitPathRe.exec(filename).slice(1);\n},normalizeArray:function (parts, allowAboveRoot) {\n    // if the path tries to go above the root, up ends up > 0\n    var up = 0;\n    for (var i = parts.length - 1; i >= 0; i--) {\n        var last = parts[i];\n        if (last === \'.\') {\n            parts.splice(i, 1);\n        } else if (last === \'..\') {\n            parts.splice(i, 1);\n            up++;\n        } else if (up) {\n            parts.splice(i, 1);\n            up--;\n        }\n    }\n    // if the path is allowed to go above the root, restore leading ..s\n    if (allowAboveRoot) {\n        for (; up; up--) {\n            parts.unshift(\'..\');\n        }\n    }\n    return parts;\n},normalize:function (path) {\n    var isAbsolute = path.charAt(0) === \'/\',\n        trailingSlash = path.substr(-1) === \'/\';\n    // Normalize the path\n    path = PATH.normalizeArray(path.split(\'/\').filter(function(p) {\n        return !!p;\n    }), !isAbsolute).join(\'/\');\n    if (!path && !isAbsolute) {\n        path = \'.\';\n    }\n    if (path && trailingSlash) {\n        path += \'/\';\n    }\n    return (isAbsolute ? \'/\' : \'\') + path;\n},dirname:function (path) {\n    var result = PATH.splitPath(path),\n        root = result[0],\n        dir = result[1];\n    if (!root && !dir) {\n        // No dirname whatsoever\n        return \'.\';\n    }\n    if (dir) {\n        // It has a dirname, strip trailing slash\n        dir = dir.substr(0, dir.length - 1);\n    }\n    return root + dir;\n},basename:function (path) {\n    // EMSCRIPTEN return \'/\'\' for \'/\', not an empty string\n    if (path === \'/\') return \'/\';\n    var lastSlash = path.lastIndexOf(\'/\');\n    if (lastSlash === -1) return path;\n    return path.substr(lastSlash+1);\n},extname:function (path) {\n    return PATH.splitPath(path)[3];\n},join:function () {\n    var paths = Array.prototype.slice.call(arguments, 0);\n    return PATH.normalize(paths.join(\'/\'));\n},join2:function (l, r) {\n    return PATH.normalize(l + \'/\' + r);\n},resolve:function () {\n    var resolvedPath = \'\',\n        resolvedAbsolute = false;\n    for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n        var path = (i >= 0) ? arguments[i] : FS.cwd();\n        // Skip empty and invalid entries\n        if (typeof path !== \'string\') {\n            throw new TypeError(\'Arguments to path.resolve must be strings\');\n        } else if (!path) {\n            return \'\'; // an invalid portion invalidates the whole thing\n        }\n        resolvedPath = path + \'/\' + resolvedPath;\n        resolvedAbsolute = path.charAt(0) === \'/\';\n    }\n    // At this point the path should be resolved to a full absolute path, but\n    // handle relative paths to be safe (might happen when process.cwd() fails)\n    resolvedPath = PATH.normalizeArray(resolvedPath.split(\'/\').filter(function(p) {\n        return !!p;\n    }), !resolvedAbsolute).join(\'/\');\n    return ((resolvedAbsolute ? \'/\' : \'\') + resolvedPath) || \'.\';\n},relative:function (from, to) {\n    from = PATH.resolve(from).substr(1);\n    to = PATH.resolve(to).substr(1);\n    function trim(arr) {\n        var start = 0;\n        for (; start < arr.length; start++) {\n            if (arr[start] !== \'\') break;\n        }\n        var end = arr.length - 1;\n        for (; end >= 0; end--) {\n            if (arr[end] !== \'\') break;\n        }\n        if (start > end) return [];\n        return arr.slice(start, end - start + 1);\n    }\n    var fromParts = trim(from.split(\'/\'));\n    var toParts = trim(to.split(\'/\'));\n    var length = Math.min(fromParts.length, toParts.length);\n    var samePartsLength = length;\n    for (var i = 0; i < length; i++) {\n        if (fromParts[i] !== toParts[i]) {\n            samePartsLength = i;\n            break;\n        }\n    }\n    var outputParts = [];\n    for (var i = samePartsLength; i < fromParts.length; i++) {\n        outputParts.push(\'..\');\n    }\n    outputParts = outputParts.concat(toParts.slice(samePartsLength));\n    return outputParts.join(\'/\');\n}};\n\nvar TTY={ttys:[],init:function () {\n    // https://github.com/kripken/emscripten/pull/1555\n    // if (ENVIRONMENT_IS_NODE) {\n    //   // currently, FS.init does not distinguish if process.stdin is a file or TTY\n    //   // device, it always assumes it\'s a TTY device. because of this, we\'re forcing\n    //   // process.stdin to UTF8 encoding to at least make stdin reading compatible\n    //   // with text files until FS.init can be refactored.\n    //   process[\'stdin\'][\'setEncoding\'](\'utf8\');\n    // }\n},shutdown:function () {\n    // https://github.com/kripken/emscripten/pull/1555\n    // if (ENVIRONMENT_IS_NODE) {\n    //   // inolen: any idea as to why node -e \'process.stdin.read()\' wouldn\'t exit immediately (with process.stdin being a tty)?\n    //   // isaacs: because now it\'s reading from the stream, you\'ve expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation\n    //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?\n    //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle\n    //   // isaacs: do process.stdin.pause() and i\'d think it\'d probably close the pending call\n    //   process[\'stdin\'][\'pause\']();\n    // }\n},register:function (dev, ops) {\n    TTY.ttys[dev] = { input: [], output: [], ops: ops };\n    FS.registerDevice(dev, TTY.stream_ops);\n},stream_ops:{open:function (stream) {\n    var tty = TTY.ttys[stream.node.rdev];\n    if (!tty) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENODEV);\n    }\n    stream.tty = tty;\n    stream.seekable = false;\n},close:function (stream) {\n    // flush any pending line data\n    stream.tty.ops.flush(stream.tty);\n},flush:function (stream) {\n    stream.tty.ops.flush(stream.tty);\n},read:function (stream, buffer, offset, length, pos /* ignored */) {\n    if (!stream.tty || !stream.tty.ops.get_char) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENXIO);\n    }\n    var bytesRead = 0;\n    for (var i = 0; i < length; i++) {\n        var result;\n        try {\n            result = stream.tty.ops.get_char(stream.tty);\n        } catch (e) {\n            throw new FS.ErrnoError(ERRNO_CODES.EIO);\n        }\n        if (result === undefined && bytesRead === 0) {\n            throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);\n        }\n        if (result === null || result === undefined) break;\n        bytesRead++;\n        buffer[offset+i] = result;\n    }\n    if (bytesRead) {\n        stream.node.timestamp = Date.now();\n    }\n    return bytesRead;\n},write:function (stream, buffer, offset, length, pos) {\n    if (!stream.tty || !stream.tty.ops.put_char) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENXIO);\n    }\n    for (var i = 0; i < length; i++) {\n        try {\n            stream.tty.ops.put_char(stream.tty, buffer[offset+i]);\n        } catch (e) {\n            throw new FS.ErrnoError(ERRNO_CODES.EIO);\n        }\n    }\n    if (length) {\n        stream.node.timestamp = Date.now();\n    }\n    return i;\n}},default_tty_ops:{get_char:function (tty) {\n    if (!tty.input.length) {\n        var result = null;\n        if (ENVIRONMENT_IS_NODE) {\n            // we will read data by chunks of BUFSIZE\n            var BUFSIZE = 256;\n            var buf = new Buffer(BUFSIZE);\n            var bytesRead = 0;\n\n            var isPosixPlatform = (process.platform != \'win32\'); // Node doesn\'t offer a direct check, so test by exclusion\n\n            var fd = process.stdin.fd;\n            if (isPosixPlatform) {\n                // Linux and Mac cannot use process.stdin.fd (which isn\'t set up as sync)\n                var usingDevice = false;\n                try {\n                    fd = fs.openSync(\'/dev/stdin\', \'r\');\n                    usingDevice = true;\n                } catch (e) {}\n            }\n\n            try {\n                bytesRead = fs.readSync(fd, buf, 0, BUFSIZE, null);\n            } catch(e) {\n                // Cross-platform differences: on Windows, reading EOF throws an exception, but on other OSes,\n                // reading EOF returns 0. Uniformize behavior by treating the EOF exception to return 0.\n                if (e.toString().indexOf(\'EOF\') != -1) bytesRead = 0;\n                else throw e;\n            }\n\n            if (usingDevice) { fs.closeSync(fd); }\n            if (bytesRead > 0) {\n                result = buf.slice(0, bytesRead).toString(\'utf-8\');\n            } else {\n                result = null;\n            }\n\n        } else if (typeof window != \'undefined\' &&\n            typeof window.prompt == \'function\') {\n            // Browser.\n            result = window.prompt(\'Input: \');  // returns null on cancel\n            if (result !== null) {\n                result += \'\\n\';\n            }\n        } else if (typeof readline == \'function\') {\n            // Command line.\n            result = readline();\n            if (result !== null) {\n                result += \'\\n\';\n            }\n        }\n        if (!result) {\n            return null;\n        }\n        tty.input = intArrayFromString(result, true);\n    }\n    return tty.input.shift();\n},put_char:function (tty, val) {\n    if (val === null || val === 10) {\n        Module[\'print\'](UTF8ArrayToString(tty.output, 0));\n        tty.output = [];\n    } else {\n        if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle.\n    }\n},flush:function (tty) {\n    if (tty.output && tty.output.length > 0) {\n        Module[\'print\'](UTF8ArrayToString(tty.output, 0));\n        tty.output = [];\n    }\n}},default_tty1_ops:{put_char:function (tty, val) {\n    if (val === null || val === 10) {\n        Module[\'printErr\'](UTF8ArrayToString(tty.output, 0));\n        tty.output = [];\n    } else {\n        if (val != 0) tty.output.push(val);\n    }\n},flush:function (tty) {\n    if (tty.output && tty.output.length > 0) {\n        Module[\'printErr\'](UTF8ArrayToString(tty.output, 0));\n        tty.output = [];\n    }\n}}};\n\nvar MEMFS={ops_table:null,mount:function (mount) {\n    return MEMFS.createNode(null, \'/\', 16384 | 511 /* 0777 */, 0);\n},createNode:function (parent, name, mode, dev) {\n    if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n        // no supported\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    if (!MEMFS.ops_table) {\n        MEMFS.ops_table = {\n            dir: {\n                node: {\n                    getattr: MEMFS.node_ops.getattr,\n                    setattr: MEMFS.node_ops.setattr,\n                    lookup: MEMFS.node_ops.lookup,\n                    mknod: MEMFS.node_ops.mknod,\n                    rename: MEMFS.node_ops.rename,\n                    unlink: MEMFS.node_ops.unlink,\n                    rmdir: MEMFS.node_ops.rmdir,\n                    readdir: MEMFS.node_ops.readdir,\n                    symlink: MEMFS.node_ops.symlink\n                },\n                stream: {\n                    llseek: MEMFS.stream_ops.llseek\n                }\n            },\n            file: {\n                node: {\n                    getattr: MEMFS.node_ops.getattr,\n                    setattr: MEMFS.node_ops.setattr\n                },\n                stream: {\n                    llseek: MEMFS.stream_ops.llseek,\n                    read: MEMFS.stream_ops.read,\n                    write: MEMFS.stream_ops.write,\n                    allocate: MEMFS.stream_ops.allocate,\n                    mmap: MEMFS.stream_ops.mmap,\n                    msync: MEMFS.stream_ops.msync\n                }\n            },\n            link: {\n                node: {\n                    getattr: MEMFS.node_ops.getattr,\n                    setattr: MEMFS.node_ops.setattr,\n                    readlink: MEMFS.node_ops.readlink\n                },\n                stream: {}\n            },\n            chrdev: {\n                node: {\n                    getattr: MEMFS.node_ops.getattr,\n                    setattr: MEMFS.node_ops.setattr\n                },\n                stream: FS.chrdev_stream_ops\n            }\n        };\n    }\n    var node = FS.createNode(parent, name, mode, dev);\n    if (FS.isDir(node.mode)) {\n        node.node_ops = MEMFS.ops_table.dir.node;\n        node.stream_ops = MEMFS.ops_table.dir.stream;\n        node.contents = {};\n    } else if (FS.isFile(node.mode)) {\n        node.node_ops = MEMFS.ops_table.file.node;\n        node.stream_ops = MEMFS.ops_table.file.stream;\n        node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity.\n        // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred\n        // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size\n        // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme.\n        node.contents = null;\n    } else if (FS.isLink(node.mode)) {\n        node.node_ops = MEMFS.ops_table.link.node;\n        node.stream_ops = MEMFS.ops_table.link.stream;\n    } else if (FS.isChrdev(node.mode)) {\n        node.node_ops = MEMFS.ops_table.chrdev.node;\n        node.stream_ops = MEMFS.ops_table.chrdev.stream;\n    }\n    node.timestamp = Date.now();\n    // add the new node to the parent\n    if (parent) {\n        parent.contents[name] = node;\n    }\n    return node;\n},getFileDataAsRegularArray:function (node) {\n    if (node.contents && node.contents.subarray) {\n        var arr = [];\n        for (var i = 0; i < node.usedBytes; ++i) arr.push(node.contents[i]);\n        return arr; // Returns a copy of the original data.\n    }\n    return node.contents; // No-op, the file contents are already in a JS array. Return as-is.\n},getFileDataAsTypedArray:function (node) {\n    if (!node.contents) return new Uint8Array;\n    if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes); // Make sure to not return excess unused bytes.\n    return new Uint8Array(node.contents);\n},expandFileStorage:function (node, newCapacity) {\n    // If we are asked to expand the size of a file that already exists, revert to using a standard JS array to store the file\n    // instead of a typed array. This makes resizing the array more flexible because we can just .push() elements at the back to\n    // increase the size.\n    if (node.contents && node.contents.subarray && newCapacity > node.contents.length) {\n        node.contents = MEMFS.getFileDataAsRegularArray(node);\n        node.usedBytes = node.contents.length; // We might be writing to a lazy-loaded file which had overridden this property, so force-reset it.\n    }\n\n    if (!node.contents || node.contents.subarray) { // Keep using a typed array if creating a new storage, or if old one was a typed array as well.\n        var prevCapacity = node.contents ? node.contents.length : 0;\n        if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough.\n        // Don\'t expand strictly to the given requested limit if it\'s only a very small increase, but instead geometrically grow capacity.\n        // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to\n        // avoid overshooting the allocation cap by a very large margin.\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024;\n        newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) | 0);\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding.\n        var oldContents = node.contents;\n        node.contents = new Uint8Array(newCapacity); // Allocate new storage.\n        if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); // Copy old data over to the new storage.\n        return;\n    }\n    // Not using a typed array to back the file storage. Use a standard JS array instead.\n    if (!node.contents && newCapacity > 0) node.contents = [];\n    while (node.contents.length < newCapacity) node.contents.push(0);\n},resizeFileStorage:function (node, newSize) {\n    if (node.usedBytes == newSize) return;\n    if (newSize == 0) {\n        node.contents = null; // Fully decommit when requesting a resize to zero.\n        node.usedBytes = 0;\n        return;\n    }\n    if (!node.contents || node.contents.subarray) { // Resize a typed array if that is being used as the backing store.\n        var oldContents = node.contents;\n        node.contents = new Uint8Array(new ArrayBuffer(newSize)); // Allocate new storage.\n        if (oldContents) {\n            node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); // Copy old data over to the new storage.\n        }\n        node.usedBytes = newSize;\n        return;\n    }\n    // Backing with a JS array.\n    if (!node.contents) node.contents = [];\n    if (node.contents.length > newSize) node.contents.length = newSize;\n    else while (node.contents.length < newSize) node.contents.push(0);\n    node.usedBytes = newSize;\n},node_ops:{getattr:function (node) {\n    var attr = {};\n    // device numbers reuse inode numbers.\n    attr.dev = FS.isChrdev(node.mode) ? node.id : 1;\n    attr.ino = node.id;\n    attr.mode = node.mode;\n    attr.nlink = 1;\n    attr.uid = 0;\n    attr.gid = 0;\n    attr.rdev = node.rdev;\n    if (FS.isDir(node.mode)) {\n        attr.size = 4096;\n    } else if (FS.isFile(node.mode)) {\n        attr.size = node.usedBytes;\n    } else if (FS.isLink(node.mode)) {\n        attr.size = node.link.length;\n    } else {\n        attr.size = 0;\n    }\n    attr.atime = new Date(node.timestamp);\n    attr.mtime = new Date(node.timestamp);\n    attr.ctime = new Date(node.timestamp);\n    // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),\n    //       but this is not required by the standard.\n    attr.blksize = 4096;\n    attr.blocks = Math.ceil(attr.size / attr.blksize);\n    return attr;\n},setattr:function (node, attr) {\n    if (attr.mode !== undefined) {\n        node.mode = attr.mode;\n    }\n    if (attr.timestamp !== undefined) {\n        node.timestamp = attr.timestamp;\n    }\n    if (attr.size !== undefined) {\n        MEMFS.resizeFileStorage(node, attr.size);\n    }\n},lookup:function (parent, name) {\n    throw FS.genericErrors[ERRNO_CODES.ENOENT];\n},mknod:function (parent, name, mode, dev) {\n    return MEMFS.createNode(parent, name, mode, dev);\n},rename:function (old_node, new_dir, new_name) {\n    // if we\'re overwriting a directory at new_name, make sure it\'s empty.\n    if (FS.isDir(old_node.mode)) {\n        var new_node;\n        try {\n            new_node = FS.lookupNode(new_dir, new_name);\n        } catch (e) {\n        }\n        if (new_node) {\n            for (var i in new_node.contents) {\n                throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);\n            }\n        }\n    }\n    // do the internal rewiring\n    delete old_node.parent.contents[old_node.name];\n    old_node.name = new_name;\n    new_dir.contents[new_name] = old_node;\n    old_node.parent = new_dir;\n},unlink:function (parent, name) {\n    delete parent.contents[name];\n},rmdir:function (parent, name) {\n    var node = FS.lookupNode(parent, name);\n    for (var i in node.contents) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);\n    }\n    delete parent.contents[name];\n},readdir:function (node) {\n    var entries = [\'.\', \'..\']\n    for (var key in node.contents) {\n        if (!node.contents.hasOwnProperty(key)) {\n            continue;\n        }\n        entries.push(key);\n    }\n    return entries;\n},symlink:function (parent, newname, oldpath) {\n    var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);\n    node.link = oldpath;\n    return node;\n},readlink:function (node) {\n    if (!FS.isLink(node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    return node.link;\n}},stream_ops:{read:function (stream, buffer, offset, length, position) {\n    var contents = stream.node.contents;\n    if (position >= stream.node.usedBytes) return 0;\n    var size = Math.min(stream.node.usedBytes - position, length);\n    assert(size >= 0);\n    if (size > 8 && contents.subarray) { // non-trivial, and typed array\n        buffer.set(contents.subarray(position, position + size), offset);\n    } else {\n        for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];\n    }\n    return size;\n},write:function (stream, buffer, offset, length, position, canOwn) {\n    if (!length) return 0;\n    var node = stream.node;\n    node.timestamp = Date.now();\n\n    if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array?\n        if (canOwn) {\n            node.contents = buffer.subarray(offset, offset + length);\n            node.usedBytes = length;\n            return length;\n        } else if (node.usedBytes === 0 && position === 0) { // If this is a simple first write to an empty file, do a fast set since we don\'t need to care about old data.\n            node.contents = new Uint8Array(buffer.subarray(offset, offset + length));\n            node.usedBytes = length;\n            return length;\n        } else if (position + length <= node.usedBytes) { // Writing to an already allocated and used subrange of the file?\n            node.contents.set(buffer.subarray(offset, offset + length), position);\n            return length;\n        }\n    }\n\n    // Appending to an existing file and we need to reallocate, or source data did not come as a typed array.\n    MEMFS.expandFileStorage(node, position+length);\n    if (node.contents.subarray && buffer.subarray) node.contents.set(buffer.subarray(offset, offset + length), position); // Use typed array write if available.\n    else {\n        for (var i = 0; i < length; i++) {\n            node.contents[position + i] = buffer[offset + i]; // Or fall back to manual write if not.\n        }\n    }\n    node.usedBytes = Math.max(node.usedBytes, position+length);\n    return length;\n},llseek:function (stream, offset, whence) {\n    var position = offset;\n    if (whence === 1) {  // SEEK_CUR.\n        position += stream.position;\n    } else if (whence === 2) {  // SEEK_END.\n        if (FS.isFile(stream.node.mode)) {\n            position += stream.node.usedBytes;\n        }\n    }\n    if (position < 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    return position;\n},allocate:function (stream, offset, length) {\n    MEMFS.expandFileStorage(stream.node, offset + length);\n    stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length);\n},mmap:function (stream, buffer, offset, length, position, prot, flags) {\n    if (!FS.isFile(stream.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENODEV);\n    }\n    var ptr;\n    var allocated;\n    var contents = stream.node.contents;\n    // Only make a new copy when MAP_PRIVATE is specified.\n    if ( !(flags & 2) &&\n        (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {\n        // We can\'t emulate MAP_SHARED when the file is not backed by the buffer\n        // we\'re mapping to (e.g. the HEAP buffer).\n        allocated = false;\n        ptr = contents.byteOffset;\n    } else {\n        // Try to avoid unnecessary slices.\n        if (position > 0 || position + length < stream.node.usedBytes) {\n            if (contents.subarray) {\n                contents = contents.subarray(position, position + length);\n            } else {\n                contents = Array.prototype.slice.call(contents, position, position + length);\n            }\n        }\n        allocated = true;\n        ptr = _malloc(length);\n        if (!ptr) {\n            throw new FS.ErrnoError(ERRNO_CODES.ENOMEM);\n        }\n        buffer.set(contents, ptr);\n    }\n    return { ptr: ptr, allocated: allocated };\n},msync:function (stream, buffer, offset, length, mmapFlags) {\n    if (!FS.isFile(stream.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENODEV);\n    }\n    if (mmapFlags & 2) {\n        // MAP_PRIVATE calls need not to be synced back to underlying fs\n        return 0;\n    }\n\n    var bytesWritten = MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false);\n    // should we check if bytesWritten and length are the same?\n    return 0;\n}}};\n\nvar IDBFS={dbs:{},indexedDB:function () {\n    if (typeof indexedDB !== \'undefined\') return indexedDB;\n    var ret = null;\n    if (typeof window === \'object\') ret = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;\n    assert(ret, \'IDBFS used, but indexedDB not supported\');\n    return ret;\n},DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {\n    // reuse all of the core MEMFS functionality\n    return MEMFS.mount.apply(null, arguments);\n},syncfs:function (mount, populate, callback) {\n    IDBFS.getLocalSet(mount, function(err, local) {\n        if (err) return callback(err);\n\n        IDBFS.getRemoteSet(mount, function(err, remote) {\n            if (err) return callback(err);\n\n            var src = populate ? remote : local;\n            var dst = populate ? local : remote;\n\n            IDBFS.reconcile(src, dst, callback);\n        });\n    });\n},getDB:function (name, callback) {\n    // check the cache first\n    var db = IDBFS.dbs[name];\n    if (db) {\n        return callback(null, db);\n    }\n\n    var req;\n    try {\n        req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);\n    } catch (e) {\n        return callback(e);\n    }\n    if (!req) {\n        return callback("Unable to connect to IndexedDB");\n    }\n    req.onupgradeneeded = function(e) {\n        var db = e.target.result;\n        var transaction = e.target.transaction;\n\n        var fileStore;\n\n        if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {\n            fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);\n        } else {\n            fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);\n        }\n\n        if (!fileStore.indexNames.contains(\'timestamp\')) {\n            fileStore.createIndex(\'timestamp\', \'timestamp\', { unique: false });\n        }\n    };\n    req.onsuccess = function() {\n        db = req.result;\n\n        // add to the cache\n        IDBFS.dbs[name] = db;\n        callback(null, db);\n    };\n    req.onerror = function(e) {\n        callback(this.error);\n        e.preventDefault();\n    };\n},getLocalSet:function (mount, callback) {\n    var entries = {};\n\n    function isRealDir(p) {\n        return p !== \'.\' && p !== \'..\';\n    };\n    function toAbsolute(root) {\n        return function(p) {\n            return PATH.join2(root, p);\n        }\n    };\n\n    var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));\n\n    while (check.length) {\n        var path = check.pop();\n        var stat;\n\n        try {\n            stat = FS.stat(path);\n        } catch (e) {\n            return callback(e);\n        }\n\n        if (FS.isDir(stat.mode)) {\n            check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));\n        }\n\n        entries[path] = { timestamp: stat.mtime };\n    }\n\n    return callback(null, { type: \'local\', entries: entries });\n},getRemoteSet:function (mount, callback) {\n    var entries = {};\n\n    IDBFS.getDB(mount.mountpoint, function(err, db) {\n        if (err) return callback(err);\n\n        var transaction = db.transaction([IDBFS.DB_STORE_NAME], \'readonly\');\n        transaction.onerror = function(e) {\n            callback(this.error);\n            e.preventDefault();\n        };\n\n        var store = transaction.objectStore(IDBFS.DB_STORE_NAME);\n        var index = store.index(\'timestamp\');\n\n        index.openKeyCursor().onsuccess = function(event) {\n            var cursor = event.target.result;\n\n            if (!cursor) {\n                return callback(null, { type: \'remote\', db: db, entries: entries });\n            }\n\n            entries[cursor.primaryKey] = { timestamp: cursor.key };\n\n            cursor.continue();\n        };\n    });\n},loadLocalEntry:function (path, callback) {\n    var stat, node;\n\n    try {\n        var lookup = FS.lookupPath(path);\n        node = lookup.node;\n        stat = FS.stat(path);\n    } catch (e) {\n        return callback(e);\n    }\n\n    if (FS.isDir(stat.mode)) {\n        return callback(null, { timestamp: stat.mtime, mode: stat.mode });\n    } else if (FS.isFile(stat.mode)) {\n        // Performance consideration: storing a normal JavaScript array to a IndexedDB is much slower than storing a typed array.\n        // Therefore always convert the file contents to a typed array first before writing the data to IndexedDB.\n        node.contents = MEMFS.getFileDataAsTypedArray(node);\n        return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });\n    } else {\n        return callback(new Error(\'node type not supported\'));\n    }\n},storeLocalEntry:function (path, entry, callback) {\n    try {\n        if (FS.isDir(entry.mode)) {\n            FS.mkdir(path, entry.mode);\n        } else if (FS.isFile(entry.mode)) {\n            FS.writeFile(path, entry.contents, { encoding: \'binary\', canOwn: true });\n        } else {\n            return callback(new Error(\'node type not supported\'));\n        }\n\n        FS.chmod(path, entry.mode);\n        FS.utime(path, entry.timestamp, entry.timestamp);\n    } catch (e) {\n        return callback(e);\n    }\n\n    callback(null);\n},removeLocalEntry:function (path, callback) {\n    try {\n        var lookup = FS.lookupPath(path);\n        var stat = FS.stat(path);\n\n        if (FS.isDir(stat.mode)) {\n            FS.rmdir(path);\n        } else if (FS.isFile(stat.mode)) {\n            FS.unlink(path);\n        }\n    } catch (e) {\n        return callback(e);\n    }\n\n    callback(null);\n},loadRemoteEntry:function (store, path, callback) {\n    var req = store.get(path);\n    req.onsuccess = function(event) { callback(null, event.target.result); };\n    req.onerror = function(e) {\n        callback(this.error);\n        e.preventDefault();\n    };\n},storeRemoteEntry:function (store, path, entry, callback) {\n    var req = store.put(entry, path);\n    req.onsuccess = function() { callback(null); };\n    req.onerror = function(e) {\n        callback(this.error);\n        e.preventDefault();\n    };\n},removeRemoteEntry:function (store, path, callback) {\n    var req = store.delete(path);\n    req.onsuccess = function() { callback(null); };\n    req.onerror = function(e) {\n        callback(this.error);\n        e.preventDefault();\n    };\n},reconcile:function (src, dst, callback) {\n    var total = 0;\n\n    var create = [];\n    Object.keys(src.entries).forEach(function (key) {\n        var e = src.entries[key];\n        var e2 = dst.entries[key];\n        if (!e2 || e.timestamp > e2.timestamp) {\n            create.push(key);\n            total++;\n        }\n    });\n\n    var remove = [];\n    Object.keys(dst.entries).forEach(function (key) {\n        var e = dst.entries[key];\n        var e2 = src.entries[key];\n        if (!e2) {\n            remove.push(key);\n            total++;\n        }\n    });\n\n    if (!total) {\n        return callback(null);\n    }\n\n    var errored = false;\n    var completed = 0;\n    var db = src.type === \'remote\' ? src.db : dst.db;\n    var transaction = db.transaction([IDBFS.DB_STORE_NAME], \'readwrite\');\n    var store = transaction.objectStore(IDBFS.DB_STORE_NAME);\n\n    function done(err) {\n        if (err) {\n            if (!done.errored) {\n                done.errored = true;\n                return callback(err);\n            }\n            return;\n        }\n        if (++completed >= total) {\n            return callback(null);\n        }\n    };\n\n    transaction.onerror = function(e) {\n        done(this.error);\n        e.preventDefault();\n    };\n\n    // sort paths in ascending order so directory entries are created\n    // before the files inside them\n    create.sort().forEach(function (path) {\n        if (dst.type === \'local\') {\n            IDBFS.loadRemoteEntry(store, path, function (err, entry) {\n                if (err) return done(err);\n                IDBFS.storeLocalEntry(path, entry, done);\n            });\n        } else {\n            IDBFS.loadLocalEntry(path, function (err, entry) {\n                if (err) return done(err);\n                IDBFS.storeRemoteEntry(store, path, entry, done);\n            });\n        }\n    });\n\n    // sort paths in descending order so files are deleted before their\n    // parent directories\n    remove.sort().reverse().forEach(function(path) {\n        if (dst.type === \'local\') {\n            IDBFS.removeLocalEntry(path, done);\n        } else {\n            IDBFS.removeRemoteEntry(store, path, done);\n        }\n    });\n}};\n\nvar NODEFS={isWindows:false,staticInit:function () {\n    NODEFS.isWindows = !!process.platform.match(/^win/);\n},mount:function (mount) {\n    assert(ENVIRONMENT_IS_NODE);\n    return NODEFS.createNode(null, \'/\', NODEFS.getMode(mount.opts.root), 0);\n},createNode:function (parent, name, mode, dev) {\n    if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    var node = FS.createNode(parent, name, mode);\n    node.node_ops = NODEFS.node_ops;\n    node.stream_ops = NODEFS.stream_ops;\n    return node;\n},getMode:function (path) {\n    var stat;\n    try {\n        stat = fs.lstatSync(path);\n        if (NODEFS.isWindows) {\n            // On Windows, directories return permission bits \'rw-rw-rw-\', even though they have \'rwxrwxrwx\', so\n            // propagate write bits to execute bits.\n            stat.mode = stat.mode | ((stat.mode & 146) >> 1);\n        }\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n    return stat.mode;\n},realPath:function (node) {\n    var parts = [];\n    while (node.parent !== node) {\n        parts.push(node.name);\n        node = node.parent;\n    }\n    parts.push(node.mount.opts.root);\n    parts.reverse();\n    return PATH.join.apply(null, parts);\n},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+"},flagsToPermissionString:function (flags) {\n    flags &= ~0x200000 /*O_PATH*/; // Ignore this flag from musl, otherwise node.js fails to open the file.\n    flags &= ~0x800 /*O_NONBLOCK*/; // Ignore this flag from musl, otherwise node.js fails to open the file.\n    flags &= ~0x8000 /*O_LARGEFILE*/; // Ignore this flag from musl, otherwise node.js fails to open the file.\n    flags &= ~0x80000 /*O_CLOEXEC*/; // Some applications may pass it; it makes no sense for a single process.\n    if (flags in NODEFS.flagsToPermissionStringMap) {\n        return NODEFS.flagsToPermissionStringMap[flags];\n    } else {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n},node_ops:{getattr:function (node) {\n    var path = NODEFS.realPath(node);\n    var stat;\n    try {\n        stat = fs.lstatSync(path);\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n    // node.js v0.10.20 doesn\'t report blksize and blocks on Windows. Fake them with default blksize of 4096.\n    // See http://support.microsoft.com/kb/140365\n    if (NODEFS.isWindows && !stat.blksize) {\n        stat.blksize = 4096;\n    }\n    if (NODEFS.isWindows && !stat.blocks) {\n        stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;\n    }\n    return {\n        dev: stat.dev,\n        ino: stat.ino,\n        mode: stat.mode,\n        nlink: stat.nlink,\n        uid: stat.uid,\n        gid: stat.gid,\n        rdev: stat.rdev,\n        size: stat.size,\n        atime: stat.atime,\n        mtime: stat.mtime,\n        ctime: stat.ctime,\n        blksize: stat.blksize,\n        blocks: stat.blocks\n    };\n},setattr:function (node, attr) {\n    var path = NODEFS.realPath(node);\n    try {\n        if (attr.mode !== undefined) {\n            fs.chmodSync(path, attr.mode);\n            // update the common node structure mode as well\n            node.mode = attr.mode;\n        }\n        if (attr.timestamp !== undefined) {\n            var date = new Date(attr.timestamp);\n            fs.utimesSync(path, date, date);\n        }\n        if (attr.size !== undefined) {\n            fs.truncateSync(path, attr.size);\n        }\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n},lookup:function (parent, name) {\n    var path = PATH.join2(NODEFS.realPath(parent), name);\n    var mode = NODEFS.getMode(path);\n    return NODEFS.createNode(parent, name, mode);\n},mknod:function (parent, name, mode, dev) {\n    var node = NODEFS.createNode(parent, name, mode, dev);\n    // create the backing node for this in the fs root as well\n    var path = NODEFS.realPath(node);\n    try {\n        if (FS.isDir(node.mode)) {\n            fs.mkdirSync(path, node.mode);\n        } else {\n            fs.writeFileSync(path, \'\', { mode: node.mode });\n        }\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n    return node;\n},rename:function (oldNode, newDir, newName) {\n    var oldPath = NODEFS.realPath(oldNode);\n    var newPath = PATH.join2(NODEFS.realPath(newDir), newName);\n    try {\n        fs.renameSync(oldPath, newPath);\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n},unlink:function (parent, name) {\n    var path = PATH.join2(NODEFS.realPath(parent), name);\n    try {\n        fs.unlinkSync(path);\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n},rmdir:function (parent, name) {\n    var path = PATH.join2(NODEFS.realPath(parent), name);\n    try {\n        fs.rmdirSync(path);\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n},readdir:function (node) {\n    var path = NODEFS.realPath(node);\n    try {\n        return fs.readdirSync(path);\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n},symlink:function (parent, newName, oldPath) {\n    var newPath = PATH.join2(NODEFS.realPath(parent), newName);\n    try {\n        fs.symlinkSync(oldPath, newPath);\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n},readlink:function (node) {\n    var path = NODEFS.realPath(node);\n    try {\n        path = fs.readlinkSync(path);\n        path = NODEJS_PATH.relative(NODEJS_PATH.resolve(node.mount.opts.root), path);\n        return path;\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n}},stream_ops:{open:function (stream) {\n    var path = NODEFS.realPath(stream.node);\n    try {\n        if (FS.isFile(stream.node.mode)) {\n            stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags));\n        }\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n},close:function (stream) {\n    try {\n        if (FS.isFile(stream.node.mode) && stream.nfd) {\n            fs.closeSync(stream.nfd);\n        }\n    } catch (e) {\n        if (!e.code) throw e;\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n},read:function (stream, buffer, offset, length, position) {\n    if (length === 0) return 0; // node errors on 0 length reads\n    // FIXME this is terrible.\n    var nbuffer = new Buffer(length);\n    var res;\n    try {\n        res = fs.readSync(stream.nfd, nbuffer, 0, length, position);\n    } catch (e) {\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n    if (res > 0) {\n        for (var i = 0; i < res; i++) {\n            buffer[offset + i] = nbuffer[i];\n        }\n    }\n    return res;\n},write:function (stream, buffer, offset, length, position) {\n    // FIXME this is terrible.\n    var nbuffer = new Buffer(buffer.subarray(offset, offset + length));\n    var res;\n    try {\n        res = fs.writeSync(stream.nfd, nbuffer, 0, length, position);\n    } catch (e) {\n        throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n    }\n    return res;\n},llseek:function (stream, offset, whence) {\n    var position = offset;\n    if (whence === 1) {  // SEEK_CUR.\n        position += stream.position;\n    } else if (whence === 2) {  // SEEK_END.\n        if (FS.isFile(stream.node.mode)) {\n            try {\n                var stat = fs.fstatSync(stream.nfd);\n                position += stat.size;\n            } catch (e) {\n                throw new FS.ErrnoError(ERRNO_CODES[e.code]);\n            }\n        }\n    }\n\n    if (position < 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n\n    return position;\n}}};\n\nvar WORKERFS={DIR_MODE:16895,FILE_MODE:33279,reader:null,mount:function (mount) {\n    assert(ENVIRONMENT_IS_WORKER);\n    if (!WORKERFS.reader) WORKERFS.reader = new FileReaderSync();\n    var root = WORKERFS.createNode(null, \'/\', WORKERFS.DIR_MODE, 0);\n    var createdParents = {};\n    function ensureParent(path) {\n        // return the parent node, creating subdirs as necessary\n        var parts = path.split(\'/\');\n        var parent = root;\n        for (var i = 0; i < parts.length-1; i++) {\n            var curr = parts.slice(0, i+1).join(\'/\');\n            // Issue 4254: Using curr as a node name will prevent the node\n            // from being found in FS.nameTable when FS.open is called on\n            // a path which holds a child of this node,\n            // given that all FS functions assume node names\n            // are just their corresponding parts within their given path,\n            // rather than incremental aggregates which include their parent\'s\n            // directories.\n            if (!createdParents[curr]) {\n                createdParents[curr] = WORKERFS.createNode(parent, parts[i], WORKERFS.DIR_MODE, 0);\n            }\n            parent = createdParents[curr];\n        }\n        return parent;\n    }\n    function base(path) {\n        var parts = path.split(\'/\');\n        return parts[parts.length-1];\n    }\n    // We also accept FileList here, by using Array.prototype\n    Array.prototype.forEach.call(mount.opts["files"] || [], function(file) {\n        WORKERFS.createNode(ensureParent(file.name), base(file.name), WORKERFS.FILE_MODE, 0, file, file.lastModifiedDate);\n    });\n    (mount.opts["blobs"] || []).forEach(function(obj) {\n        WORKERFS.createNode(ensureParent(obj["name"]), base(obj["name"]), WORKERFS.FILE_MODE, 0, obj["data"]);\n    });\n    (mount.opts["packages"] || []).forEach(function(pack) {\n        pack[\'metadata\'].files.forEach(function(file) {\n            var name = file.filename.substr(1); // remove initial slash\n            WORKERFS.createNode(ensureParent(name), base(name), WORKERFS.FILE_MODE, 0, pack[\'blob\'].slice(file.run, file.end));\n        });\n    });\n    return root;\n},createNode:function (parent, name, mode, dev, contents, mtime) {\n    var node = FS.createNode(parent, name, mode);\n    node.mode = mode;\n    node.node_ops = WORKERFS.node_ops;\n    node.stream_ops = WORKERFS.stream_ops;\n    node.timestamp = (mtime || new Date).getTime();\n    assert(WORKERFS.FILE_MODE !== WORKERFS.DIR_MODE);\n    if (mode === WORKERFS.FILE_MODE) {\n        node.size = contents.size;\n        node.contents = contents;\n    } else {\n        node.size = 4096;\n        node.contents = {};\n    }\n    if (parent) {\n        parent.contents[name] = node;\n    }\n    return node;\n},node_ops:{getattr:function (node) {\n    return {\n        dev: 1,\n        ino: undefined,\n        mode: node.mode,\n        nlink: 1,\n        uid: 0,\n        gid: 0,\n        rdev: undefined,\n        size: node.size,\n        atime: new Date(node.timestamp),\n        mtime: new Date(node.timestamp),\n        ctime: new Date(node.timestamp),\n        blksize: 4096,\n        blocks: Math.ceil(node.size / 4096),\n    };\n},setattr:function (node, attr) {\n    if (attr.mode !== undefined) {\n        node.mode = attr.mode;\n    }\n    if (attr.timestamp !== undefined) {\n        node.timestamp = attr.timestamp;\n    }\n},lookup:function (parent, name) {\n    throw new FS.ErrnoError(ERRNO_CODES.ENOENT);\n},mknod:function (parent, name, mode, dev) {\n    throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n},rename:function (oldNode, newDir, newName) {\n    throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n},unlink:function (parent, name) {\n    throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n},rmdir:function (parent, name) {\n    throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n},readdir:function (node) {\n    var entries = [\'.\', \'..\'];\n    for (var key in node.contents) {\n        if (!node.contents.hasOwnProperty(key)) {\n            continue;\n        }\n        entries.push(key);\n    }\n    return entries;\n},symlink:function (parent, newName, oldPath) {\n    throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n},readlink:function (node) {\n    throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n}},stream_ops:{read:function (stream, buffer, offset, length, position) {\n    if (position >= stream.node.size) return 0;\n    var chunk = stream.node.contents.slice(position, position + length);\n    var ab = WORKERFS.reader.readAsArrayBuffer(chunk);\n    buffer.set(new Uint8Array(ab), offset);\n    return chunk.size;\n},write:function (stream, buffer, offset, length, position) {\n    throw new FS.ErrnoError(ERRNO_CODES.EIO);\n},llseek:function (stream, offset, whence) {\n    var position = offset;\n    if (whence === 1) {  // SEEK_CUR.\n        position += stream.position;\n    } else if (whence === 2) {  // SEEK_END.\n        if (FS.isFile(stream.node.mode)) {\n            position += stream.node.size;\n        }\n    }\n    if (position < 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    return position;\n}}};\n\nvar _stdin=STATICTOP; STATICTOP += 16;;\n\nvar _stdout=STATICTOP; STATICTOP += 16;;\n\nvar _stderr=STATICTOP; STATICTOP += 16;;var FS={root:null,mounts:[],devices:[null],streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,trackingDelegate:{},tracking:{openFlags:{READ:1,WRITE:2}},ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,handleFSError:function (e) {\n    if (!(e instanceof FS.ErrnoError)) throw e + \' : \' + stackTrace();\n    return ___setErrNo(e.errno);\n},lookupPath:function (path, opts) {\n    path = PATH.resolve(FS.cwd(), path);\n    opts = opts || {};\n\n    if (!path) return { path: \'\', node: null };\n\n    var defaults = {\n        follow_mount: true,\n        recurse_count: 0\n    };\n    for (var key in defaults) {\n        if (opts[key] === undefined) {\n            opts[key] = defaults[key];\n        }\n    }\n\n    if (opts.recurse_count > 8) {  // max recursive lookup of 8\n        throw new FS.ErrnoError(ERRNO_CODES.ELOOP);\n    }\n\n    // split the path\n    var parts = PATH.normalizeArray(path.split(\'/\').filter(function(p) {\n        return !!p;\n    }), false);\n\n    // start at the root\n    var current = FS.root;\n    var current_path = \'/\';\n\n    for (var i = 0; i < parts.length; i++) {\n        var islast = (i === parts.length-1);\n        if (islast && opts.parent) {\n            // stop resolving\n            break;\n        }\n\n        current = FS.lookupNode(current, parts[i]);\n        current_path = PATH.join2(current_path, parts[i]);\n\n        // jump to the mount\'s root node if this is a mountpoint\n        if (FS.isMountpoint(current)) {\n            if (!islast || (islast && opts.follow_mount)) {\n                current = current.mounted.root;\n            }\n        }\n\n        // by default, lookupPath will not follow a symlink if it is the final path component.\n        // setting opts.follow = true will override this behavior.\n        if (!islast || opts.follow) {\n            var count = 0;\n            while (FS.isLink(current.mode)) {\n                var link = FS.readlink(current_path);\n                current_path = PATH.resolve(PATH.dirname(current_path), link);\n\n                var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });\n                current = lookup.node;\n\n                if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).\n                    throw new FS.ErrnoError(ERRNO_CODES.ELOOP);\n                }\n            }\n        }\n    }\n\n    return { path: current_path, node: current };\n},getPath:function (node) {\n    var path;\n    while (true) {\n        if (FS.isRoot(node)) {\n            var mount = node.mount.mountpoint;\n            if (!path) return mount;\n            return mount[mount.length-1] !== \'/\' ? mount + \'/\' + path : mount + path;\n        }\n        path = path ? node.name + \'/\' + path : node.name;\n        node = node.parent;\n    }\n},hashName:function (parentid, name) {\n    var hash = 0;\n\n\n    for (var i = 0; i < name.length; i++) {\n        hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;\n    }\n    return ((parentid + hash) >>> 0) % FS.nameTable.length;\n},hashAddNode:function (node) {\n    var hash = FS.hashName(node.parent.id, node.name);\n    node.name_next = FS.nameTable[hash];\n    FS.nameTable[hash] = node;\n},hashRemoveNode:function (node) {\n    var hash = FS.hashName(node.parent.id, node.name);\n    if (FS.nameTable[hash] === node) {\n        FS.nameTable[hash] = node.name_next;\n    } else {\n        var current = FS.nameTable[hash];\n        while (current) {\n            if (current.name_next === node) {\n                current.name_next = node.name_next;\n                break;\n            }\n            current = current.name_next;\n        }\n    }\n},lookupNode:function (parent, name) {\n    var err = FS.mayLookup(parent);\n    if (err) {\n        throw new FS.ErrnoError(err, parent);\n    }\n    var hash = FS.hashName(parent.id, name);\n    for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n        var nodeName = node.name;\n        if (node.parent.id === parent.id && nodeName === name) {\n            return node;\n        }\n    }\n    // if we failed to find it in the cache, call into the VFS\n    return FS.lookup(parent, name);\n},createNode:function (parent, name, mode, rdev) {\n    if (!FS.FSNode) {\n        FS.FSNode = function(parent, name, mode, rdev) {\n            if (!parent) {\n                parent = this;  // root node sets parent to itself\n            }\n            this.parent = parent;\n            this.mount = parent.mount;\n            this.mounted = null;\n            this.id = FS.nextInode++;\n            this.name = name;\n            this.mode = mode;\n            this.node_ops = {};\n            this.stream_ops = {};\n            this.rdev = rdev;\n        };\n\n        FS.FSNode.prototype = {};\n\n        // compatibility\n        var readMode = 292 | 73;\n        var writeMode = 146;\n\n        // NOTE we must use Object.defineProperties instead of individual calls to\n        // Object.defineProperty in order to make closure compiler happy\n        Object.defineProperties(FS.FSNode.prototype, {\n            read: {\n                get: function() { return (this.mode & readMode) === readMode; },\n                set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }\n            },\n            write: {\n                get: function() { return (this.mode & writeMode) === writeMode; },\n                set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }\n            },\n            isFolder: {\n                get: function() { return FS.isDir(this.mode); }\n            },\n            isDevice: {\n                get: function() { return FS.isChrdev(this.mode); }\n            }\n        });\n    }\n\n    var node = new FS.FSNode(parent, name, mode, rdev);\n\n    FS.hashAddNode(node);\n\n    return node;\n},destroyNode:function (node) {\n    FS.hashRemoveNode(node);\n},isRoot:function (node) {\n    return node === node.parent;\n},isMountpoint:function (node) {\n    return !!node.mounted;\n},isFile:function (mode) {\n    return (mode & 61440) === 32768;\n},isDir:function (mode) {\n    return (mode & 61440) === 16384;\n},isLink:function (mode) {\n    return (mode & 61440) === 40960;\n},isChrdev:function (mode) {\n    return (mode & 61440) === 8192;\n},isBlkdev:function (mode) {\n    return (mode & 61440) === 24576;\n},isFIFO:function (mode) {\n    return (mode & 61440) === 4096;\n},isSocket:function (mode) {\n    return (mode & 49152) === 49152;\n},flagModes:{"r":0,"rs":1052672,"r+":2,"w":577,"wx":705,"xw":705,"w+":578,"wx+":706,"xw+":706,"a":1089,"ax":1217,"xa":1217,"a+":1090,"ax+":1218,"xa+":1218},modeStringToFlags:function (str) {\n    var flags = FS.flagModes[str];\n    if (typeof flags === \'undefined\') {\n        throw new Error(\'Unknown file open mode: \' + str);\n    }\n    return flags;\n},flagsToPermissionString:function (flag) {\n    var perms = [\'r\', \'w\', \'rw\'][flag & 3];\n    if ((flag & 512)) {\n        perms += \'w\';\n    }\n    return perms;\n},nodePermissions:function (node, perms) {\n    if (FS.ignorePermissions) {\n        return 0;\n    }\n    // return 0 if any user, group or owner bits are set.\n    if (perms.indexOf(\'r\') !== -1 && !(node.mode & 292)) {\n        return ERRNO_CODES.EACCES;\n    } else if (perms.indexOf(\'w\') !== -1 && !(node.mode & 146)) {\n        return ERRNO_CODES.EACCES;\n    } else if (perms.indexOf(\'x\') !== -1 && !(node.mode & 73)) {\n        return ERRNO_CODES.EACCES;\n    }\n    return 0;\n},mayLookup:function (dir) {\n    var err = FS.nodePermissions(dir, \'x\');\n    if (err) return err;\n    if (!dir.node_ops.lookup) return ERRNO_CODES.EACCES;\n    return 0;\n},mayCreate:function (dir, name) {\n    try {\n        var node = FS.lookupNode(dir, name);\n        return ERRNO_CODES.EEXIST;\n    } catch (e) {\n    }\n    return FS.nodePermissions(dir, \'wx\');\n},mayDelete:function (dir, name, isdir) {\n    var node;\n    try {\n        node = FS.lookupNode(dir, name);\n    } catch (e) {\n        return e.errno;\n    }\n    var err = FS.nodePermissions(dir, \'wx\');\n    if (err) {\n        return err;\n    }\n    if (isdir) {\n        if (!FS.isDir(node.mode)) {\n            return ERRNO_CODES.ENOTDIR;\n        }\n        if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n            return ERRNO_CODES.EBUSY;\n        }\n    } else {\n        if (FS.isDir(node.mode)) {\n            return ERRNO_CODES.EISDIR;\n        }\n    }\n    return 0;\n},mayOpen:function (node, flags) {\n    if (!node) {\n        return ERRNO_CODES.ENOENT;\n    }\n    if (FS.isLink(node.mode)) {\n        return ERRNO_CODES.ELOOP;\n    } else if (FS.isDir(node.mode)) {\n        if (FS.flagsToPermissionString(flags) !== \'r\' || // opening for write\n            (flags & 512)) { // TODO: check for O_SEARCH? (== search for dir only)\n            return ERRNO_CODES.EISDIR;\n        }\n    }\n    return FS.nodePermissions(node, FS.flagsToPermissionString(flags));\n},MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {\n    fd_start = fd_start || 0;\n    fd_end = fd_end || FS.MAX_OPEN_FDS;\n    for (var fd = fd_start; fd <= fd_end; fd++) {\n        if (!FS.streams[fd]) {\n            return fd;\n        }\n    }\n    throw new FS.ErrnoError(ERRNO_CODES.EMFILE);\n},getStream:function (fd) {\n    return FS.streams[fd];\n},createStream:function (stream, fd_start, fd_end) {\n    if (!FS.FSStream) {\n        FS.FSStream = function(){};\n        FS.FSStream.prototype = {};\n        // compatibility\n        Object.defineProperties(FS.FSStream.prototype, {\n            object: {\n                get: function() { return this.node; },\n                set: function(val) { this.node = val; }\n            },\n            isRead: {\n                get: function() { return (this.flags & 2097155) !== 1; }\n            },\n            isWrite: {\n                get: function() { return (this.flags & 2097155) !== 0; }\n            },\n            isAppend: {\n                get: function() { return (this.flags & 1024); }\n            }\n        });\n    }\n    // clone it, so we can return an instance of FSStream\n    var newStream = new FS.FSStream();\n    for (var p in stream) {\n        newStream[p] = stream[p];\n    }\n    stream = newStream;\n    var fd = FS.nextfd(fd_start, fd_end);\n    stream.fd = fd;\n    FS.streams[fd] = stream;\n    return stream;\n},closeStream:function (fd) {\n    FS.streams[fd] = null;\n},chrdev_stream_ops:{open:function (stream) {\n    var device = FS.getDevice(stream.node.rdev);\n    // override node\'s stream ops with the device\'s\n    stream.stream_ops = device.stream_ops;\n    // forward the open call\n    if (stream.stream_ops.open) {\n        stream.stream_ops.open(stream);\n    }\n},llseek:function () {\n    throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);\n}},major:function (dev) {\n    return ((dev) >> 8);\n},minor:function (dev) {\n    return ((dev) & 0xff);\n},makedev:function (ma, mi) {\n    return ((ma) << 8 | (mi));\n},registerDevice:function (dev, ops) {\n    FS.devices[dev] = { stream_ops: ops };\n},getDevice:function (dev) {\n    return FS.devices[dev];\n},getMounts:function (mount) {\n    var mounts = [];\n    var check = [mount];\n\n    while (check.length) {\n        var m = check.pop();\n\n        mounts.push(m);\n\n        check.push.apply(check, m.mounts);\n    }\n\n    return mounts;\n},syncfs:function (populate, callback) {\n    if (typeof(populate) === \'function\') {\n        callback = populate;\n        populate = false;\n    }\n\n    FS.syncFSRequests++;\n\n    if (FS.syncFSRequests > 1) {\n        console.log(\'warning: \' + FS.syncFSRequests + \' FS.syncfs operations in flight at once, probably just doing extra work\');\n    }\n\n    var mounts = FS.getMounts(FS.root.mount);\n    var completed = 0;\n\n    function doCallback(err) {\n        assert(FS.syncFSRequests > 0);\n        FS.syncFSRequests--;\n        return callback(err);\n    }\n\n    function done(err) {\n        if (err) {\n            if (!done.errored) {\n                done.errored = true;\n                return doCallback(err);\n            }\n            return;\n        }\n        if (++completed >= mounts.length) {\n            doCallback(null);\n        }\n    };\n\n    // sync all mounts\n    mounts.forEach(function (mount) {\n        if (!mount.type.syncfs) {\n            return done(null);\n        }\n        mount.type.syncfs(mount, populate, done);\n    });\n},mount:function (type, opts, mountpoint) {\n    var root = mountpoint === \'/\';\n    var pseudo = !mountpoint;\n    var node;\n\n    if (root && FS.root) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY);\n    } else if (!root && !pseudo) {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false });\n\n        mountpoint = lookup.path;  // use the absolute path\n        node = lookup.node;\n\n        if (FS.isMountpoint(node)) {\n            throw new FS.ErrnoError(ERRNO_CODES.EBUSY);\n        }\n\n        if (!FS.isDir(node.mode)) {\n            throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);\n        }\n    }\n\n    var mount = {\n        type: type,\n        opts: opts,\n        mountpoint: mountpoint,\n        mounts: []\n    };\n\n    // create a root node for the fs\n    var mountRoot = type.mount(mount);\n    mountRoot.mount = mount;\n    mount.root = mountRoot;\n\n    if (root) {\n        FS.root = mountRoot;\n    } else if (node) {\n        // set as a mountpoint\n        node.mounted = mount;\n\n        // add the new mount to the current mount\'s children\n        if (node.mount) {\n            node.mount.mounts.push(mount);\n        }\n    }\n\n    return mountRoot;\n},unmount:function (mountpoint) {\n    var lookup = FS.lookupPath(mountpoint, { follow_mount: false });\n\n    if (!FS.isMountpoint(lookup.node)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n\n    // destroy the nodes for this mount, and all its child mounts\n    var node = lookup.node;\n    var mount = node.mounted;\n    var mounts = FS.getMounts(mount);\n\n    Object.keys(FS.nameTable).forEach(function (hash) {\n        var current = FS.nameTable[hash];\n\n        while (current) {\n            var next = current.name_next;\n\n            if (mounts.indexOf(current.mount) !== -1) {\n                FS.destroyNode(current);\n            }\n\n            current = next;\n        }\n    });\n\n    // no longer a mountpoint\n    node.mounted = null;\n\n    // remove this mount from the child mounts\n    var idx = node.mount.mounts.indexOf(mount);\n    assert(idx !== -1);\n    node.mount.mounts.splice(idx, 1);\n},lookup:function (parent, name) {\n    return parent.node_ops.lookup(parent, name);\n},mknod:function (path, mode, dev) {\n    var lookup = FS.lookupPath(path, { parent: true });\n    var parent = lookup.node;\n    var name = PATH.basename(path);\n    if (!name || name === \'.\' || name === \'..\') {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    var err = FS.mayCreate(parent, name);\n    if (err) {\n        throw new FS.ErrnoError(err);\n    }\n    if (!parent.node_ops.mknod) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    return parent.node_ops.mknod(parent, name, mode, dev);\n},create:function (path, mode) {\n    mode = mode !== undefined ? mode : 438 /* 0666 */;\n    mode &= 4095;\n    mode |= 32768;\n    return FS.mknod(path, mode, 0);\n},mkdir:function (path, mode) {\n    mode = mode !== undefined ? mode : 511 /* 0777 */;\n    mode &= 511 | 512;\n    mode |= 16384;\n    return FS.mknod(path, mode, 0);\n},mkdirTree:function (path, mode) {\n    var dirs = path.split(\'/\');\n    var d = \'\';\n    for (var i = 0; i < dirs.length; ++i) {\n        if (!dirs[i]) continue;\n        d += \'/\' + dirs[i];\n        try {\n            FS.mkdir(d, mode);\n        } catch(e) {\n            if (e.errno != ERRNO_CODES.EEXIST) throw e;\n        }\n    }\n},mkdev:function (path, mode, dev) {\n    if (typeof(dev) === \'undefined\') {\n        dev = mode;\n        mode = 438 /* 0666 */;\n    }\n    mode |= 8192;\n    return FS.mknod(path, mode, dev);\n},symlink:function (oldpath, newpath) {\n    if (!PATH.resolve(oldpath)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT);\n    }\n    var lookup = FS.lookupPath(newpath, { parent: true });\n    var parent = lookup.node;\n    if (!parent) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT);\n    }\n    var newname = PATH.basename(newpath);\n    var err = FS.mayCreate(parent, newname);\n    if (err) {\n        throw new FS.ErrnoError(err);\n    }\n    if (!parent.node_ops.symlink) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    return parent.node_ops.symlink(parent, newname, oldpath);\n},rename:function (old_path, new_path) {\n    var old_dirname = PATH.dirname(old_path);\n    var new_dirname = PATH.dirname(new_path);\n    var old_name = PATH.basename(old_path);\n    var new_name = PATH.basename(new_path);\n    // parents must exist\n    var lookup, old_dir, new_dir;\n    try {\n        lookup = FS.lookupPath(old_path, { parent: true });\n        old_dir = lookup.node;\n        lookup = FS.lookupPath(new_path, { parent: true });\n        new_dir = lookup.node;\n    } catch (e) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY);\n    }\n    if (!old_dir || !new_dir) throw new FS.ErrnoError(ERRNO_CODES.ENOENT);\n    // need to be part of the same mount\n    if (old_dir.mount !== new_dir.mount) {\n        throw new FS.ErrnoError(ERRNO_CODES.EXDEV);\n    }\n    // source must exist\n    var old_node = FS.lookupNode(old_dir, old_name);\n    // old path should not be an ancestor of the new path\n    var relative = PATH.relative(old_path, new_dirname);\n    if (relative.charAt(0) !== \'.\') {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    // new path should not be an ancestor of the old path\n    relative = PATH.relative(new_path, old_dirname);\n    if (relative.charAt(0) !== \'.\') {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTEMPTY);\n    }\n    // see if the new path already exists\n    var new_node;\n    try {\n        new_node = FS.lookupNode(new_dir, new_name);\n    } catch (e) {\n        // not fatal\n    }\n    // early out if nothing needs to change\n    if (old_node === new_node) {\n        return;\n    }\n    // we\'ll need to delete the old entry\n    var isdir = FS.isDir(old_node.mode);\n    var err = FS.mayDelete(old_dir, old_name, isdir);\n    if (err) {\n        throw new FS.ErrnoError(err);\n    }\n    // need delete permissions if we\'ll be overwriting.\n    // need create permissions if new doesn\'t already exist.\n    err = new_node ?\n        FS.mayDelete(new_dir, new_name, isdir) :\n        FS.mayCreate(new_dir, new_name);\n    if (err) {\n        throw new FS.ErrnoError(err);\n    }\n    if (!old_dir.node_ops.rename) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY);\n    }\n    // if we are going to change the parent, check write permissions\n    if (new_dir !== old_dir) {\n        err = FS.nodePermissions(old_dir, \'w\');\n        if (err) {\n            throw new FS.ErrnoError(err);\n        }\n    }\n    try {\n        if (FS.trackingDelegate[\'willMovePath\']) {\n            FS.trackingDelegate[\'willMovePath\'](old_path, new_path);\n        }\n    } catch(e) {\n        console.log("FS.trackingDelegate[\'willMovePath\'](\'"+old_path+"\', \'"+new_path+"\') threw an exception: " + e.message);\n    }\n    // remove the node from the lookup hash\n    FS.hashRemoveNode(old_node);\n    // do the underlying fs rename\n    try {\n        old_dir.node_ops.rename(old_node, new_dir, new_name);\n    } catch (e) {\n        throw e;\n    } finally {\n        // add the node back to the hash (in case node_ops.rename\n        // changed its name)\n        FS.hashAddNode(old_node);\n    }\n    try {\n        if (FS.trackingDelegate[\'onMovePath\']) FS.trackingDelegate[\'onMovePath\'](old_path, new_path);\n    } catch(e) {\n        console.log("FS.trackingDelegate[\'onMovePath\'](\'"+old_path+"\', \'"+new_path+"\') threw an exception: " + e.message);\n    }\n},rmdir:function (path) {\n    var lookup = FS.lookupPath(path, { parent: true });\n    var parent = lookup.node;\n    var name = PATH.basename(path);\n    var node = FS.lookupNode(parent, name);\n    var err = FS.mayDelete(parent, name, true);\n    if (err) {\n        throw new FS.ErrnoError(err);\n    }\n    if (!parent.node_ops.rmdir) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    if (FS.isMountpoint(node)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY);\n    }\n    try {\n        if (FS.trackingDelegate[\'willDeletePath\']) {\n            FS.trackingDelegate[\'willDeletePath\'](path);\n        }\n    } catch(e) {\n        console.log("FS.trackingDelegate[\'willDeletePath\'](\'"+path+"\') threw an exception: " + e.message);\n    }\n    parent.node_ops.rmdir(parent, name);\n    FS.destroyNode(node);\n    try {\n        if (FS.trackingDelegate[\'onDeletePath\']) FS.trackingDelegate[\'onDeletePath\'](path);\n    } catch(e) {\n        console.log("FS.trackingDelegate[\'onDeletePath\'](\'"+path+"\') threw an exception: " + e.message);\n    }\n},readdir:function (path) {\n    var lookup = FS.lookupPath(path, { follow: true });\n    var node = lookup.node;\n    if (!node.node_ops.readdir) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);\n    }\n    return node.node_ops.readdir(node);\n},unlink:function (path) {\n    var lookup = FS.lookupPath(path, { parent: true });\n    var parent = lookup.node;\n    var name = PATH.basename(path);\n    var node = FS.lookupNode(parent, name);\n    var err = FS.mayDelete(parent, name, false);\n    if (err) {\n        // According to POSIX, we should map EISDIR to EPERM, but\n        // we instead do what Linux does (and we must, as we use\n        // the musl linux libc).\n        throw new FS.ErrnoError(err);\n    }\n    if (!parent.node_ops.unlink) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    if (FS.isMountpoint(node)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBUSY);\n    }\n    try {\n        if (FS.trackingDelegate[\'willDeletePath\']) {\n            FS.trackingDelegate[\'willDeletePath\'](path);\n        }\n    } catch(e) {\n        console.log("FS.trackingDelegate[\'willDeletePath\'](\'"+path+"\') threw an exception: " + e.message);\n    }\n    parent.node_ops.unlink(parent, name);\n    FS.destroyNode(node);\n    try {\n        if (FS.trackingDelegate[\'onDeletePath\']) FS.trackingDelegate[\'onDeletePath\'](path);\n    } catch(e) {\n        console.log("FS.trackingDelegate[\'onDeletePath\'](\'"+path+"\') threw an exception: " + e.message);\n    }\n},readlink:function (path) {\n    var lookup = FS.lookupPath(path);\n    var link = lookup.node;\n    if (!link) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT);\n    }\n    if (!link.node_ops.readlink) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    return PATH.resolve(FS.getPath(link.parent), link.node_ops.readlink(link));\n},stat:function (path, dontFollow) {\n    var lookup = FS.lookupPath(path, { follow: !dontFollow });\n    var node = lookup.node;\n    if (!node) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT);\n    }\n    if (!node.node_ops.getattr) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    return node.node_ops.getattr(node);\n},lstat:function (path) {\n    return FS.stat(path, true);\n},chmod:function (path, mode, dontFollow) {\n    var node;\n    if (typeof path === \'string\') {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow });\n        node = lookup.node;\n    } else {\n        node = path;\n    }\n    if (!node.node_ops.setattr) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    node.node_ops.setattr(node, {\n        mode: (mode & 4095) | (node.mode & ~4095),\n        timestamp: Date.now()\n    });\n},lchmod:function (path, mode) {\n    FS.chmod(path, mode, true);\n},fchmod:function (fd, mode) {\n    var stream = FS.getStream(fd);\n    if (!stream) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n    }\n    FS.chmod(stream.node, mode);\n},chown:function (path, uid, gid, dontFollow) {\n    var node;\n    if (typeof path === \'string\') {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow });\n        node = lookup.node;\n    } else {\n        node = path;\n    }\n    if (!node.node_ops.setattr) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    node.node_ops.setattr(node, {\n        timestamp: Date.now()\n        // we ignore the uid / gid for now\n    });\n},lchown:function (path, uid, gid) {\n    FS.chown(path, uid, gid, true);\n},fchown:function (fd, uid, gid) {\n    var stream = FS.getStream(fd);\n    if (!stream) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n    }\n    FS.chown(stream.node, uid, gid);\n},truncate:function (path, len) {\n    if (len < 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    var node;\n    if (typeof path === \'string\') {\n        var lookup = FS.lookupPath(path, { follow: true });\n        node = lookup.node;\n    } else {\n        node = path;\n    }\n    if (!node.node_ops.setattr) {\n        throw new FS.ErrnoError(ERRNO_CODES.EPERM);\n    }\n    if (FS.isDir(node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EISDIR);\n    }\n    if (!FS.isFile(node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    var err = FS.nodePermissions(node, \'w\');\n    if (err) {\n        throw new FS.ErrnoError(err);\n    }\n    node.node_ops.setattr(node, {\n        size: len,\n        timestamp: Date.now()\n    });\n},ftruncate:function (fd, len) {\n    var stream = FS.getStream(fd);\n    if (!stream) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n    }\n    if ((stream.flags & 2097155) === 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    FS.truncate(stream.node, len);\n},utime:function (path, atime, mtime) {\n    var lookup = FS.lookupPath(path, { follow: true });\n    var node = lookup.node;\n    node.node_ops.setattr(node, {\n        timestamp: Math.max(atime, mtime)\n    });\n},open:function (path, flags, mode, fd_start, fd_end) {\n    if (path === "") {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT);\n    }\n    flags = typeof flags === \'string\' ? FS.modeStringToFlags(flags) : flags;\n    mode = typeof mode === \'undefined\' ? 438 /* 0666 */ : mode;\n    if ((flags & 64)) {\n        mode = (mode & 4095) | 32768;\n    } else {\n        mode = 0;\n    }\n    var node;\n    if (typeof path === \'object\') {\n        node = path;\n    } else {\n        path = PATH.normalize(path);\n        try {\n            var lookup = FS.lookupPath(path, {\n                follow: !(flags & 131072)\n            });\n            node = lookup.node;\n        } catch (e) {\n            // ignore\n        }\n    }\n    // perhaps we need to create the node\n    var created = false;\n    if ((flags & 64)) {\n        if (node) {\n            // if O_CREAT and O_EXCL are set, error out if the node already exists\n            if ((flags & 128)) {\n                throw new FS.ErrnoError(ERRNO_CODES.EEXIST);\n            }\n        } else {\n            // node doesn\'t exist, try to create it\n            node = FS.mknod(path, mode, 0);\n            created = true;\n        }\n    }\n    if (!node) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT);\n    }\n    // can\'t truncate a device\n    if (FS.isChrdev(node.mode)) {\n        flags &= ~512;\n    }\n    // if asked only for a directory, then this must be one\n    if ((flags & 65536) && !FS.isDir(node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);\n    }\n    // check permissions, if this is not a file we just created now (it is ok to\n    // create and write to a file with read-only permissions; it is read-only\n    // for later use)\n    if (!created) {\n        var err = FS.mayOpen(node, flags);\n        if (err) {\n            throw new FS.ErrnoError(err);\n        }\n    }\n    // do truncation if necessary\n    if ((flags & 512)) {\n        FS.truncate(node, 0);\n    }\n    // we\'ve already handled these, don\'t pass down to the underlying vfs\n    flags &= ~(128 | 512);\n\n    // register the stream with the filesystem\n    var stream = FS.createStream({\n        node: node,\n        path: FS.getPath(node),  // we want the absolute path to the node\n        flags: flags,\n        seekable: true,\n        position: 0,\n        stream_ops: node.stream_ops,\n        // used by the file family libc calls (fopen, fwrite, ferror, etc.)\n        ungotten: [],\n        error: false\n    }, fd_start, fd_end);\n    // call the new stream\'s open function\n    if (stream.stream_ops.open) {\n        stream.stream_ops.open(stream);\n    }\n    if (Module[\'logReadFiles\'] && !(flags & 1)) {\n        if (!FS.readFiles) FS.readFiles = {};\n        if (!(path in FS.readFiles)) {\n            FS.readFiles[path] = 1;\n            Module[\'printErr\'](\'read file: \' + path);\n        }\n    }\n    try {\n        if (FS.trackingDelegate[\'onOpenFile\']) {\n            var trackingFlags = 0;\n            if ((flags & 2097155) !== 1) {\n                trackingFlags |= FS.tracking.openFlags.READ;\n            }\n            if ((flags & 2097155) !== 0) {\n                trackingFlags |= FS.tracking.openFlags.WRITE;\n            }\n            FS.trackingDelegate[\'onOpenFile\'](path, trackingFlags);\n        }\n    } catch(e) {\n        console.log("FS.trackingDelegate[\'onOpenFile\'](\'"+path+"\', flags) threw an exception: " + e.message);\n    }\n    return stream;\n},close:function (stream) {\n    if (stream.getdents) stream.getdents = null; // free readdir state\n    try {\n        if (stream.stream_ops.close) {\n            stream.stream_ops.close(stream);\n        }\n    } catch (e) {\n        throw e;\n    } finally {\n        FS.closeStream(stream.fd);\n    }\n},llseek:function (stream, offset, whence) {\n    if (!stream.seekable || !stream.stream_ops.llseek) {\n        throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);\n    }\n    stream.position = stream.stream_ops.llseek(stream, offset, whence);\n    stream.ungotten = [];\n    return stream.position;\n},read:function (stream, buffer, offset, length, position) {\n    if (length < 0 || position < 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    if ((stream.flags & 2097155) === 1) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n    }\n    if (FS.isDir(stream.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EISDIR);\n    }\n    if (!stream.stream_ops.read) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    var seeking = true;\n    if (typeof position === \'undefined\') {\n        position = stream.position;\n        seeking = false;\n    } else if (!stream.seekable) {\n        throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);\n    }\n    var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);\n    if (!seeking) stream.position += bytesRead;\n    return bytesRead;\n},write:function (stream, buffer, offset, length, position, canOwn) {\n    if (length < 0 || position < 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    if ((stream.flags & 2097155) === 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n    }\n    if (FS.isDir(stream.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.EISDIR);\n    }\n    if (!stream.stream_ops.write) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    if (stream.flags & 1024) {\n        // seek to the end before writing in append mode\n        FS.llseek(stream, 0, 2);\n    }\n    var seeking = true;\n    if (typeof position === \'undefined\') {\n        position = stream.position;\n        seeking = false;\n    } else if (!stream.seekable) {\n        throw new FS.ErrnoError(ERRNO_CODES.ESPIPE);\n    }\n    var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);\n    if (!seeking) stream.position += bytesWritten;\n    try {\n        if (stream.path && FS.trackingDelegate[\'onWriteToFile\']) FS.trackingDelegate[\'onWriteToFile\'](stream.path);\n    } catch(e) {\n        console.log("FS.trackingDelegate[\'onWriteToFile\'](\'"+path+"\') threw an exception: " + e.message);\n    }\n    return bytesWritten;\n},allocate:function (stream, offset, length) {\n    if (offset < 0 || length <= 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EINVAL);\n    }\n    if ((stream.flags & 2097155) === 0) {\n        throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n    }\n    if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENODEV);\n    }\n    if (!stream.stream_ops.allocate) {\n        throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);\n    }\n    stream.stream_ops.allocate(stream, offset, length);\n},mmap:function (stream, buffer, offset, length, position, prot, flags) {\n    // TODO if PROT is PROT_WRITE, make sure we have write access\n    if ((stream.flags & 2097155) === 1) {\n        throw new FS.ErrnoError(ERRNO_CODES.EACCES);\n    }\n    if (!stream.stream_ops.mmap) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENODEV);\n    }\n    return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);\n},msync:function (stream, buffer, offset, length, mmapFlags) {\n    if (!stream || !stream.stream_ops.msync) {\n        return 0;\n    }\n    return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags);\n},munmap:function (stream) {\n    return 0;\n},ioctl:function (stream, cmd, arg) {\n    if (!stream.stream_ops.ioctl) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTTY);\n    }\n    return stream.stream_ops.ioctl(stream, cmd, arg);\n},readFile:function (path, opts) {\n    opts = opts || {};\n    opts.flags = opts.flags || \'r\';\n    opts.encoding = opts.encoding || \'binary\';\n    if (opts.encoding !== \'utf8\' && opts.encoding !== \'binary\') {\n        throw new Error(\'Invalid encoding type "\' + opts.encoding + \'"\');\n    }\n    var ret;\n    var stream = FS.open(path, opts.flags);\n    var stat = FS.stat(path);\n    var length = stat.size;\n    var buf = new Uint8Array(length);\n    FS.read(stream, buf, 0, length, 0);\n    if (opts.encoding === \'utf8\') {\n        ret = UTF8ArrayToString(buf, 0);\n    } else if (opts.encoding === \'binary\') {\n        ret = buf;\n    }\n    FS.close(stream);\n    return ret;\n},writeFile:function (path, data, opts) {\n    opts = opts || {};\n    opts.flags = opts.flags || \'w\';\n    opts.encoding = opts.encoding || \'utf8\';\n    if (opts.encoding !== \'utf8\' && opts.encoding !== \'binary\') {\n        throw new Error(\'Invalid encoding type "\' + opts.encoding + \'"\');\n    }\n    var stream = FS.open(path, opts.flags, opts.mode);\n    if (opts.encoding === \'utf8\') {\n        var buf = new Uint8Array(lengthBytesUTF8(data)+1);\n        var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length);\n        FS.write(stream, buf, 0, actualNumBytes, 0, opts.canOwn);\n    } else if (opts.encoding === \'binary\') {\n        FS.write(stream, data, 0, data.length, 0, opts.canOwn);\n    }\n    FS.close(stream);\n},cwd:function () {\n    return FS.currentPath;\n},chdir:function (path) {\n    var lookup = FS.lookupPath(path, { follow: true });\n    if (lookup.node === null) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOENT);\n    }\n    if (!FS.isDir(lookup.node.mode)) {\n        throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR);\n    }\n    var err = FS.nodePermissions(lookup.node, \'x\');\n    if (err) {\n        throw new FS.ErrnoError(err);\n    }\n    FS.currentPath = lookup.path;\n},createDefaultDirectories:function () {\n    FS.mkdir(\'/tmp\');\n    FS.mkdir(\'/home\');\n    FS.mkdir(\'/home/web_user\');\n},createDefaultDevices:function () {\n    // create /dev\n    FS.mkdir(\'/dev\');\n    // setup /dev/null\n    FS.registerDevice(FS.makedev(1, 3), {\n        read: function() { return 0; },\n        write: function(stream, buffer, offset, length, pos) { return length; }\n    });\n    FS.mkdev(\'/dev/null\', FS.makedev(1, 3));\n    // setup /dev/tty and /dev/tty1\n    // stderr needs to print output using Module[\'printErr\']\n    // so we register a second tty just for it.\n    TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);\n    TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);\n    FS.mkdev(\'/dev/tty\', FS.makedev(5, 0));\n    FS.mkdev(\'/dev/tty1\', FS.makedev(6, 0));\n    // setup /dev/[u]random\n    var random_device;\n    if (typeof crypto !== \'undefined\') {\n        // for modern web browsers\n        var randomBuffer = new Uint8Array(1);\n        random_device = function() { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; };\n    } else if (ENVIRONMENT_IS_NODE) {\n        // for nodejs\n        random_device = function() { return require(\'crypto\').randomBytes(1)[0]; };\n    } else {\n        // default for ES5 platforms\n        random_device = function() { return (Math.random()*256)|0; };\n    }\n    FS.createDevice(\'/dev\', \'random\', random_device);\n    FS.createDevice(\'/dev\', \'urandom\', random_device);\n    // we\'re not going to emulate the actual shm device,\n    // just create the tmp dirs that reside in it commonly\n    FS.mkdir(\'/dev/shm\');\n    FS.mkdir(\'/dev/shm/tmp\');\n},createSpecialDirectories:function () {\n    // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the name of the stream for fd 6 (see test_unistd_ttyname)\n    FS.mkdir(\'/proc\');\n    FS.mkdir(\'/proc/self\');\n    FS.mkdir(\'/proc/self/fd\');\n    FS.mount({\n        mount: function() {\n            var node = FS.createNode(\'/proc/self\', \'fd\', 16384 | 511 /* 0777 */, 73);\n            node.node_ops = {\n                lookup: function(parent, name) {\n                    var fd = +name;\n                    var stream = FS.getStream(fd);\n                    if (!stream) throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n                    var ret = {\n                        parent: null,\n                        mount: { mountpoint: \'fake\' },\n                        node_ops: { readlink: function() { return stream.path } }\n                    };\n                    ret.parent = ret; // make it look like a simple root node\n                    return ret;\n                }\n            };\n            return node;\n        }\n    }, {}, \'/proc/self/fd\');\n},createStandardStreams:function () {\n    // TODO deprecate the old functionality of a single\n    // input / output callback and that utilizes FS.createDevice\n    // and instead require a unique set of stream ops\n\n    // by default, we symlink the standard streams to the\n    // default tty devices. however, if the standard streams\n    // have been overwritten we create a unique device for\n    // them instead.\n    if (Module[\'stdin\']) {\n        FS.createDevice(\'/dev\', \'stdin\', Module[\'stdin\']);\n    } else {\n        FS.symlink(\'/dev/tty\', \'/dev/stdin\');\n    }\n    if (Module[\'stdout\']) {\n        FS.createDevice(\'/dev\', \'stdout\', null, Module[\'stdout\']);\n    } else {\n        FS.symlink(\'/dev/tty\', \'/dev/stdout\');\n    }\n    if (Module[\'stderr\']) {\n        FS.createDevice(\'/dev\', \'stderr\', null, Module[\'stderr\']);\n    } else {\n        FS.symlink(\'/dev/tty1\', \'/dev/stderr\');\n    }\n\n    // open default streams for the stdin, stdout and stderr devices\n    var stdin = FS.open(\'/dev/stdin\', \'r\');\n    assert(stdin.fd === 0, \'invalid handle for stdin (\' + stdin.fd + \')\');\n\n    var stdout = FS.open(\'/dev/stdout\', \'w\');\n    assert(stdout.fd === 1, \'invalid handle for stdout (\' + stdout.fd + \')\');\n\n    var stderr = FS.open(\'/dev/stderr\', \'w\');\n    assert(stderr.fd === 2, \'invalid handle for stderr (\' + stderr.fd + \')\');\n},ensureErrnoError:function () {\n    if (FS.ErrnoError) return;\n    FS.ErrnoError = function ErrnoError(errno, node) {\n        //Module.printErr(stackTrace()); // useful for debugging\n        this.node = node;\n        this.setErrno = function(errno) {\n            this.errno = errno;\n            for (var key in ERRNO_CODES) {\n                if (ERRNO_CODES[key] === errno) {\n                    this.code = key;\n                    break;\n                }\n            }\n        };\n        this.setErrno(errno);\n        this.message = ERRNO_MESSAGES[errno];\n    };\n    FS.ErrnoError.prototype = new Error();\n    FS.ErrnoError.prototype.constructor = FS.ErrnoError;\n    // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)\n    [ERRNO_CODES.ENOENT].forEach(function(code) {\n        FS.genericErrors[code] = new FS.ErrnoError(code);\n        FS.genericErrors[code].stack = \'<generic error, no stack>\';\n    });\n},staticInit:function () {\n    FS.ensureErrnoError();\n\n    FS.nameTable = new Array(4096);\n\n    FS.mount(MEMFS, {}, \'/\');\n\n    FS.createDefaultDirectories();\n    FS.createDefaultDevices();\n    FS.createSpecialDirectories();\n\n    FS.filesystems = {\n        \'MEMFS\': MEMFS,\n        \'IDBFS\': IDBFS,\n        \'NODEFS\': NODEFS,\n        \'WORKERFS\': WORKERFS,\n    };\n},init:function (input, output, error) {\n    assert(!FS.init.initialized, \'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)\');\n    FS.init.initialized = true;\n\n    FS.ensureErrnoError();\n\n    // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here\n    Module[\'stdin\'] = input || Module[\'stdin\'];\n    Module[\'stdout\'] = output || Module[\'stdout\'];\n    Module[\'stderr\'] = error || Module[\'stderr\'];\n\n    FS.createStandardStreams();\n},quit:function () {\n    FS.init.initialized = false;\n    // force-flush all streams, so we get musl std streams printed out\n    var fflush = Module[\'_fflush\'];\n    if (fflush) fflush(0);\n    // close all of our streams\n    for (var i = 0; i < FS.streams.length; i++) {\n        var stream = FS.streams[i];\n        if (!stream) {\n            continue;\n        }\n        FS.close(stream);\n    }\n},getMode:function (canRead, canWrite) {\n    var mode = 0;\n    if (canRead) mode |= 292 | 73;\n    if (canWrite) mode |= 146;\n    return mode;\n},joinPath:function (parts, forceRelative) {\n    var path = PATH.join.apply(null, parts);\n    if (forceRelative && path[0] == \'/\') path = path.substr(1);\n    return path;\n},absolutePath:function (relative, base) {\n    return PATH.resolve(base, relative);\n},standardizePath:function (path) {\n    return PATH.normalize(path);\n},findObject:function (path, dontResolveLastLink) {\n    var ret = FS.analyzePath(path, dontResolveLastLink);\n    if (ret.exists) {\n        return ret.object;\n    } else {\n        ___setErrNo(ret.error);\n        return null;\n    }\n},analyzePath:function (path, dontResolveLastLink) {\n    // operate from within the context of the symlink\'s target\n    try {\n        var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });\n        path = lookup.path;\n    } catch (e) {\n    }\n    var ret = {\n        isRoot: false, exists: false, error: 0, name: null, path: null, object: null,\n        parentExists: false, parentPath: null, parentObject: null\n    };\n    try {\n        var lookup = FS.lookupPath(path, { parent: true });\n        ret.parentExists = true;\n        ret.parentPath = lookup.path;\n        ret.parentObject = lookup.node;\n        ret.name = PATH.basename(path);\n        lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });\n        ret.exists = true;\n        ret.path = lookup.path;\n        ret.object = lookup.node;\n        ret.name = lookup.node.name;\n        ret.isRoot = lookup.path === \'/\';\n    } catch (e) {\n        ret.error = e.errno;\n    };\n    return ret;\n},createFolder:function (parent, name, canRead, canWrite) {\n    var path = PATH.join2(typeof parent === \'string\' ? parent : FS.getPath(parent), name);\n    var mode = FS.getMode(canRead, canWrite);\n    return FS.mkdir(path, mode);\n},createPath:function (parent, path, canRead, canWrite) {\n    parent = typeof parent === \'string\' ? parent : FS.getPath(parent);\n    var parts = path.split(\'/\').reverse();\n    while (parts.length) {\n        var part = parts.pop();\n        if (!part) continue;\n        var current = PATH.join2(parent, part);\n        try {\n            FS.mkdir(current);\n        } catch (e) {\n            // ignore EEXIST\n        }\n        parent = current;\n    }\n    return current;\n},createFile:function (parent, name, properties, canRead, canWrite) {\n    var path = PATH.join2(typeof parent === \'string\' ? parent : FS.getPath(parent), name);\n    var mode = FS.getMode(canRead, canWrite);\n    return FS.create(path, mode);\n},createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {\n    var path = name ? PATH.join2(typeof parent === \'string\' ? parent : FS.getPath(parent), name) : parent;\n    var mode = FS.getMode(canRead, canWrite);\n    var node = FS.create(path, mode);\n    if (data) {\n        if (typeof data === \'string\') {\n            var arr = new Array(data.length);\n            for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);\n            data = arr;\n        }\n        // make sure we can write to the file\n        FS.chmod(node, mode | 146);\n        var stream = FS.open(node, \'w\');\n        FS.write(stream, data, 0, data.length, 0, canOwn);\n        FS.close(stream);\n        FS.chmod(node, mode);\n    }\n    return node;\n},createDevice:function (parent, name, input, output) {\n    var path = PATH.join2(typeof parent === \'string\' ? parent : FS.getPath(parent), name);\n    var mode = FS.getMode(!!input, !!output);\n    if (!FS.createDevice.major) FS.createDevice.major = 64;\n    var dev = FS.makedev(FS.createDevice.major++, 0);\n    // Create a fake device that a set of stream ops to emulate\n    // the old behavior.\n    FS.registerDevice(dev, {\n        open: function(stream) {\n            stream.seekable = false;\n        },\n        close: function(stream) {\n            // flush any pending line data\n            if (output && output.buffer && output.buffer.length) {\n                output(10);\n            }\n        },\n        read: function(stream, buffer, offset, length, pos /* ignored */) {\n            var bytesRead = 0;\n            for (var i = 0; i < length; i++) {\n                var result;\n                try {\n                    result = input();\n                } catch (e) {\n                    throw new FS.ErrnoError(ERRNO_CODES.EIO);\n                }\n                if (result === undefined && bytesRead === 0) {\n                    throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);\n                }\n                if (result === null || result === undefined) break;\n                bytesRead++;\n                buffer[offset+i] = result;\n            }\n            if (bytesRead) {\n                stream.node.timestamp = Date.now();\n            }\n            return bytesRead;\n        },\n        write: function(stream, buffer, offset, length, pos) {\n            for (var i = 0; i < length; i++) {\n                try {\n                    output(buffer[offset+i]);\n                } catch (e) {\n                    throw new FS.ErrnoError(ERRNO_CODES.EIO);\n                }\n            }\n            if (length) {\n                stream.node.timestamp = Date.now();\n            }\n            return i;\n        }\n    });\n    return FS.mkdev(path, mode, dev);\n},createLink:function (parent, name, target, canRead, canWrite) {\n    var path = PATH.join2(typeof parent === \'string\' ? parent : FS.getPath(parent), name);\n    return FS.symlink(target, path);\n},forceLoadFile:function (obj) {\n    if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;\n    var success = true;\n    if (typeof XMLHttpRequest !== \'undefined\') {\n        throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.");\n    } else if (Module[\'read\']) {\n        // Command-line.\n        try {\n            // WARNING: Can\'t read binary files in V8\'s d8 or tracemonkey\'s js, as\n            //          read() will try to parse UTF8.\n            obj.contents = intArrayFromString(Module[\'read\'](obj.url), true);\n            obj.usedBytes = obj.contents.length;\n        } catch (e) {\n            success = false;\n        }\n    } else {\n        throw new Error(\'Cannot load without read() or XMLHttpRequest.\');\n    }\n    if (!success) ___setErrNo(ERRNO_CODES.EIO);\n    return success;\n},createLazyFile:function (parent, name, url, canRead, canWrite) {\n    // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.\n    function LazyUint8Array() {\n        this.lengthKnown = false;\n        this.chunks = []; // Loaded chunks. Index is the chunk number\n    }\n    LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n        if (idx > this.length-1 || idx < 0) {\n            return undefined;\n        }\n        var chunkOffset = idx % this.chunkSize;\n        var chunkNum = (idx / this.chunkSize)|0;\n        return this.getter(chunkNum)[chunkOffset];\n    }\n    LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {\n        this.getter = getter;\n    }\n    LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n        // Find length\n        var xhr = new XMLHttpRequest();\n        xhr.open(\'HEAD\', url, false);\n        xhr.send(null);\n        if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn\'t load " + url + ". Status: " + xhr.status);\n        var datalength = Number(xhr.getResponseHeader("Content-length"));\n        var header;\n        var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";\n        var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip";\n\n        var chunkSize = 1024*1024; // Chunk size in bytes\n\n        if (!hasByteServing) chunkSize = datalength;\n\n        // Function to get a range from the remote URL.\n        var doXHR = (function(from, to) {\n            if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");\n            if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");\n\n            // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.\n            var xhr = new XMLHttpRequest();\n            xhr.open(\'GET\', url, false);\n            if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);\n\n            // Some hints to the browser that we want binary data.\n            if (typeof Uint8Array != \'undefined\') xhr.responseType = \'arraybuffer\';\n            if (xhr.overrideMimeType) {\n                xhr.overrideMimeType(\'text/plain; charset=x-user-defined\');\n            }\n\n            xhr.send(null);\n            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn\'t load " + url + ". Status: " + xhr.status);\n            if (xhr.response !== undefined) {\n                return new Uint8Array(xhr.response || []);\n            } else {\n                return intArrayFromString(xhr.responseText || \'\', true);\n            }\n        });\n        var lazyArray = this;\n        lazyArray.setDataGetter(function(chunkNum) {\n            var start = chunkNum * chunkSize;\n            var end = (chunkNum+1) * chunkSize - 1; // including this byte\n            end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block\n            if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {\n                lazyArray.chunks[chunkNum] = doXHR(start, end);\n            }\n            if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");\n            return lazyArray.chunks[chunkNum];\n        });\n\n        if (usesGzip || !datalength) {\n            // if the server uses gzip or doesn\'t supply the length, we have to download the whole file to get the (uncompressed) length\n            chunkSize = datalength = 1; // this will force getter(0)/doXHR do download the whole file\n            datalength = this.getter(0).length;\n            chunkSize = datalength;\n            console.log("LazyFiles on gzip forces download of the whole file when length is accessed");\n        }\n\n        this._length = datalength;\n        this._chunkSize = chunkSize;\n        this.lengthKnown = true;\n    }\n    if (typeof XMLHttpRequest !== \'undefined\') {\n        if (!ENVIRONMENT_IS_WORKER) throw \'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc\';\n        var lazyArray = new LazyUint8Array();\n        Object.defineProperties(lazyArray, {\n            length: {\n                get: function() {\n                    if(!this.lengthKnown) {\n                        this.cacheLength();\n                    }\n                    return this._length;\n                }\n            },\n            chunkSize: {\n                get: function() {\n                    if(!this.lengthKnown) {\n                        this.cacheLength();\n                    }\n                    return this._chunkSize;\n                }\n            }\n        });\n\n        var properties = { isDevice: false, contents: lazyArray };\n    } else {\n        var properties = { isDevice: false, url: url };\n    }\n\n    var node = FS.createFile(parent, name, properties, canRead, canWrite);\n    // This is a total hack, but I want to get this lazy file code out of the\n    // core of MEMFS. If we want to keep this lazy file concept I feel it should\n    // be its own thin LAZYFS proxying calls to MEMFS.\n    if (properties.contents) {\n        node.contents = properties.contents;\n    } else if (properties.url) {\n        node.contents = null;\n        node.url = properties.url;\n    }\n    // Add a function that defers querying the file size until it is asked the first time.\n    Object.defineProperties(node, {\n        usedBytes: {\n            get: function() { return this.contents.length; }\n        }\n    });\n    // override each stream op with one that tries to force load the lazy file first\n    var stream_ops = {};\n    var keys = Object.keys(node.stream_ops);\n    keys.forEach(function(key) {\n        var fn = node.stream_ops[key];\n        stream_ops[key] = function forceLoadLazyFile() {\n            if (!FS.forceLoadFile(node)) {\n                throw new FS.ErrnoError(ERRNO_CODES.EIO);\n            }\n            return fn.apply(null, arguments);\n        };\n    });\n    // use a custom read function\n    stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {\n        if (!FS.forceLoadFile(node)) {\n            throw new FS.ErrnoError(ERRNO_CODES.EIO);\n        }\n        var contents = stream.node.contents;\n        if (position >= contents.length)\n            return 0;\n        var size = Math.min(contents.length - position, length);\n        assert(size >= 0);\n        if (contents.slice) { // normal array\n            for (var i = 0; i < size; i++) {\n                buffer[offset + i] = contents[position + i];\n            }\n        } else {\n            for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR\n                buffer[offset + i] = contents.get(position + i);\n            }\n        }\n        return size;\n    };\n    node.stream_ops = stream_ops;\n    return node;\n},createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) {\n    Browser.init(); // XXX perhaps this method should move onto Browser?\n    // TODO we should allow people to just pass in a complete filename instead\n    // of parent and name being that we just join them anyways\n    var fullname = name ? PATH.resolve(PATH.join2(parent, name)) : parent;\n    var dep = getUniqueRunDependency(\'cp \' + fullname); // might have several active requests for the same fullname\n    function processData(byteArray) {\n        function finish(byteArray) {\n            if (preFinish) preFinish();\n            if (!dontCreateFile) {\n                FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);\n            }\n            if (onload) onload();\n            removeRunDependency(dep);\n        }\n        var handled = false;\n        Module[\'preloadPlugins\'].forEach(function(plugin) {\n            if (handled) return;\n            if (plugin[\'canHandle\'](fullname)) {\n                plugin[\'handle\'](byteArray, fullname, finish, function() {\n                    if (onerror) onerror();\n                    removeRunDependency(dep);\n                });\n                handled = true;\n            }\n        });\n        if (!handled) finish(byteArray);\n    }\n    addRunDependency(dep);\n    if (typeof url == \'string\') {\n        Browser.asyncLoad(url, function(byteArray) {\n            processData(byteArray);\n        }, onerror);\n    } else {\n        processData(url);\n    }\n},indexedDB:function () {\n    return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;\n},DB_NAME:function () {\n    return \'EM_FS_\' + window.location.pathname;\n},DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {\n    onload = onload || function(){};\n    onerror = onerror || function(){};\n    var indexedDB = FS.indexedDB();\n    try {\n        var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);\n    } catch (e) {\n        return onerror(e);\n    }\n    openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {\n        console.log(\'creating db\');\n        var db = openRequest.result;\n        db.createObjectStore(FS.DB_STORE_NAME);\n    };\n    openRequest.onsuccess = function openRequest_onsuccess() {\n        var db = openRequest.result;\n        var transaction = db.transaction([FS.DB_STORE_NAME], \'readwrite\');\n        var files = transaction.objectStore(FS.DB_STORE_NAME);\n        var ok = 0, fail = 0, total = paths.length;\n        function finish() {\n            if (fail == 0) onload(); else onerror();\n        }\n        paths.forEach(function(path) {\n            var putRequest = files.put(FS.analyzePath(path).object.contents, path);\n            putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };\n            putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };\n        });\n        transaction.onerror = onerror;\n    };\n    openRequest.onerror = onerror;\n},loadFilesFromDB:function (paths, onload, onerror) {\n    onload = onload || function(){};\n    onerror = onerror || function(){};\n    var indexedDB = FS.indexedDB();\n    try {\n        var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);\n    } catch (e) {\n        return onerror(e);\n    }\n    openRequest.onupgradeneeded = onerror; // no database to load from\n    openRequest.onsuccess = function openRequest_onsuccess() {\n        var db = openRequest.result;\n        try {\n            var transaction = db.transaction([FS.DB_STORE_NAME], \'readonly\');\n        } catch(e) {\n            onerror(e);\n            return;\n        }\n        var files = transaction.objectStore(FS.DB_STORE_NAME);\n        var ok = 0, fail = 0, total = paths.length;\n        function finish() {\n            if (fail == 0) onload(); else onerror();\n        }\n        paths.forEach(function(path) {\n            var getRequest = files.get(path);\n            getRequest.onsuccess = function getRequest_onsuccess() {\n                if (FS.analyzePath(path).exists) {\n                    FS.unlink(path);\n                }\n                FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);\n                ok++;\n                if (ok + fail == total) finish();\n            };\n            getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };\n        });\n        transaction.onerror = onerror;\n    };\n    openRequest.onerror = onerror;\n}};var SYSCALLS={DEFAULT_POLLMASK:5,mappings:{},umask:511,calculateAt:function (dirfd, path) {\n    if (path[0] !== \'/\') {\n        // relative path\n        var dir;\n        if (dirfd === -100) {\n            dir = FS.cwd();\n        } else {\n            var dirstream = FS.getStream(dirfd);\n            if (!dirstream) throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n            dir = dirstream.path;\n        }\n        path = PATH.join2(dir, path);\n    }\n    return path;\n},doStat:function (func, path, buf) {\n    try {\n        var stat = func(path);\n    } catch (e) {\n        if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) {\n            // an error occurred while trying to look up the path; we should just report ENOTDIR\n            return -ERRNO_CODES.ENOTDIR;\n        }\n        throw e;\n    }\n    HEAP32[((buf)>>2)]=stat.dev;\n    HEAP32[(((buf)+(4))>>2)]=0;\n    HEAP32[(((buf)+(8))>>2)]=stat.ino;\n    HEAP32[(((buf)+(12))>>2)]=stat.mode;\n    HEAP32[(((buf)+(16))>>2)]=stat.nlink;\n    HEAP32[(((buf)+(20))>>2)]=stat.uid;\n    HEAP32[(((buf)+(24))>>2)]=stat.gid;\n    HEAP32[(((buf)+(28))>>2)]=stat.rdev;\n    HEAP32[(((buf)+(32))>>2)]=0;\n    HEAP32[(((buf)+(36))>>2)]=stat.size;\n    HEAP32[(((buf)+(40))>>2)]=4096;\n    HEAP32[(((buf)+(44))>>2)]=stat.blocks;\n    HEAP32[(((buf)+(48))>>2)]=(stat.atime.getTime() / 1000)|0;\n    HEAP32[(((buf)+(52))>>2)]=0;\n    HEAP32[(((buf)+(56))>>2)]=(stat.mtime.getTime() / 1000)|0;\n    HEAP32[(((buf)+(60))>>2)]=0;\n    HEAP32[(((buf)+(64))>>2)]=(stat.ctime.getTime() / 1000)|0;\n    HEAP32[(((buf)+(68))>>2)]=0;\n    HEAP32[(((buf)+(72))>>2)]=stat.ino;\n    return 0;\n},doMsync:function (addr, stream, len, flags) {\n    var buffer = new Uint8Array(HEAPU8.subarray(addr, addr + len));\n    FS.msync(stream, buffer, 0, len, flags);\n},doMkdir:function (path, mode) {\n    // remove a trailing slash, if one - /a/b/ has basename of \'\', but\n    // we want to create b in the context of this function\n    path = PATH.normalize(path);\n    if (path[path.length-1] === \'/\') path = path.substr(0, path.length-1);\n    FS.mkdir(path, mode, 0);\n    return 0;\n},doMknod:function (path, mode, dev) {\n    // we don\'t want this in the JS API as it uses mknod to create all nodes.\n    switch (mode & 61440) {\n        case 32768:\n        case 8192:\n        case 24576:\n        case 4096:\n        case 49152:\n            break;\n        default: return -ERRNO_CODES.EINVAL;\n    }\n    FS.mknod(path, mode, dev);\n    return 0;\n},doReadlink:function (path, buf, bufsize) {\n    if (bufsize <= 0) return -ERRNO_CODES.EINVAL;\n    var ret = FS.readlink(path);\n\n    var len = Math.min(bufsize, lengthBytesUTF8(ret));\n    var endChar = HEAP8[buf+len];\n    stringToUTF8(ret, buf, bufsize+1);\n    // readlink is one of the rare functions that write out a C string, but does never append a null to the output buffer(!)\n    // stringToUTF8() always appends a null byte, so restore the character under the null byte after the write.\n    HEAP8[buf+len] = endChar;\n\n    return len;\n},doAccess:function (path, amode) {\n    if (amode & ~7) {\n        // need a valid mode\n        return -ERRNO_CODES.EINVAL;\n    }\n    var node;\n    var lookup = FS.lookupPath(path, { follow: true });\n    node = lookup.node;\n    var perms = \'\';\n    if (amode & 4) perms += \'r\';\n    if (amode & 2) perms += \'w\';\n    if (amode & 1) perms += \'x\';\n    if (perms /* otherwise, they\'ve just passed F_OK */ && FS.nodePermissions(node, perms)) {\n        return -ERRNO_CODES.EACCES;\n    }\n    return 0;\n},doDup:function (path, flags, suggestFD) {\n    var suggest = FS.getStream(suggestFD);\n    if (suggest) FS.close(suggest);\n    return FS.open(path, flags, 0, suggestFD, suggestFD).fd;\n},doReadv:function (stream, iov, iovcnt, offset) {\n    var ret = 0;\n    for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAP32[(((iov)+(i*8))>>2)];\n        var len = HEAP32[(((iov)+(i*8 + 4))>>2)];\n        var curr = FS.read(stream, HEAP8,ptr, len, offset);\n        if (curr < 0) return -1;\n        ret += curr;\n        if (curr < len) break; // nothing more to read\n    }\n    return ret;\n},doWritev:function (stream, iov, iovcnt, offset) {\n    var ret = 0;\n    for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAP32[(((iov)+(i*8))>>2)];\n        var len = HEAP32[(((iov)+(i*8 + 4))>>2)];\n        var curr = FS.write(stream, HEAP8,ptr, len, offset);\n        if (curr < 0) return -1;\n        ret += curr;\n    }\n    return ret;\n},varargs:0,get:function (varargs) {\n    SYSCALLS.varargs += 4;\n    var ret = HEAP32[(((SYSCALLS.varargs)-(4))>>2)];\n    return ret;\n},getStr:function () {\n    var ret = Pointer_stringify(SYSCALLS.get());\n    return ret;\n},getStreamFromFD:function () {\n    var stream = FS.getStream(SYSCALLS.get());\n    if (!stream) throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n    return stream;\n},getSocketFromFD:function () {\n    var socket = SOCKFS.getSocket(SYSCALLS.get());\n    if (!socket) throw new FS.ErrnoError(ERRNO_CODES.EBADF);\n    return socket;\n},getSocketAddress:function (allowNull) {\n    var addrp = SYSCALLS.get(), addrlen = SYSCALLS.get();\n    if (allowNull && addrp === 0) return null;\n    var info = __read_sockaddr(addrp, addrlen);\n    if (info.errno) throw new FS.ErrnoError(info.errno);\n    info.addr = DNS.lookup_addr(info.addr) || info.addr;\n    return info;\n},get64:function () {\n    var low = SYSCALLS.get(), high = SYSCALLS.get();\n    if (low >= 0) assert(high === 0);\n    else assert(high === -1);\n    return low;\n},getZero:function () {\n    assert(SYSCALLS.get() === 0);\n}};function ___syscall54(which, varargs) {SYSCALLS.varargs = varargs;\n    try {\n        // ioctl\n        var stream = SYSCALLS.getStreamFromFD(), op = SYSCALLS.get();\n        switch (op) {\n            case 21505: {\n                if (!stream.tty) return -ERRNO_CODES.ENOTTY;\n                return 0;\n            }\n            case 21506: {\n                if (!stream.tty) return -ERRNO_CODES.ENOTTY;\n                return 0; // no-op, not actually adjusting terminal settings\n            }\n            case 21519: {\n                if (!stream.tty) return -ERRNO_CODES.ENOTTY;\n                var argp = SYSCALLS.get();\n                HEAP32[((argp)>>2)]=0;\n                return 0;\n            }\n            case 21520: {\n                if (!stream.tty) return -ERRNO_CODES.ENOTTY;\n                return -ERRNO_CODES.EINVAL; // not supported\n            }\n            case 21531: {\n                var argp = SYSCALLS.get();\n                return FS.ioctl(stream, op, argp);\n            }\n            case 21523: {\n                // TODO: in theory we should write to the winsize struct that gets\n                // passed in, but for now musl doesn\'t read anything on it\n                if (!stream.tty) return -ERRNO_CODES.ENOTTY;\n                return 0;\n            }\n            default: abort(\'bad ioctl syscall \' + op);\n        }\n    } catch (e) {\n        if (typeof FS === \'undefined\' || !(e instanceof FS.ErrnoError)) abort(e);\n        return -e.errno;\n    }\n}\n\nvar ___tm_current=STATICTOP; STATICTOP += 48;;\n\nfunction ___cxa_pure_virtual() {\n    ABORT = true;\n    throw \'Pure virtual function called!\';\n}\n\nfunction _pthread_cond_init() { return 0; }\n\n\n\nfunction _pthread_join() {}\n\n\n\nfunction ___syscall5(which, varargs) {SYSCALLS.varargs = varargs;\n    try {\n        // open\n        var pathname = SYSCALLS.getStr(), flags = SYSCALLS.get(), mode = SYSCALLS.get() // optional TODO\n        var stream = FS.open(pathname, flags, mode);\n        return stream.fd;\n    } catch (e) {\n        if (typeof FS === \'undefined\' || !(e instanceof FS.ErrnoError)) abort(e);\n        return -e.errno;\n    }\n}\n\n\nfunction _emscripten_memcpy_big(dest, src, num) {\n    HEAPU8.set(HEAPU8.subarray(src, src+num), dest);\n    return dest;\n}\n\nfunction ___syscall6(which, varargs) {SYSCALLS.varargs = varargs;\n    try {\n        // close\n        var stream = SYSCALLS.getStreamFromFD();\n        FS.close(stream);\n        return 0;\n    } catch (e) {\n        if (typeof FS === \'undefined\' || !(e instanceof FS.ErrnoError)) abort(e);\n        return -e.errno;\n    }\n}\n\n\n\nvar cttz_i8 = allocate([8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0], "i8", ALLOC_STATIC);function _llvm_cttz_i32(x) {\n    x = x|0;\n    var ret = 0;\n    ret = ((HEAP8[(((cttz_i8)+(x & 0xff))>>0)])|0);\n    if ((ret|0) < 8) return ret|0;\n    ret = ((HEAP8[(((cttz_i8)+((x >> 8)&0xff))>>0)])|0);\n    if ((ret|0) < 8) return (ret + 8)|0;\n    ret = ((HEAP8[(((cttz_i8)+((x >> 16)&0xff))>>0)])|0);\n    if ((ret|0) < 8) return (ret + 16)|0;\n    return (((HEAP8[(((cttz_i8)+(x >>> 24))>>0)])|0) + 24)|0;\n}\n\n\n\n\n\n\nfunction __ZSt18uncaught_exceptionv() { // std::uncaught_exception()\n    return !!__ZSt18uncaught_exceptionv.uncaught_exception;\n}\n\nvar EXCEPTIONS={last:0,caught:[],infos:{},deAdjust:function (adjusted) {\n    if (!adjusted || EXCEPTIONS.infos[adjusted]) return adjusted;\n    for (var ptr in EXCEPTIONS.infos) {\n        var info = EXCEPTIONS.infos[ptr];\n        if (info.adjusted === adjusted) {\n            return ptr;\n        }\n    }\n    return adjusted;\n},addRef:function (ptr) {\n    if (!ptr) return;\n    var info = EXCEPTIONS.infos[ptr];\n    info.refcount++;\n},decRef:function (ptr) {\n    if (!ptr) return;\n    var info = EXCEPTIONS.infos[ptr];\n    assert(info.refcount > 0);\n    info.refcount--;\n    // A rethrown exception can reach refcount 0; it must not be discarded\n    // Its next handler will clear the rethrown flag and addRef it, prior to\n    // final decRef and destruction here\n    if (info.refcount === 0 && !info.rethrown) {\n        if (info.destructor) {\n            Module[\'dynCall_vi\'](info.destructor, ptr);\n        }\n        delete EXCEPTIONS.infos[ptr];\n        ___cxa_free_exception(ptr);\n    }\n},clearRef:function (ptr) {\n    if (!ptr) return;\n    var info = EXCEPTIONS.infos[ptr];\n    info.refcount = 0;\n}};function ___cxa_begin_catch(ptr) {\n    var info = EXCEPTIONS.infos[ptr];\n    if (info && !info.caught) {\n        info.caught = true;\n        __ZSt18uncaught_exceptionv.uncaught_exception--;\n    }\n    if (info) info.rethrown = false;\n    EXCEPTIONS.caught.push(ptr);\n    EXCEPTIONS.addRef(EXCEPTIONS.deAdjust(ptr));\n    return ptr;\n}\n\n\n\nfunction ___resumeException(ptr) {\n    if (!EXCEPTIONS.last) { EXCEPTIONS.last = ptr; }\n    throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";\n}function ___cxa_find_matching_catch() {\n    var thrown = EXCEPTIONS.last;\n    if (!thrown) {\n        // just pass through the null ptr\n        return ((Runtime.setTempRet0(0),0)|0);\n    }\n    var info = EXCEPTIONS.infos[thrown];\n    var throwntype = info.type;\n    if (!throwntype) {\n        // just pass through the thrown ptr\n        return ((Runtime.setTempRet0(0),thrown)|0);\n    }\n    var typeArray = Array.prototype.slice.call(arguments);\n\n    var pointer = Module[\'___cxa_is_pointer_type\'](throwntype);\n    // can_catch receives a **, add indirection\n    if (!___cxa_find_matching_catch.buffer) ___cxa_find_matching_catch.buffer = _malloc(4);\n    HEAP32[((___cxa_find_matching_catch.buffer)>>2)]=thrown;\n    thrown = ___cxa_find_matching_catch.buffer;\n    // The different catch blocks are denoted by different types.\n    // Due to inheritance, those types may not precisely match the\n    // type of the thrown object. Find one which matches, and\n    // return the type of the catch block which should be called.\n    for (var i = 0; i < typeArray.length; i++) {\n        if (typeArray[i] && Module[\'___cxa_can_catch\'](typeArray[i], throwntype, thrown)) {\n            thrown = HEAP32[((thrown)>>2)]; // undo indirection\n            info.adjusted = thrown;\n            return ((Runtime.setTempRet0(typeArray[i]),thrown)|0);\n        }\n    }\n    // Shouldn\'t happen unless we have bogus data in typeArray\n    // or encounter a type for which emscripten doesn\'t have suitable\n    // typeinfo defined. Best-efforts match just in case.\n    thrown = HEAP32[((thrown)>>2)]; // undo indirection\n    return ((Runtime.setTempRet0(throwntype),thrown)|0);\n}function ___gxx_personality_v0() {\n}\n\n\n\nfunction _pthread_mutexattr_init() {}\n\n\n\nfunction ___cxa_free_exception(ptr) {\n    try {\n        return _free(ptr);\n    } catch(e) { // XXX FIXME\n    }\n}function ___cxa_end_catch() {\n    // Clear state flag.\n    Module[\'setThrew\'](0);\n    // Call destructor if one is registered then clear it.\n    var ptr = EXCEPTIONS.caught.pop();\n    if (ptr) {\n        EXCEPTIONS.decRef(EXCEPTIONS.deAdjust(ptr));\n        EXCEPTIONS.last = 0; // XXX in decRef?\n    }\n}function ___cxa_rethrow() {\n    var ptr = EXCEPTIONS.caught.pop();\n    if (!EXCEPTIONS.infos[ptr].rethrown) {\n        // Only pop if the corresponding push was through rethrow_primary_exception\n        EXCEPTIONS.caught.push(ptr)\n        EXCEPTIONS.infos[ptr].rethrown = true;\n    }\n    EXCEPTIONS.last = ptr;\n    throw ptr + " - Exception catching is disabled, this exception cannot be caught. Compile with -s DISABLE_EXCEPTION_CATCHING=0 or DISABLE_EXCEPTION_CATCHING=2 to catch.";\n}\n\nfunction _time(ptr) {\n    var ret = (Date.now()/1000)|0;\n    if (ptr) {\n      HEAP32[((ptr)>>2)]=ret;\n    }\n    return ret;\n  }\n\n  function _localtime(time) {\n    return _localtime_r(time, ___tm_current);\n  }\n\n  function _localtime_r(time, tmPtr) {\n    _tzset();\n    var date = new Date(HEAP32[((time)>>2)]*1000);\n    HEAP32[((tmPtr)>>2)]=date.getSeconds();\n    HEAP32[(((tmPtr)+(4))>>2)]=date.getMinutes();\n    HEAP32[(((tmPtr)+(8))>>2)]=date.getHours();\n    HEAP32[(((tmPtr)+(12))>>2)]=date.getDate();\n    HEAP32[(((tmPtr)+(16))>>2)]=date.getMonth();\n    HEAP32[(((tmPtr)+(20))>>2)]=date.getFullYear()-1900;\n    HEAP32[(((tmPtr)+(24))>>2)]=date.getDay();\n\n    var start = new Date(date.getFullYear(), 0, 1);\n    var yday = ((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24))|0;\n    HEAP32[(((tmPtr)+(28))>>2)]=yday;\n    HEAP32[(((tmPtr)+(36))>>2)]=-(date.getTimezoneOffset() * 60);\n\n    // DST is in December in South\n    var summerOffset = new Date(2000, 6, 1).getTimezoneOffset();\n    var winterOffset = start.getTimezoneOffset();\n    var dst = (date.getTimezoneOffset() == Math.min(winterOffset, summerOffset))|0;\n    HEAP32[(((tmPtr)+(32))>>2)]=dst;\n\n    var zonePtr = HEAP32[(((_tzname)+(dst ? Runtime.QUANTUM_SIZE : 0))>>2)];\n    HEAP32[(((tmPtr)+(40))>>2)]=zonePtr;\n\n    return tmPtr;\n  }\n\nfunction ___syscall140(which, varargs) {SYSCALLS.varargs = varargs;\n    try {\n        // llseek\n        var stream = SYSCALLS.getStreamFromFD(), offset_high = SYSCALLS.get(), offset_low = SYSCALLS.get(), result = SYSCALLS.get(), whence = SYSCALLS.get();\n        // NOTE: offset_high is unused - Emscripten\'s off_t is 32-bit\n        var offset = offset_low;\n        FS.llseek(stream, offset, whence);\n        HEAP32[((result)>>2)]=stream.position;\n        if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; // reset readdir state\n        return 0;\n    } catch (e) {\n        if (typeof FS === \'undefined\' || !(e instanceof FS.ErrnoError)) abort(e);\n        return -e.errno;\n    }\n}\n\nfunction ___syscall146(which, varargs) {SYSCALLS.varargs = varargs;\n    try {\n        // writev\n        var stream = SYSCALLS.getStreamFromFD(), iov = SYSCALLS.get(), iovcnt = SYSCALLS.get();\n        return SYSCALLS.doWritev(stream, iov, iovcnt);\n    } catch (e) {\n        if (typeof FS === \'undefined\' || !(e instanceof FS.ErrnoError)) abort(e);\n        return -e.errno;\n    }\n}\n\nfunction ___syscall221(which, varargs) {SYSCALLS.varargs = varargs;\n    try {\n        // fcntl64\n        var stream = SYSCALLS.getStreamFromFD(), cmd = SYSCALLS.get();\n        switch (cmd) {\n            case 0: {\n                var arg = SYSCALLS.get();\n                if (arg < 0) {\n                    return -ERRNO_CODES.EINVAL;\n                }\n                var newStream;\n                newStream = FS.open(stream.path, stream.flags, 0, arg);\n                return newStream.fd;\n            }\n            case 1:\n            case 2:\n                return 0;  // FD_CLOEXEC makes no sense for a single process.\n            case 3:\n                return stream.flags;\n            case 4: {\n                var arg = SYSCALLS.get();\n                stream.flags |= arg;\n                return 0;\n            }\n            case 12:\n            case 12: {\n                var arg = SYSCALLS.get();\n                var offset = 0;\n                // We\'re always unlocked.\n                HEAP16[(((arg)+(offset))>>1)]=2;\n                return 0;\n            }\n            case 13:\n            case 14:\n            case 13:\n            case 14:\n                return 0; // Pretend that the locking is successful.\n            case 16:\n            case 8:\n                return -ERRNO_CODES.EINVAL; // These are for sockets. We don\'t have them fully implemented yet.\n            case 9:\n                // musl trusts getown return values, due to a bug where they must be, as they overlap with errors. just return -1 here, so fnctl() returns that, and we set errno ourselves.\n                ___setErrNo(ERRNO_CODES.EINVAL);\n                return -1;\n            default: {\n                return -ERRNO_CODES.EINVAL;\n            }\n        }\n    } catch (e) {\n        if (typeof FS === \'undefined\' || !(e instanceof FS.ErrnoError)) abort(e);\n        return -e.errno;\n    }\n}\n\nfunction ___syscall145(which, varargs) {SYSCALLS.varargs = varargs;\n    try {\n        // readv\n        var stream = SYSCALLS.getStreamFromFD(), iov = SYSCALLS.get(), iovcnt = SYSCALLS.get();\n        return SYSCALLS.doReadv(stream, iov, iovcnt);\n    } catch (e) {\n        if (typeof FS === \'undefined\' || !(e instanceof FS.ErrnoError)) abort(e);\n        return -e.errno;\n    }\n}\nFS.staticInit();__ATINIT__.unshift(function() { if (!Module["noFSInit"] && !FS.init.initialized) FS.init() });__ATMAIN__.push(function() { FS.ignorePermissions = false });__ATEXIT__.push(function() { FS.quit() });Module["FS_createFolder"] = FS.createFolder;Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;Module["FS_createPreloadedFile"] = FS.createPreloadedFile;Module["FS_createLazyFile"] = FS.createLazyFile;Module["FS_createLink"] = FS.createLink;Module["FS_createDevice"] = FS.createDevice;Module["FS_unlink"] = FS.unlink;;\n__ATINIT__.unshift(function() { TTY.init() });__ATEXIT__.push(function() { TTY.shutdown() });;\nif (ENVIRONMENT_IS_NODE) { var fs = require("fs"); var NODEJS_PATH = require("path"); NODEFS.staticInit(); };\nDYNAMICTOP_PTR = allocate(1, "i32", ALLOC_STATIC);\n\nSTACK_BASE = STACKTOP = Runtime.alignMemory(STATICTOP);\n\nSTACK_MAX = STACK_BASE + TOTAL_STACK;\n\nDYNAMIC_BASE = Runtime.alignMemory(STACK_MAX);\n\nHEAP32[DYNAMICTOP_PTR>>2] = DYNAMIC_BASE;\n\nstaticSealed = true; // seal the static portion of memory\n\n\nModule[\'wasmTableSize\'] = 306;\n\nModule[\'wasmMaxTableSize\'] = 306;\n\nfunction invoke_vi(index,a1) {\n    try {\n        Module["dynCall_vi"](index,a1);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_iiii(index,a1,a2,a3) {\n    try {\n        return Module["dynCall_iiii"](index,a1,a2,a3);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_viiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) {\n    try {\n        Module["dynCall_viiiiiiiiii"](index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_viiiii(index,a1,a2,a3,a4,a5) {\n    try {\n        Module["dynCall_viiiii"](index,a1,a2,a3,a4,a5);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6) {\n    try {\n        return Module["dynCall_iiiiiii"](index,a1,a2,a3,a4,a5,a6);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_vii(index,a1,a2) {\n    try {\n        Module["dynCall_vii"](index,a1,a2);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_iiiiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10) {\n    try {\n        return Module["dynCall_iiiiiiiiiii"](index,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_viiiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8,a9) {\n    try {\n        Module["dynCall_viiiiiiiii"](index,a1,a2,a3,a4,a5,a6,a7,a8,a9);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_ii(index,a1) {\n    try {\n        return Module["dynCall_ii"](index,a1);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7) {\n    try {\n        Module["dynCall_viiiiiii"](index,a1,a2,a3,a4,a5,a6,a7);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_viiiiiiii(index,a1,a2,a3,a4,a5,a6,a7,a8) {\n    try {\n        Module["dynCall_viiiiiiii"](index,a1,a2,a3,a4,a5,a6,a7,a8);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_v(index) {\n    try {\n        Module["dynCall_v"](index);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_iiiii(index,a1,a2,a3,a4) {\n    try {\n        return Module["dynCall_iiiii"](index,a1,a2,a3,a4);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_viiiiii(index,a1,a2,a3,a4,a5,a6) {\n    try {\n        Module["dynCall_viiiiii"](index,a1,a2,a3,a4,a5,a6);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_iii(index,a1,a2) {\n    try {\n        return Module["dynCall_iii"](index,a1,a2);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nfunction invoke_viiii(index,a1,a2,a3,a4) {\n    try {\n        Module["dynCall_viiii"](index,a1,a2,a3,a4);\n    } catch(e) {\n        if (typeof e !== \'number\' && e !== \'longjmp\') throw e;\n        Module["setThrew"](1, 0);\n    }\n}\n\nModule.asmGlobalArg = { "Math": Math, "Int8Array": Int8Array, "Int16Array": Int16Array, "Int32Array": Int32Array, "Uint8Array": Uint8Array, "Uint16Array": Uint16Array, "Uint32Array": Uint32Array, "Float32Array": Float32Array, "Float64Array": Float64Array, "NaN": NaN, "Infinity": Infinity, "byteLength": byteLength };\n\nModule.asmLibraryArg = { "abort": abort, "assert": assert, "enlargeMemory": enlargeMemory, "getTotalMemory": getTotalMemory, "abortOnCannotGrowMemory": abortOnCannotGrowMemory, "invoke_vi": invoke_vi, "invoke_iiii": invoke_iiii, "invoke_viiiiiiiiii": invoke_viiiiiiiiii, "invoke_viiiii": invoke_viiiii, "invoke_iiiiiii": invoke_iiiiiii, "invoke_vii": invoke_vii, "invoke_iiiiiiiiiii": invoke_iiiiiiiiiii, "invoke_viiiiiiiii": invoke_viiiiiiiii, "invoke_ii": invoke_ii, "invoke_viiiiiii": invoke_viiiiiii, "invoke_viiiiiiii": invoke_viiiiiiii, "invoke_v": invoke_v, "invoke_iiiii": invoke_iiiii, "invoke_viiiiii": invoke_viiiiii, "invoke_iii": invoke_iii, "invoke_viiii": invoke_viiii, "___syscall221": ___syscall221, "_pthread_cond_wait": _pthread_cond_wait, "___lock": ___lock, "_pthread_join": _pthread_join, "___syscall54": ___syscall54, "_abort": _abort, "___gxx_personality_v0": ___gxx_personality_v0, "___cxa_free_exception": ___cxa_free_exception, "_usleep": _usleep, "__ZSt18uncaught_exceptionv": __ZSt18uncaught_exceptionv, "_pthread_cond_init": _pthread_cond_init, "_llvm_cttz_i32": _llvm_cttz_i32, "___setErrNo": ___setErrNo, "___cxa_begin_catch": ___cxa_begin_catch, "_emscripten_memcpy_big": _emscripten_memcpy_big, "___cxa_end_catch": ___cxa_end_catch, "___resumeException": ___resumeException, "___cxa_find_matching_catch": ___cxa_find_matching_catch, "_pthread_getspecific": _pthread_getspecific, "_pthread_mutex_destroy": _pthread_mutex_destroy, "_pthread_once": _pthread_once, "_pthread_mutexattr_settype": _pthread_mutexattr_settype, "_pthread_key_create": _pthread_key_create, "___unlock": ___unlock, "_pthread_create": _pthread_create, "_pthread_mutexattr_init": _pthread_mutexattr_init, "_pthread_setspecific": _pthread_setspecific, "___cxa_rethrow": ___cxa_rethrow, "___syscall6": ___syscall6, "___syscall5": ___syscall5, "_time": _time, "_mktime": _mktime, "_tzset": _tzset, "_localtime": _localtime, "_localtime_r": _localtime_r,  "___cxa_pure_virtual": ___cxa_pure_virtual, "_pthread_cond_destroy": _pthread_cond_destroy, "___syscall140": ___syscall140, "_pthread_mutex_init": _pthread_mutex_init, "___syscall145": ___syscall145, "___syscall146": ___syscall146, "DYNAMICTOP_PTR": DYNAMICTOP_PTR, "tempDoublePtr": tempDoublePtr, "ABORT": ABORT, "STACKTOP": STACKTOP, "STACK_MAX": STACK_MAX, "cttz_i8": cttz_i8 };\n// EMSCRIPTEN_START_ASM\n/*var asm =Module["asm"]// EMSCRIPTEN_END_ASM\n(Module.asmGlobalArg, Module.asmLibraryArg, buffer);*/\n\n//Module[\'asm\'] = asm;\n\nvar _QY265GetFramePts = Module["_QY265GetFramePts"] = function() {  return Module["asm"]["_QY265GetFramePts"].apply(null, arguments) };\nvar stackSave = Module["stackSave"] = function() {  return Module["asm"]["stackSave"].apply(null, arguments) };\nvar getTempRet0 = Module["getTempRet0"] = function() {  return Module["asm"]["getTempRet0"].apply(null, arguments) };\nvar ___udivdi3 = Module["___udivdi3"] = function() {  return Module["asm"]["___udivdi3"].apply(null, arguments) };\nvar _QY265DecodeFrameEnSkip = Module["_QY265DecodeFrameEnSkip"] = function() {  return Module["asm"]["_QY265DecodeFrameEnSkip"].apply(null, arguments) };\nvar _QY265DecoderDestroy = Module["_QY265DecoderDestroy"] = function() {  return Module["asm"]["_QY265DecoderDestroy"].apply(null, arguments) };\nvar setThrew = Module["setThrew"] = function() {  return Module["asm"]["setThrew"].apply(null, arguments) };\nvar _bitshift64Lshr = Module["_bitshift64Lshr"] = function() {  return Module["asm"]["_bitshift64Lshr"].apply(null, arguments) };\nvar _QY265DecoderCreate = Module["_QY265DecoderCreate"] = function() {  return Module["asm"]["_QY265DecoderCreate"].apply(null, arguments) };\nvar _QY265DumpVUIParameters = Module["_QY265DumpVUIParameters"] = function() {  return Module["asm"]["_QY265DumpVUIParameters"].apply(null, arguments) };\nvar _bitshift64Shl = Module["_bitshift64Shl"] = function() {  return Module["asm"]["_bitshift64Shl"].apply(null, arguments) };\nvar _QY265DecoderGetDecodedFrameEm = Module["_QY265DecoderGetDecodedFrameEm"] = function() {  return Module["asm"]["_QY265DecoderGetDecodedFrameEm"].apply(null, arguments) };\nvar _QY265GetFrameHeight = Module["_QY265GetFrameHeight"] = function() {  return Module["asm"]["_QY265GetFrameHeight"].apply(null, arguments) };\nvar _memset = Module["_memset"] = function() {  return Module["asm"]["_memset"].apply(null, arguments) };\nvar _QY265DecoderGetDecodedFrame = Module["_QY265DecoderGetDecodedFrame"] = function() {  return Module["asm"]["_QY265DecoderGetDecodedFrame"].apply(null, arguments) };\nvar _sbrk = Module["_sbrk"] = function() {  return Module["asm"]["_sbrk"].apply(null, arguments) };\nvar _memcpy = Module["_memcpy"] = function() {  return Module["asm"]["_memcpy"].apply(null, arguments) };\nvar ___errno_location = Module["___errno_location"] = function() {  return Module["asm"]["___errno_location"].apply(null, arguments) };\nvar ___uremdi3 = Module["___uremdi3"] = function() {  return Module["asm"]["___uremdi3"].apply(null, arguments) };\nvar _QY265DecodeFrame = Module["_QY265DecodeFrame"] = function() {  return Module["asm"]["_QY265DecodeFrame"].apply(null, arguments) };\nvar stackAlloc = Module["stackAlloc"] = function() {  return Module["asm"]["stackAlloc"].apply(null, arguments) };\nvar _QY265GetFrameWidth = Module["_QY265GetFrameWidth"] = function() {  return Module["asm"]["_QY265GetFrameWidth"].apply(null, arguments) };\nvar _i64Subtract = Module["_i64Subtract"] = function() {  return Module["asm"]["_i64Subtract"].apply(null, arguments) };\nvar setTempRet0 = Module["setTempRet0"] = function() {  return Module["asm"]["setTempRet0"].apply(null, arguments) };\nvar _QY265DecodeFlush = Module["_QY265DecodeFlush"] = function() {  return Module["asm"]["_QY265DecodeFlush"].apply(null, arguments) };\nvar _i64Add = Module["_i64Add"] = function() {  return Module["asm"]["_i64Add"].apply(null, arguments) };\nvar _pthread_mutex_unlock = Module["_pthread_mutex_unlock"] = function() {  return Module["asm"]["_pthread_mutex_unlock"].apply(null, arguments) };\nvar __GLOBAL__sub_I_DecParameterSetReader_cpp = Module["__GLOBAL__sub_I_DecParameterSetReader_cpp"] = function() {  return Module["asm"]["__GLOBAL__sub_I_DecParameterSetReader_cpp"].apply(null, arguments) };\nvar _emscripten_get_global_libc = Module["_emscripten_get_global_libc"] = function() {  return Module["asm"]["_emscripten_get_global_libc"].apply(null, arguments) };\nvar _pthread_cond_broadcast = Module["_pthread_cond_broadcast"] = function() {  return Module["asm"]["_pthread_cond_broadcast"].apply(null, arguments) };\nvar _llvm_bswap_i32 = Module["_llvm_bswap_i32"] = function() {  return Module["asm"]["_llvm_bswap_i32"].apply(null, arguments) };\nvar runPostSets = Module["runPostSets"] = function() {  return Module["asm"]["runPostSets"].apply(null, arguments) };\nvar ___cxa_can_catch = Module["___cxa_can_catch"] = function() {  return Module["asm"]["___cxa_can_catch"].apply(null, arguments) };\nvar _free = Module["_free"] = function() {  return Module["asm"]["_free"].apply(null, arguments) };\nvar _QY265DecoderSetDecConfig = Module["_QY265DecoderSetDecConfig"] = function() {  return Module["asm"]["_QY265DecoderSetDecConfig"].apply(null, arguments) };\nvar establishStackSpace = Module["establishStackSpace"] = function() {  return Module["asm"]["establishStackSpace"].apply(null, arguments) };\nvar _QY265DecoderReturnDecodedFrame = Module["_QY265DecoderReturnDecodedFrame"] = function() {  return Module["asm"]["_QY265DecoderReturnDecodedFrame"].apply(null, arguments) };\nvar _QY265DecoderGetFrameValid = Module["_QY265DecoderGetFrameValid"] = function() {  return Module["asm"]["_QY265DecoderGetFrameValid"].apply(null, arguments) };\nvar stackRestore = Module["stackRestore"] = function() {  return Module["asm"]["stackRestore"].apply(null, arguments) };\nvar _malloc = Module["_malloc"] = function() {  return Module["asm"]["_malloc"].apply(null, arguments) };\nvar _pthread_mutex_lock = Module["_pthread_mutex_lock"] = function() {  return Module["asm"]["_pthread_mutex_lock"].apply(null, arguments) };\nvar _emscripten_replace_memory = Module["_emscripten_replace_memory"] = function() {  return Module["asm"]["_emscripten_replace_memory"].apply(null, arguments) };\nvar _QY265GetPixelBits = Module["_QY265GetPixelBits"] = function() {  return Module["asm"]["_QY265GetPixelBits"].apply(null, arguments) };\nvar ___cxa_is_pointer_type = Module["___cxa_is_pointer_type"] = function() {  return Module["asm"]["___cxa_is_pointer_type"].apply(null, arguments) };\nvar _QY265DecoderGetFramePlane = Module["_QY265DecoderGetFramePlane"] = function() {  return Module["asm"]["_QY265DecoderGetFramePlane"].apply(null, arguments) };\nvar dynCall_vi = Module["dynCall_vi"] = function() {  return Module["asm"]["dynCall_vi"].apply(null, arguments) };\nvar dynCall_iiii = Module["dynCall_iiii"] = function() {  return Module["asm"]["dynCall_iiii"].apply(null, arguments) };\nvar dynCall_viiiiiiiiii = Module["dynCall_viiiiiiiiii"] = function() {  return Module["asm"]["dynCall_viiiiiiiiii"].apply(null, arguments) };\nvar dynCall_viiiii = Module["dynCall_viiiii"] = function() {  return Module["asm"]["dynCall_viiiii"].apply(null, arguments) };\nvar dynCall_iiiiiii = Module["dynCall_iiiiiii"] = function() {  return Module["asm"]["dynCall_iiiiiii"].apply(null, arguments) };\nvar dynCall_vii = Module["dynCall_vii"] = function() {  return Module["asm"]["dynCall_vii"].apply(null, arguments) };\nvar dynCall_iiiiiiiiiii = Module["dynCall_iiiiiiiiiii"] = function() {  return Module["asm"]["dynCall_iiiiiiiiiii"].apply(null, arguments) };\nvar dynCall_viiiiiiiii = Module["dynCall_viiiiiiiii"] = function() {  return Module["asm"]["dynCall_viiiiiiiii"].apply(null, arguments) };\nvar dynCall_ii = Module["dynCall_ii"] = function() {  return Module["asm"]["dynCall_ii"].apply(null, arguments) };\nvar dynCall_viiiiiii = Module["dynCall_viiiiiii"] = function() {  return Module["asm"]["dynCall_viiiiiii"].apply(null, arguments) };\nvar dynCall_viiiiiiii = Module["dynCall_viiiiiiii"] = function() {  return Module["asm"]["dynCall_viiiiiiii"].apply(null, arguments) };\nvar dynCall_v = Module["dynCall_v"] = function() {  return Module["asm"]["dynCall_v"].apply(null, arguments) };\nvar dynCall_iiiii = Module["dynCall_iiiii"] = function() {  return Module["asm"]["dynCall_iiiii"].apply(null, arguments) };\nvar dynCall_viiiiii = Module["dynCall_viiiiii"] = function() {  return Module["asm"]["dynCall_viiiiii"].apply(null, arguments) };\nvar dynCall_iii = Module["dynCall_iii"] = function() {  return Module["asm"]["dynCall_iii"].apply(null, arguments) };\nvar dynCall_viiii = Module["dynCall_viiii"] = function() {  return Module["asm"]["dynCall_viiii"].apply(null, arguments) };\n;\nvar _mktime = Module["_mktime"] = function() {  return Module["asm"]["_mktime"].apply(null, arguments) };\nvar _time = Module["_time"] = function() {  return Module["asm"]["_time"].apply(null, arguments) };\nvar _localtime = Module["_localtime"] = function() {  return Module["asm"]["_localtime"].apply(null, arguments) };\n;\nRuntime.stackAlloc = Module[\'stackAlloc\'];\nRuntime.stackSave = Module[\'stackSave\'];\nRuntime.stackRestore = Module[\'stackRestore\'];\nRuntime.establishStackSpace = Module[\'establishStackSpace\'];\nRuntime.setTempRet0 = Module[\'setTempRet0\'];\nRuntime.getTempRet0 = Module[\'getTempRet0\'];\n\n\n// === Auto-generated postamble setup entry stuff ===\n\n//Module[\'asm\'] = asm;\n\n\n\nif (memoryInitializer) {\n    if (typeof Module[\'locateFile\'] === \'function\') {\n        memoryInitializer = Module[\'locateFile\'](memoryInitializer);\n    } else if (Module[\'memoryInitializerPrefixURL\']) {\n        memoryInitializer = Module[\'memoryInitializerPrefixURL\'] + memoryInitializer;\n    }\n    if (ENVIRONMENT_IS_NODE || ENVIRONMENT_IS_SHELL) {\n        var data = Module[\'readBinary\'](memoryInitializer);\n        HEAPU8.set(data, Runtime.GLOBAL_BASE);\n    } else {\n        addRunDependency(\'memory initializer\');\n        var applyMemoryInitializer = function(data) {\n            if (data.byteLength) data = new Uint8Array(data);\n            HEAPU8.set(data, Runtime.GLOBAL_BASE);\n            // Delete the typed array that contains the large blob of the memory initializer request response so that\n            // we won\'t keep unnecessary memory lying around. However, keep the XHR object itself alive so that e.g.\n            // its .status field can still be accessed later.\n            if (Module[\'memoryInitializerRequest\']) delete Module[\'memoryInitializerRequest\'].response;\n            removeRunDependency(\'memory initializer\');\n        }\n        function doBrowserLoad() {\n            Module[\'readAsync\'](memoryInitializer, applyMemoryInitializer, function() {\n                throw \'could not load memory initializer \' + memoryInitializer;\n            });\n        }\n        if (Module[\'memoryInitializerRequest\']) {\n            // a network request has already been created, just use that\n            function useRequest() {\n                var request = Module[\'memoryInitializerRequest\'];\n                if (request.status !== 200 && request.status !== 0) {\n                    // If you see this warning, the issue may be that you are using locateFile or memoryInitializerPrefixURL, and defining them in JS. That\n                    // means that the HTML file doesn\'t know about them, and when it tries to create the mem init request early, does it to the wrong place.\n                    // Look in your browser\'s devtools network console to see what\'s going on.\n                    console.warn(\'a problem seems to have happened with Module.memoryInitializerRequest, status: \' + request.status + \', retrying \' + memoryInitializer);\n                    doBrowserLoad();\n                    return;\n                }\n                applyMemoryInitializer(request.response);\n            }\n            if (Module[\'memoryInitializerRequest\'].response) {\n                setTimeout(useRequest, 0); // it\'s already here; but, apply it asynchronously\n            } else {\n                Module[\'memoryInitializerRequest\'].addEventListener(\'load\', useRequest); // wait for it\n            }\n        } else {\n            // fetch it from the network ourselves\n            doBrowserLoad();\n        }\n    }\n}\n\n\n\n/**\n * @constructor\n * @extends {Error}\n */\nfunction ExitStatus(status) {\n    this.name = "ExitStatus";\n    this.message = "Program terminated with exit(" + status + ")";\n    this.status = status;\n};\nExitStatus.prototype = new Error();\nExitStatus.prototype.constructor = ExitStatus;\n\nvar initialStackTop;\nvar preloadStartTime = null;\nvar calledMain = false;\n\ndependenciesFulfilled = function runCaller() {\n    // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)\n    if (!Module[\'calledRun\']) run();\n    if (!Module[\'calledRun\']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled\n}\n\nModule[\'callMain\'] = Module.callMain = function callMain(args) {\n\n    args = args || [];\n\n    ensureInitRuntime();\n\n    var argc = args.length+1;\n    function pad() {\n        for (var i = 0; i < 4-1; i++) {\n            argv.push(0);\n        }\n    }\n    var argv = [allocate(intArrayFromString(Module[\'thisProgram\']), \'i8\', ALLOC_NORMAL) ];\n    pad();\n    for (var i = 0; i < argc-1; i = i + 1) {\n        argv.push(allocate(intArrayFromString(args[i]), \'i8\', ALLOC_NORMAL));\n        pad();\n    }\n    argv.push(0);\n    argv = allocate(argv, \'i32\', ALLOC_NORMAL);\n\n\n    try {\n\n        var ret = Module[\'_main\'](argc, argv, 0);\n\n\n        // if we\'re not running an evented main loop, it\'s time to exit\n        exit(ret, /* implicit = */ true);\n    }\n    catch(e) {\n        if (e instanceof ExitStatus) {\n            // exit() throws this once it\'s done to make sure execution\n            // has been stopped completely\n            return;\n        } else if (e == \'SimulateInfiniteLoop\') {\n            // running an evented main loop, don\'t immediately exit\n            Module[\'noExitRuntime\'] = true;\n            return;\n        } else {\n            var toLog = e;\n            if (e && typeof e === \'object\' && e.stack) {\n                toLog = [e, e.stack];\n            }\n            Module.printErr(\'exception thrown: \' + toLog);\n            Module[\'quit\'](1, e);\n        }\n    } finally {\n        calledMain = true;\n    }\n}\n\n\n\n\n/** @type {function(Array=)} */\nfunction run(args) {\n    args = args || Module[\'arguments\'];\n\n    if (preloadStartTime === null) preloadStartTime = Date.now();\n\n    if (runDependencies > 0) {\n        return;\n    }\n\n\n    preRun();\n\n    if (runDependencies > 0) return; // a preRun added a dependency, run will be called later\n    if (Module[\'calledRun\']) return; // run may have just been called through dependencies being fulfilled just in this very frame\n\n    function doRun() {\n        if (Module[\'calledRun\']) return; // run may have just been called while the async setStatus time below was happening\n        Module[\'calledRun\'] = true;\n\n        if (ABORT) return;\n\n        ensureInitRuntime();\n\n        preMain();\n\n\n        if (Module[\'onRuntimeInitialized\']) Module[\'onRuntimeInitialized\']();\n\n        if (Module[\'_main\'] && shouldRunNow) Module[\'callMain\'](args);\n\n        postRun();\n    }\n\n    if (Module[\'setStatus\']) {\n        Module[\'setStatus\'](\'Running...\');\n        setTimeout(function() {\n            setTimeout(function() {\n                Module[\'setStatus\'](\'\');\n            }, 1);\n            doRun();\n        }, 1);\n    } else {\n        doRun();\n    }\n}\nModule[\'run\'] = Module.run = run;\n\nfunction exit(status, implicit) {\n    if (implicit && Module[\'noExitRuntime\']) {\n        return;\n    }\n\n    if (Module[\'noExitRuntime\']) {\n    } else {\n\n        ABORT = true;\n        EXITSTATUS = status;\n        STACKTOP = initialStackTop;\n\n        exitRuntime();\n\n        if (Module[\'onExit\']) Module[\'onExit\'](status);\n    }\n\n    if (ENVIRONMENT_IS_NODE) {\n        process[\'exit\'](status);\n    }\n    Module[\'quit\'](status, new ExitStatus(status));\n}\nModule[\'exit\'] = Module.exit = exit;\n\nvar abortDecorators = [];\n\nfunction abort(what) {\n    if (Module[\'onAbort\']) {\n        Module[\'onAbort\'](what);\n    }\n\n    if (what !== undefined) {\n        Module.print(what);\n        Module.printErr(what);\n        what = JSON.stringify(what)\n    } else {\n        what = \'\';\n    }\n\n    ABORT = true;\n    EXITSTATUS = 1;\n\n    var extra = \'\\nIf this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.\';\n\n    var output = \'abort(\' + what + \') at \' + stackTrace() + extra;\n    if (abortDecorators) {\n        abortDecorators.forEach(function(decorator) {\n            output = decorator(output, what);\n        });\n    }\n    throw output;\n}\nModule[\'abort\'] = Module.abort = abort;\n\n// {{PRE_RUN_ADDITIONS}}\n\nif (Module[\'preInit\']) {\n    if (typeof Module[\'preInit\'] == \'function\') Module[\'preInit\'] = [Module[\'preInit\']];\n    while (Module[\'preInit\'].length > 0) {\n        Module[\'preInit\'].pop()();\n    }\n}\n\n// shouldRunNow refers to calling main(), not run().\nvar shouldRunNow = false;\nif (Module[\'noInitialRun\']) {\n    shouldRunNow = false;\n}\n\nModule["noExitRuntime"] = true;\n\n//run();\n\n// {{POST_RUN_ADDITIONS}}\n\n// {{MODULE_ADDITIONS}}\n\n// don\'t pollute the global namespace\n//delete this[\'Module\'];\n\nconst qy265decoder = {\n    QY_OK : (0x00000000),          // Success codes\n    QY_FAIL : (0x80000001),        //  Unspecified error\n    QY_OUTOFMEMORY : (0x80000002), //  Ran out of memory\n    QY_POINTER : (0x80000003),     //  Invalid pointer\n    QY_NOTSUPPORTED : (0x80000004),//  NOT support feature encoutnered\n    //QY_REACH_LIMIT : (0x80000005), //  frame cnt Reach limit\n    QY_AUTH_INVALID : (0x80000005), //  authentication invalid\n    QY_SEARCHING_ACCESS_POINT : (0x00000001), // in process of searching first access point\n    QY_REF_PIC_NOT_FOUND : (0x80000007), // encode complete\n    QY_NEED_MORE_DATA : (0x00000008),\n    QY_BITSTREAM_ERROR : (0x00000009),\n\n    QY265DecoderCreate: cwrap(\'QY265DecoderCreate\', \'number\',[\'number\', \'number\']),\n    QY265DecoderDestroy: cwrap(\'QY265DecoderDestroy\', \'number\', [\'number\']),\n    QY265DecoderSetDecConfig: cwrap(\'QY265DecoderSetDecConfig\', \'number\', [\'number\',\'number\',\'number\']),\n    QY265DecodeFrame:cwrap(\'QY265DecodeFrame\', \'number\', [\'number\',\'array\',\'number\',\'number\',\'number\']),\n    QY265DecodeFrameEnSkip:cwrap(\'QY265DecodeFrameEnSkip\', \'number\', [\'number\',\'array\',\'number\',\'number\',\'number\',\'number\']),\n\n    QY265DecodeFlush:cwrap(\'QY265DecodeFlush\', \'number\', [\'number\',\'number\',\'number\']),\n    QY265DecoderGetDecodedFrame:cwrap(\'QY265DecoderGetDecodedFrame\', \'number\', [\'number\',\'number\',\'number\',\'number\']),\n    QY265DecoderGetDecodedFrameEm:cwrap(\'QY265DecoderGetDecodedFrameEm\', \'number\', [\'number\',\'number\',\'number\']),\n    QY265DecoderReturnDecodedFrame:cwrap(\'QY265DecoderReturnDecodedFrame\', \'number\', [\'number\',\'number\']),\n    QY265DecoderGetFramePlane : cwrap(\'QY265DecoderGetFramePlane\', \'number\', [\'number\',\'number\',\'number\']),\n    QY265DecoderGetFrameValid: cwrap(\'QY265DecoderGetFrameValid\',  \'number\', [\'number\']),\n   \n    QY265DumpVUIParameters:cwrap(\'QY265DumpVUIParameters\', \'number\', [\'number\',\'number\',\'number\']),\n    QY265GetFrameWidth:cwrap(\'QY265GetFrameWidth\', \'number\', [\'number\',\'number\']),\n    QY265GetFrameHeight:cwrap(\'QY265GetFrameHeight\', \'number\', [\'number\',\'number\']),\n    QY265GetFramePts:cwrap(\'QY265GetFramePts\', \'number\', [\'number\',\'number\']),\n    QY265GetPixelBits:cwrap(\'QY265GetPixelBits\', \'number\', [\'number\',\'number\']),\n};\n\n\n\n\n\n/**\n * A decoded image\n */\nclass Image {\n    constructor(decoder, img) {\n        this.decoder = decoder;\n        this.img = img; // frame\n        this.width = null;\n        this.height = null;\n        this.pts = null;\n    }\n    free(){\n        this.decoder = null;\n        this.img = null;\n        this.width = null;\n        this.height = null;\n        this.pts = null;\n    }\n    get_width() {\n        if (this.width === null) {\n            this.width = qy265decoder.QY265GetFrameWidth(this.img, 0);\n        }\n        return this.width;\n    }\n    get_height() {\n        if (this.height === null) {\n            this.height = qy265decoder.QY265GetFrameHeight(this.img, 0);\n        }\n        return this.height;\n    }\n    get_pts() {\n        if(this.pts === null) {\n            this.pts = qy265decoder.QY265GetFramePts(this.img, 0);\n        }\n        return this.pts;\n    }\n    transcode(imageData, callback, next) { //get YUV data and convert to RGB data\n        var w = this.get_width();\n        var h = this.get_height();\n        var chroma = 1;\n        var stride = _malloc(2);\n        var y = qy265decoder.QY265DecoderGetFramePlane(this.img, 0, stride);\n        var stridey = getValue(stride, "i16");\n        var bppy = 8;\n        var u = qy265decoder.QY265DecoderGetFramePlane(this.img, 1, stride);\n        var strideu = getValue(stride, "i16");\n        var bppu = 8;\n        var v = qy265decoder.QY265DecoderGetFramePlane(this.img, 2, stride);\n        var stridev = getValue(stride, "i16");\n        var bppv = 8;\n        _free(stride);\n\n        this.decoder.convert_yuv2rgb(chroma, y, u, v, w, h, stridey, strideu, stridev, bppy, bppu, bppv, imageData, callback, next);\n    }\n    //\u83B7\u53D6image \u7684YUV420\u6570\u636E\n    getYuvData() {\n        var h = this.get_height();\n        var w = this.get_width();\n        var stride = _malloc(2);\n        var y = qy265decoder.QY265DecoderGetFramePlane(this.img, 0, stride);\n        var stridey = getValue(stride, "i16"); //544\n        var u = qy265decoder.QY265DecoderGetFramePlane(this.img, 1, stride);\n        var strideu = getValue(stride, "i16");\n        var v = qy265decoder.QY265DecoderGetFramePlane(this.img, 2, stride);\n        var stridev = getValue(stride, "i16");\n        \n        var yData = HEAPU8.subarray(y, y+(h*stridey));\n        var uData = HEAPU8.subarray(u, u+(h*strideu));\n        var vData = HEAPU8.subarray(v, v+(h*stridev));\n\n        let yuvData = new Uint8Array(h * w + h / 2 * w / 2 * 2);\n        for(let i = 0; i < h; i++) {\n            yuvData.set(yData.subarray(i*stridey, i*stridey + w), w * i);\n        }\n        for(let i = 0; i < h/2; i++) {\n            let offset = w * h + w/2 * i;\n            yuvData.set(uData.subarray(i* strideu, i* strideu + w/2), offset);\n        }\n        for(let i = 0; i < h/2; i++) {\n            let offset = w * h * 1.25 + w / 2 * i;\n            yuvData.set(vData.subarray(i* stridev, i*stridev+ w/2), offset);\n        }\n        yData = null;\n        uData = null;\n        vData = null;\n    \n        return yuvData;\n    }\n    // \u83B7\u53D6YUV\u6570\u636E\uFF08\u4E0D\u9700\u8981\u6570\u636E\u62FC\u63A5\uFF09\n    getYuvDataNew() {\n        let h = this.get_height();\n        let w = this.get_width();\n        let bufSize = h * w * 1.5;\n\n        let yuvPtr = qy265decoder.QY265DecoderSetYUVPlane(this.img);\n        let yuvData = HEAPU8.subarray(yuvPtr, yuvPtr + bufSize);\n\n        return new Uint8Array(yuvData);\n    \n    }\n}\n\n\nclass LocalConverter{\n    constructor(){}\n    destroy() {}\n    convert(chroma, y, u, v, w, h, stridey, strideu, stridev, bppy, bppu, bppv, imageData, callback) {\n        _do_convert_yuv2rgb(chroma,\n            y, u, v,\n            w, h,\n            stridey, strideu, stridev,\n            bppy, bppu, bppv,\n            imageData);\n\n        if(callback) callback(imageData);\n    }\n}\n\nfunction _do_convert_yuv2rgb(chroma, y, u, v, w, h, stridey, strideu, stridev, bppy, bppu, bppv, dest) {\n    if (!dest) {\n        dest = new Uint8ClampedArray(w * h * 4);\n    }\n    // NOTE: we can\'t use libde265 constants here as the function can also be\n    // run inside the Worker where "libde265" is not available.\n    switch (chroma) {\n        case 0:  /* libde265.de265_chroma_mono */\n            // TODO(fancycode): implement me\n            console.log("Chroma format not implemented yet", chroma, bppy, bppu, bppv);\n            break;\n        case 1:  /* libde265.de265_chroma_420 */\n            if (bppy !== 8 || bppu !== 8 || bppv !== 8) {\n                // TODO(fancycode): implement me\n                console.log("Chroma format not implemented yet", chroma, bppy, bppu, bppv);\n            } else {\n                _do_convert_yuv420(y, u, v, w, h, stridey, strideu, stridev, bppy, bppu, bppv, dest);\n            }\n            break;\n        case 2:  /* libde265.de265_chroma_422 */\n            // TODO(fancycode): implement me\n            console.log("Chroma format not implemented yet", chroma, bppy, bppu, bppv);\n            break;\n        case 3:  /* libde265.de265_chroma_444 */\n            // TODO(fancycode): implement me\n            console.log("Chroma format not implemented yet", chroma, bppy, bppu, bppv);\n            break;\n        default:\n            console.log("Unsupported chroma format", chroma, bppy, bppu, bppv);\n            break;\n    }\n    return dest;\n}\n\nfunction _do_convert_yuv420(y, u, v, w, h, stridey, strideu, stridev, bppy, bppu, bppv, dest) {\n    var yval;\n    var uval;\n    var vval;\n    var xpos = 0;\n    var ypos = 0;\n    var w2 = w >> 1;\n    var maxi = w2*h;\n    var yoffset = 0;\n    var uoffset = 0;\n    var voffset = 0;\n    var x2;\n    var i2;\n    for (var i=0; i<maxi; i++) {\n        i2 = i << 1;\n        x2 = (xpos << 1);\n        yval = 1.164 * (y[yoffset + x2] - 16);\n\n        uval = u[uoffset + xpos] - 128;\n        vval = v[voffset + xpos] - 128;\n        dest[(i2<<2)+0] = yval + 1.596 * vval;\n        dest[(i2<<2)+1] = yval - 0.813 * vval - 0.391 * uval;\n        dest[(i2<<2)+2] = yval + 2.018 * uval;\n        dest[(i2<<2)+3] = 0xff;\n\n        yval = 1.164 * (y[yoffset + x2 + 1] - 16);\n        dest[((i2+1)<<2)+0] = yval + 1.596 * vval;\n        dest[((i2+1)<<2)+1] = yval - 0.813 * vval - 0.391 * uval;\n        dest[((i2+1)<<2)+2] = yval + 2.018 * uval;\n        dest[((i2+1)<<2)+3] = 0xff;\n\n        xpos++;\n        if (xpos === w2) {\n            xpos = 0;\n            ypos++;\n            yoffset += stridey;\n            uoffset = ((ypos >> 1) * strideu);\n            voffset = ((ypos >> 1) * stridev);\n        }\n    }\n}\n\n\nclass H265Decoder {\n    constructor(config) {\n        this.TAG = \'H265Decoder\';\n        this.config = config;\n        this.enableRender = config.enableRender;\n        this.image_callback = null;\n\n        this.framecount = 0; // the counter of frames outputed from decoder\n        this.skippedframecount = 0; // the counter of skipped frames\n        this.innalucount = 0;  // the number of NALU sended to decoder (include frames skipped) \n        this.times = 0;        // decode time\n        this.convertimes = 0; // YUV to RGB converting time\n        this.decStat_cre = _malloc(4);\n\n        //this.more = _malloc(2);\n        this.decStat_ret = _malloc(4);\n        this.decStat_get = _malloc(4);\n\n        this.decoder = qy265decoder.QY265DecoderCreate(null, this.decStat_cre); // request to create a h265 decoder \n\n        this.converter = new LocalConverter();\n\n        this.toBeDecodeQueue = []; // store items like {nalu: Uint8Array, pts: number } \n        this._emitter = new EventEmitter();\n        this._started = false;\n        this._isPausing = false;\n        this.start();\n    }\n    free() {\n        if (this.converter) {\n            this.converter.destroy();\n            this.converter = null;\n        }\n        qy265decoder.QY265DecoderDestroy(this.decoder);\n        this.decoder = null;\n        //_free(this.more);\n        //this.more = null;\n        _free(this.decStat_ret);\n        this.decStat_ret = null;\n        _free(this.decStat_get);\n        this.decStat_get = null;\n        this.toBeDecodeQueue = null;\n        this._emitter.removeAllListeners();\n        this._emitter = null;\n        this.framecount = 0;  \n        this.innalucount = 0;  \n    }\n    on(event, listener) {\n        this._emitter.addListener(event, listener);\n    }\n\n    off(event, listener) {\n        this._emitter.removeListener(event, listener);\n    }\n    \n    convert_yuv2rgb(chroma, y, u, v, w, h, stridey, strideu, stridev, bppy, bppu, bppv, imageData, callback, next) {\n        var begin = new Date();\n        y = HEAPU8.subarray(y, y+(h*stridey));\n        u = HEAPU8.subarray(u, u+(h*strideu));\n        v = HEAPU8.subarray(v, v+(h*stridev));\n        this.converter.convert(chroma, y, u, v, w, h, stridey, strideu, stridev, bppy, bppu, bppv, imageData, callback, next);\n        var span = new Date() - begin;\n        this.convertimes += span; // yuv->rgb coverting time\n    }\n    start() {\n        this._started = true;\n        this._consumeData();\n    }\n    isStarted() {\n        return this._started;\n    }\n    pause() {\n        this._isPausing = true;\n    }\n    isPaused() {\n        return this._isPausing;\n    }\n    resume() {\n        this._isPausing = false;\n        this._consumeData();\n    }\n    _consumeData() {\n        if(this._started && !this._isPausing) {\n            let nal = this.toBeDecodeQueue.shift();\n            if(nal && nal.nalu && nal.pts) {\n                this._decode(nal);\n            }else {\n                setTimeout(() => {\n                    if(!this._isPausing) {\n                        this.resume();\n                    }\n                }, 0);\n            }\n        }\n    }\n    //send data to decoder when previous round of dicoding finished or need more data \n    _decode(data, callback) {  //data: {nalu: Uint8Array, pts: number}\n        try{\n            let starttime = new Date();\n\n            var err;\n            setValue(this.decStat_ret, 0, "i32"); //set the return code of QY265DecodeFrameEnSkip to 0\n            setValue(this.decStat_get, 0, "i32"); //set the return code of QY265DecoderGetDecodedFrameEm to 0\n       \n            if(this.config.enableSkipFrame) {\n                qy265decoder.QY265DecodeFrameEnSkip(this.decoder, data.nalu, data.nalu.length, this.decStat_ret, data.pts, data.isDroppable ? 1: 0);\n            }else {\n                qy265decoder.QY265DecodeFrameEnSkip(this.decoder, data.nalu, data.nalu.length, this.decStat_ret, data.pts, 0);\n            }\n    \n            this.innalucount++ ; \n    \n            if(this.config.enableSkipFrame && data.isDroppable) {\n                this.skippedframecount++;\n                if(this.skippedframecount % 30 == 0) {\n                    this._emitter.emit(\'skip_frame\', this.skippedframecount);\n                }\n            }\n    \n            var framevalid =  1;\n    \n            var bForcelogo = 0;\n            do{  \n                var frame = qy265decoder.QY265DecoderGetDecodedFrameEm(this.decoder,this.decStat_get, bForcelogo);\n                if(getValue(this.decStat_get, \'i32\') !== qy265decoder.QY_OK) //get result status of decoding\n                    break;\n                framevalid = qy265decoder.QY265DecoderGetFrameValid(frame);\n                if(getValue(this.decStat_get, \'i32\') === qy265decoder.QY_OK && framevalid){\n                    if (this.image_callback) {\n                        if(this.enableRender){\n                            this.framecount++ ; //include skipped frame\n                            this.image_callback(new Image(this, frame));\n                        }else{\n                            this.image_callback(undefined);\n                        }\n                    }\n                    qy265decoder.QY265DecoderReturnDecodedFrame(this.decoder, frame); // tell decoder to release memory of the frame\n                   \n                }\n            }while(getValue(this.decStat_get, \'i32\') === qy265decoder.QY_OK && framevalid);\n    \n    \n            var spantime = new Date() - starttime;\n            this.times += spantime;\n            if(this.framecount % 30 == 0) {\n                let realFps = (this.framecount/(this.times * 0.001)).toFixed(1);\n     \n                //console.log(\'\u5B9E\u9645\u89E3\u51FA\u5E27\u6570: \' + this.framecount + \'\\t \u5355\u7EAF\u89E3\u7801\u5E27\u7387:\' + realFps);\n                if(this.config.enableSkipFrame) {\n                    let fakeFps = ((this.skippedframecount + this.framecount) / this.times *1000).toFixed(1);\n                    //console.log(\'\u8DF3\u5E27\u6570: \' + this.skippedframecount + \'\\t \u8DF3\u5E27\u89E3\u7801\u5E27\u7387:\' + fakeFps);\n                }\n            }\n    \n            if(callback) {\n                callback(getValue(this.decStat_ret, \'i32\'));\n            }\n    \n            this._consumeData();\n\n        }catch(e) {\n            this.toBeDecodeQueue.unshift(data); //\u6570\u636E\u585E\u56DE\u961F\u5217\n            setTimeout(()=> {\n                this.consumeData();\n            }, 0);\n        }\n\n        return;\n    }\n    set_image_callback(callback) {\n        this.image_callback = callback;\n    }\n}\n\nfunction compileWasmInterfaces(wasmFilePath, callback) {\n  integrateWasmJS(Module, wasmFilePath, callback);\n  var asm = Module[\'asm\'](Module.asmGlobalArg, Module.asmLibraryArg, buffer);\n  Module[\'asm\'] = asm;\n}\n\nlet decoder = null;\nlet config = {\n  wasmFilePath: \'https://s.ssl.pdim.gs/static/0012deb34ee6d934.wasm\',\n  enableSkipFrame: true,\n  enableRender:true,\n  maxLength4ToBeDecodeQueue: 30 * 30,\n  maxLength4ToBeRenderQueue: 30\n};\ninitHevcDecoder();\nonmessage = function(e) {\n  hevcDecode(e.data);\n}\n\nfunction initHevcDecoder() {\n  compileWasmInterfaces(config.wasmFilePath, callback);\n  \n  function callback() {\n    decoder = new H265Decoder(config);\n    decoder.set_image_callback((image) => {\n      let w = image.get_width(); \n      let h = image.get_height(); \n      let pts = image.get_pts();\n      let yuvData = image.getYuvData();\n      let imageObject = {\n        width:w,\n        height:h,\n        imagedata:yuvData,\n        pts\n      };\n      postMessage(imageObject);\n    });\n  }\n}\n\nfunction hevcDecode(frame) {\n  if(decoder){\n    decoder.toBeDecodeQueue.push({\n    nalu: new Uint8Array(frame.data),  // naluData \u4E3A ArrayBuffer\u7C7B\u578B\u6570\u636E\n    pts: frame.timestamp + frame.compositionTime,  //\u5C55\u793A\u65F6\u95F4\u6233\n    isDroppable: true });  // \u8868\u793A\u662F\u5426\u53EF\u4EE5\u8DF3\u5E27\n  }\n}';
              var workerBlob = new Blob([workerText], { type: 'text/javascript' });
              var workerURL = window.URL.createObjectURL(workerBlob);
              this.worker = new Worker(workerURL);
              this.worker.onmessage = messageEvent.bind(this);
              function messageEvent(e) {
                  this.clearbuffer.call(this);
                  if (this.images && new Date().getTime() - this.ifDecodeTime < 1e3) {
                      this.images.push(e.data);
                  }
              }
          }
      }, {
          key: 'clearbuffer',
          value: function clearbuffer() {
              if (!this.images || this.images.length < 1) {
                  return;
              }
              if (this.images.length > 100) {
                  this.images = this.images.slice(this.images.length - 50);
              }
          }
      }, {
          key: '_canvasPlay',
          value: function _canvasPlay() {
              var got = 0;
              if (!this.canvas) {
                  this.logger.warn(this.TAG, 'no canvas!');
                  return;
              }
              if (this.images && this.images.length > 45) {
                  if (this.needWait && this.mediaElement.paused) {
                      this.mediaElement.play();
                      this.needWait = false;
                  }
                  var w = this.images[0].width;
                  var h = this.images[0].height;
                  if (this.canvas.width != w || this.canvas.height != h) {
                      this.canvas.width = w;
                      this.canvas.height = h;
                      this.webGLCanvas = new _yuvrenderMin2.default({
                          canvas: this.canvas,
                          width: w,
                          height: h
                      });
                      this.ylen = w * h;
                      this.uvlen = w / 2 * (h / 2);
                  }
                  for (var i = 0; i < this.images.length - 1; i++) {
                      var that = this.images[i];
                      var next = this.images[i + 1];
                      if (this.mediaElement.currentTime * 1000 >= that.pts - 5 && this.mediaElement.currentTime * 1000 <= next.pts + 5) {
                          var ylen = this.ylen;
                          var uvlen = this.uvlen;
                          this.webGLCanvas.drawNextOutputPicture({
                              yData: that.imagedata.subarray(0, ylen),
                              uData: that.imagedata.subarray(ylen, ylen + uvlen),
                              vData: that.imagedata.subarray(ylen + uvlen, ylen + uvlen * 2)
                          });
                          got++;
                          this.images.shift();
                          break;
                      } else if (this.mediaElement.currentTime * 1000 > that.pts + 50 && this.images.length > 1) {
                          this.images.shift();
                      }
                  }
                  if (got == 0 && this.images[0].pts / 1000 - this.mediaElement.currentTime > 1.5) {
                      this.mediaElement.currentTime = this.images[0].pts / 1000;
                      this.logger.log(this.TAG, '追帧至' + this.images[0].pts);
                  }
                  if (got == 0 && this.mediaElement.currentTime - this.images[0].pts / 1000 > 1.5 && !this.needWait) {
                      this.needWait = true;
                      this.mediaElement.pause();
                      this.logger.log(this.TAG, '停顿等帧');
                  }
              }
              this.ifDecodeTime = new Date().getTime();
              window.requestAnimationFrame(this._canvasPlay.bind(this));
          }
      }, {
          key: 'destroy',
          value: function destroy() {
              this._dtsBase = 0;
              this._dtsBaseInited = false;
              this._audioDtsBase = Infinity;
              this._videoDtsBase = Infinity;
              this._audioNextDts = undefined;
              this._videoNextDts = undefined;
              this._audioMeta = null;
              this._videoMeta = null;
              this.images = null;
              this.frame = null;
              this.inits = false;
              this.ifDecodeTime = null;
              this.worker = null;
              this.webGLCanvas = null;
              this.ylen = null;
              this.uvlen = null;
          }
      }, {
          key: 'timmerCallback',
          value: function timmerCallback() {
              this.mccree.media.tracks.videoTrack && this.mccree.media.tracks.audioTrack && this._generateBoxes();
          }
      }, {
          key: 'remux',
          value: function remux() {
              //传入来源MSE.
              // 监听媒体数据传入.
              this.observer.on('METADATA_PARSED', this._generateInitailSegment.bind(this));
  
              // 监听视频数据传入.
              this.observer.on('AUDIODATA_PARSED', this._generateBoxes.bind(this));
  
              this.observer.on('VIDEO_PARSED', this._generatevideo.bind(this));
          }
      }, {
          key: '_generateInitailSegment',
          value: function _generateInitailSegment() {
              _mp4Generator2.default.init();
              var audioTrack = this.mccree.media.tracks.audioTrack;
              audioTrack.isAAC = audioTrack.format === 10;
              this._generateConfig();
              // 视频处理
              var amovie = _mp4Generator2.default.initSegment([audioTrack]);
              this.mccree.initSegment.audio = amovie;
              this.observer.trigger('INIT_SEGMENT_REMUXED');
              this._generateBoxes();
          }
      }, {
          key: '_fixRatio',
          value: function _fixRatio() {
              // SPS 错误兼容 / SPS宽高信息错误。转成16:9
              var mediaInfo = this.mccree.media.mediaInfo || {},
                  videoTrack = this.mccree.media.tracks.videoTrack || {},
                  meta = videoTrack.meta || {},
                  height = meta.codecHeight,
                  width = meta.codecWidth;
  
              if (mediaInfo.width && mediaInfo.height && mediaInfo.width === meta.codecWidth && mediaInfo.height === meta.codecHeight) {
                  return;
              }
              if (meta.codecHeight !== meta.codecWidth * 9 / 16) {
                  width = mediaInfo.width ? mediaInfo.width : parseInt(meta.codecHeight * 16 / 9);
                  height = mediaInfo.height ? mediaInfo.height : parseInt(meta.codecWidth * 9 / 16);
                  meta.codecHeight = height;
                  meta.codecWidth = width;
                  meta.presentHeight = height;
                  meta.presentWidth = width;
              }
          }
      }, {
          key: '_generateConfig',
          value: function _generateConfig() {
              var audioTrack = this.mccree.media.tracks.audioTrack,
                  meta = audioTrack.meta;
              var config = [],
                  audioObjectType = audioTrack.objectType,
                  samplingIndex = meta.sampleRateIndex,
                  extensionSamplingIndex = void 0,
                  channelConfig = meta.channelCount;
              var userAgent = navigator.userAgent.toLowerCase();
              if (userAgent.indexOf('firefox') !== -1) {
                  if (samplingIndex >= 6) {
                      audioObjectType = 5;
                      extensionSamplingIndex = samplingIndex - 3;
                  } else {
                      audioObjectType = 2;
                      config = new Array(2);
                      extensionSamplingIndex = samplingIndex;
                  }
              } else if (userAgent.indexOf('android') !== -1) {
                  audioObjectType = 2;
                  extensionSamplingIndex = samplingIndex;
              } else {
                  audioObjectType = 5;
                  extensionSamplingIndex = samplingIndex;
                  if (samplingIndex >= 6) {
                      extensionSamplingIndex = samplingIndex - 3;
                  } else if (channelConfig === 1) {
                      audioObjectType = 2;
                      extensionSamplingIndex = samplingIndex;
                  }
              }
              config[0] = audioObjectType << 3;
              config[0] |= (samplingIndex & 0x0F) >>> 1;
              config[1] = (samplingIndex & 0x0F) << 7;
              config[1] |= (channelConfig & 0x0F) << 3;
              if (audioObjectType === 5) {
                  config[1] |= (samplingIndex & 0x0F) >>> 1;
                  config[2] = (samplingIndex & 0x01) << 7;
                  config[2] |= 2 << 2;
                  config[3] = 0;
              }
              meta.config = config;
              meta.codec = 'mp4a.40.' + audioObjectType;
          }
      }, {
          key: '_generateBoxes',
          value: function _generateBoxes() {
              var audioTrack = this.mccree.media.tracks.audioTrack,
                  nextIframe = 15;
  
              if (audioTrack.samples.length < 16) {
                  return;
              }
  
              this._remuxAudio(audioTrack.samples[0].timestamp, audioTrack.samples[nextIframe].timestamp);
          }
      }, {
          key: '_remuxAudio',
          value: function _remuxAudio(baseDts, nextDts) {
              var base = baseDts,
                  next = baseDts;
              var videoTrack = this.mccree.media.tracks.videoTrack;
              var audioTrack = this.mccree.media.tracks.audioTrack,
                  sampleDuration = audioTrack.meta.refSampleDuration,
                  audioSamples = audioTrack.samples;
              var sampleSize = 0;
              var mp4data = [],
                  mp4Samples = [];
              // 如果音视频总时长差出一个音频片段长度，则该音频片段废弃。
              while (audioSamples[0] && audioSamples[0].timestamp + sampleDuration < baseDts) {
                  this.logger.warn(this.TAG, 'Audio chase frame to ' + audioSamples[0].timestamp);
                  audioSamples.shift();
              }
  
              baseDts = audioSamples[0].timestamp;
              var audioSample = audioSamples[0];
              var tep = audioSamples[0].timestamp;
              while (audioSamples.length > 0 && audioSamples[0].timestamp <= nextDts // 音频片段起始时间小于下一个gop的时间
              ) {
  
                  audioSample = audioSamples.shift();
  
                  if (audioSamples[0]) {
                      base = audioSample.timestamp;
                      next = audioSamples[0].timestamp;
                  } else {
                      base = audioSample.timestamp;
                      next = audioSample.timestamp + sampleDuration;
                  }
  
                  audioSample.sampleDuration = next - base;
  
                  this.mccree.media.audioDuration += audioSample.sampleDuration;
                  var mp4Sample = {
                      dts: audioSample.timestamp - this._dtsBase,
                      pts: audioSample.timestamp - this._dtsBase,
                      cts: 0,
                      size: audioSample.data.length,
                      duration: audioSample.sampleDuration,
                      originalDts: base,
                      flags: {
                          isLeading: 0,
                          dependsOn: 1,
                          isDependedOn: 0,
                          hasRedundancy: 0
                      }
                  };
                  mp4Samples.push(mp4Sample);
                  sampleSize += audioSample.data.length;
                  mp4data.push(audioSample.data);
                  this.mccree.remuxBuffer.lastDts = mp4Sample.dts;
              }
  
              var bytes = sampleSize + 8;
              var offset = 8;
              var mdatbox = new Uint8Array(bytes);
              mdatbox[0] = bytes >>> 24 & 0xFF;
              mdatbox[1] = bytes >>> 16 & 0xFF;
              mdatbox[2] = bytes >>> 8 & 0xFF;
              mdatbox[3] = bytes & 0xFF;
              mdatbox.set(_mp4Generator2.default.types.mdat, 4);
              for (var i = 0; i < mp4data.length; i++) {
                  mdatbox.set(mp4data[i], offset);
                  offset += mp4data[i].length;
              }
              var track = {
                  id: audioTrack.id,
                  samples: mp4Samples
              };
  
              audioTrack.sequenceNumber++;
              var moofbox = _mp4Generator2.default.moof(audioTrack.sequenceNumber, baseDts - this._dtsBase, track);
              this.mccree.remuxBuffer.audio.push({
                  type: 'audio',
                  data: this._mergeBoxes(moofbox, mdatbox)
              });
              this.observer.trigger('MEDIA_SEGMENT_REMUXED', 15);
          }
      }, {
          key: '_calculateDtsBase',
          value: function _calculateDtsBase(audioTrack, videoTrack) {
              if (this._dtsBaseInited) {
                  return;
              }
  
              if (audioTrack.samples && audioTrack.samples.length) {
                  this._audioDtsBase = audioTrack.samples[0].timestamp;
              }
              if (videoTrack.samples && videoTrack.samples.length) {
                  this._videoDtsBase = videoTrack.samples[0].timestamp;
              }
  
              this._dtsBase = Math.min(this._audioDtsBase, this._videoDtsBase);
              this._dtsBaseInited = true;
          }
      }, {
          key: '_mergeBoxes',
          value: function _mergeBoxes(moof, mdat) {
              var result = new Uint8Array(moof.byteLength + mdat.byteLength);
              result.set(moof, 0);
              result.set(mdat, moof.byteLength);
              return result;
          }
      }, {
          key: '_generatevideo',
          value: function _generatevideo() {
              this.frame = this.mccree.media.tracks.videoTrack.samples.shift();
              if (new Date().getTime() - this.ifDecodeTime < 1e3) {
                  this.worker.postMessage(this.frame);
              } else {
                  this.images = [];
              }
  
              if (!this.inits) {
                  this.mediaElement = this.mccree.getMediaElement();
                  if (this.mediaElement) {
                      window.requestAnimationFrame(this._canvasPlay.bind(this));
                  } else {
                      this.logger.warn(this.TAG, 'no mediaElement!');
                  }
                  this.inits = true;
              }
          }
      }]);
  
      return HevcDecoder;
  }();
  
  exports.default = HevcDecoder;