text: // Copyright 2010 The Emscripten Authors.  All rights reserved.
  // Emscripten is available under two separate licenses, the MIT license and the
  // University of Illinois/NCSA Open Source License.  Both these licenses can be
  // found in the LICENSE file.
  
  // The Module object: Our interface to the outside world. We import
  // and export values on it. There are various ways Module can be used:
  // 1. Not defined. We create it here
  // 2. A function parameter, function(Module) { ..generated code.. }
  // 3. pre-run appended it, var Module = {}; ..generated code..
  // 4. External script tag defines var Module.
  // We need to check if Module already exists (e.g. case 3 above).
  // Substitution will be replaced with actual code on later stage of the build,
  // this way Closure Compiler will not mangle it (e.g. case 4. above).
  // Note that if you want to run closure, and also to use Module
  // after the generated code, you will need to define   var Module = {};
  // before the code. Then that object will be used in the code, and you
  // can continue to use Module afterwards as well.
  var Module = typeof Module !== 'undefined' ? Module : {};
  
  // --pre-jses are emitted after the Module integration code, so that they can
  // refer to Module (if they choose; they can also define Module)
  // {{PRE_JSES}}
  
  // Sometimes an existing Module object exists with properties
  // meant to overwrite the default module functionality. Here
  // we collect those properties and reapply _after_ we configure
  // the current environment's defaults to avoid having to be so
  // defensive during initialization.
  var moduleOverrides = {};
  var key;
  for (key in Module) {
    if (Module.hasOwnProperty(key)) {
      moduleOverrides[key] = Module[key];
    }
  }
  
  Module['arguments'] = [];
  Module['thisProgram'] = './this.program';
  Module['quit'] = function(status, toThrow) {
    throw toThrow;
  };
  Module['preRun'] = [];
  Module['postRun'] = [];
  
  // Determine the runtime environment we are in. You can customize this by
  // setting the ENVIRONMENT setting at compile time (see settings.js).
  
  var ENVIRONMENT_IS_WEB = false;
  var ENVIRONMENT_IS_WORKER = false;
  var ENVIRONMENT_IS_NODE = false;
  var ENVIRONMENT_HAS_NODE = false;
  var ENVIRONMENT_IS_SHELL = false;
  ENVIRONMENT_IS_WEB = typeof window === 'object';
  ENVIRONMENT_IS_WORKER = typeof importScripts === 'function';
  // A web environment like Electron.js can have Node enabled, so we must
  // distinguish between Node-enabled environments and Node environments per se.
  // This will allow the former to do things like mount NODEFS.
  // Extended check using process.versions fixes issue #8816.
  // (Also makes redundant the original check that 'require' is a function.)
  ENVIRONMENT_HAS_NODE = typeof process === 'object' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
  ENVIRONMENT_IS_NODE = ENVIRONMENT_HAS_NODE && !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_WORKER;
  ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER;
  
  if (Module['ENVIRONMENT']) {
    throw new Error('Module.ENVIRONMENT has been deprecated. To force the environment, use the ENVIRONMENT compile-time option (for example, -s ENVIRONMENT=web or -s ENVIRONMENT=node)');
  }
  
  
  // Three configurations we can be running in:
  // 1) We could be the application main() thread running in the main JS UI thread. (ENVIRONMENT_IS_WORKER == false and ENVIRONMENT_IS_PTHREAD == false)
  // 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)
  // 3) We could be an application pthread running in a worker. (ENVIRONMENT_IS_WORKER == true and ENVIRONMENT_IS_PTHREAD == true)
  
  
  
  
  // `/` should be present at the end if `scriptDirectory` is not empty
  var scriptDirectory = '';
  function locateFile(path) {
    if (Module['locateFile']) {
      return Module['locateFile'](path, scriptDirectory);
    } else {
      return scriptDirectory + path;
    }
  }
  
  if (ENVIRONMENT_IS_NODE) {
    scriptDirectory = __dirname + '/';
  
    // Expose functionality in the same simple way that the shells work
    // Note that we pollute the global namespace here, otherwise we break in node
    var nodeFS;
    var nodePath;
  
    Module['read'] = function shell_read(filename, binary) {
      var ret;
        if (!nodeFS) nodeFS = require('fs');
        if (!nodePath) nodePath = require('path');
        filename = nodePath['normalize'](filename);
        ret = nodeFS['readFileSync'](filename);
      return binary ? ret : ret.toString();
    };
  
    Module['readBinary'] = function readBinary(filename) {
      var ret = Module['read'](filename, true);
      if (!ret.buffer) {
        ret = new Uint8Array(ret);
      }
      assert(ret.buffer);
      return ret;
    };
  
    if (process['argv'].length > 1) {
      Module['thisProgram'] = process['argv'][1].replace(/\\/g, '/');
    }
  
    Module['arguments'] = process['argv'].slice(2);
  
    if (typeof module !== 'undefined') {
      module['exports'] = Module;
    }
  
    process['on']('uncaughtException', function(ex) {
      // suppress ExitStatus exceptions from showing an error
      if (!(ex instanceof ExitStatus)) {
        throw ex;
      }
    });
    // Currently node will swallow unhandled rejections, but this behavior is
    // deprecated, and in the future it will exit with error status.
    process['on']('unhandledRejection', abort);
  
    Module['quit'] = function(status) {
      process['exit'](status);
    };
  
    Module['inspect'] = function () { return '[Emscripten Module object]'; };
  } else
  if (ENVIRONMENT_IS_SHELL) {
  
  
    if (typeof read != 'undefined') {
      Module['read'] = function shell_read(f) {
        return read(f);
      };
    }
  
    Module['readBinary'] = function readBinary(f) {
      var data;
      if (typeof readbuffer === 'function') {
        return new Uint8Array(readbuffer(f));
      }
      data = read(f, 'binary');
      assert(typeof data === 'object');
      return data;
    };
  
    if (typeof scriptArgs != 'undefined') {
      Module['arguments'] = scriptArgs;
    } else if (typeof arguments != 'undefined') {
      Module['arguments'] = arguments;
    }
  
    if (typeof quit === 'function') {
      Module['quit'] = function(status) {
        quit(status);
      }
    }
  } else
  if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {
    if (ENVIRONMENT_IS_WORKER) { // Check worker, not web, since window could be polyfilled
      scriptDirectory = self.location.href;
    } else if (document.currentScript) { // web
      scriptDirectory = document.currentScript.src;
    }
    // blob urls look like blob:http://site.com/etc/etc and we cannot infer anything from them.
    // otherwise, slice off the final part of the url to find the script directory.
    // if scriptDirectory does not contain a slash, lastIndexOf will return -1,
    // and scriptDirectory will correctly be replaced with an empty string.
    if (scriptDirectory.indexOf('blob:') !== 0) {
      scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf('/')+1);
    } else {
      scriptDirectory = '';
    }
  
  
    Module['read'] = function shell_read(url) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url, false);
        xhr.send(null);
        return xhr.responseText;
    };
  
    if (ENVIRONMENT_IS_WORKER) {
      Module['readBinary'] = function readBinary(url) {
          var xhr = new XMLHttpRequest();
          xhr.open('GET', url, false);
          xhr.responseType = 'arraybuffer';
          xhr.send(null);
          return new Uint8Array(xhr.response);
      };
    }
  
    Module['readAsync'] = function readAsync(url, onload, onerror) {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', url, true);
      xhr.responseType = 'arraybuffer';
      xhr.onload = function xhr_onload() {
        if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) { // file URLs can return 0
          onload(xhr.response);
          return;
        }
        onerror();
      };
      xhr.onerror = onerror;
      xhr.send(null);
    };
  
    Module['setWindowTitle'] = function(title) { document.title = title };
  } else
  {
    throw new Error('environment detection error');
  }
  
  // Set up the out() and err() hooks, which are how we can print to stdout or
  // stderr, respectively.
  // If the user provided Module.print or printErr, use that. Otherwise,
  // console.log is checked first, as 'print' on the web will open a print dialogue
  // printErr is preferable to console.warn (works better in shells)
  // bind(console) is necessary to fix IE/Edge closed dev tools panel behavior.
  var out = Module['print'] || (typeof console !== 'undefined' ? console.log.bind(console) : (typeof print !== 'undefined' ? print : null));
  var err = Module['printErr'] || (typeof printErr !== 'undefined' ? printErr : ((typeof console !== 'undefined' && console.warn.bind(console)) || out));
  
  // Merge back in the overrides
  for (key in moduleOverrides) {
    if (moduleOverrides.hasOwnProperty(key)) {
      Module[key] = moduleOverrides[key];
    }
  }
  // Free the object hierarchy contained in the overrides, this lets the GC
  // reclaim data used e.g. in memoryInitializerRequest, which is a large typed array.
  moduleOverrides = undefined;
  
  // perform assertions in shell.js after we set up out() and err(), as otherwise if an assertion fails it cannot print the message
  assert(typeof Module['memoryInitializerPrefixURL'] === 'undefined', 'Module.memoryInitializerPrefixURL option was removed, use Module.locateFile instead');
  assert(typeof Module['pthreadMainPrefixURL'] === 'undefined', 'Module.pthreadMainPrefixURL option was removed, use Module.locateFile instead');
  assert(typeof Module['cdInitializerPrefixURL'] === 'undefined', 'Module.cdInitializerPrefixURL option was removed, use Module.locateFile instead');
  assert(typeof Module['filePackagePrefixURL'] === 'undefined', 'Module.filePackagePrefixURL option was removed, use Module.locateFile instead');
  
  
  
  // Copyright 2017 The Emscripten Authors.  All rights reserved.
  // Emscripten is available under two separate licenses, the MIT license and the
  // University of Illinois/NCSA Open Source License.  Both these licenses can be
  // found in the LICENSE file.
  
  // {{PREAMBLE_ADDITIONS}}
  
  var STACK_ALIGN = 16;
  
  // stack management, and other functionality that is provided by the compiled code,
  // should not be used before it is ready
  stackSave = stackRestore = stackAlloc = function() {
    abort('cannot use the stack before compiled code is ready to run, and has provided stack access');
  };
  
  function staticAlloc(size) {
    abort('staticAlloc is no longer available at runtime; instead, perform static allocations at compile time (using makeStaticAlloc)');
  }
  
  function dynamicAlloc(size) {
    assert(DYNAMICTOP_PTR);
    var ret = HEAP32[DYNAMICTOP_PTR>>2];
    var end = (ret + size + 15) & -16;
    if (end > _emscripten_get_heap_size()) {
      abort('failure to dynamicAlloc - memory growth etc. is not supported there, call malloc/sbrk directly');
    }
    HEAP32[DYNAMICTOP_PTR>>2] = end;
    return ret;
  }
  
  function alignMemory(size, factor) {
    if (!factor) factor = STACK_ALIGN; // stack alignment (16-byte) by default
    return Math.ceil(size / factor) * factor;
  }
  
  function getNativeTypeSize(type) {
    switch (type) {
      case 'i1': case 'i8': return 1;
      case 'i16': return 2;
      case 'i32': return 4;
      case 'i64': return 8;
      case 'float': return 4;
      case 'double': return 8;
      default: {
        if (type[type.length-1] === '*') {
          return 4; // A pointer
        } else if (type[0] === 'i') {
          var bits = parseInt(type.substr(1));
          assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type);
          return bits / 8;
        } else {
          return 0;
        }
      }
    }
  }
  
  function warnOnce(text) {
    if (!warnOnce.shown) warnOnce.shown = {};
    if (!warnOnce.shown[text]) {
      warnOnce.shown[text] = 1;
      err(text);
    }
  }
  
  var asm2wasmImports = { // special asm2wasm imports
      "f64-rem": function(x, y) {
          return x % y;
      },
      "debugger": function() {
          debugger;
      }
  };
  
  
  
  
  // Wraps a JS function as a wasm function with a given signature.
  // In the future, we may get a WebAssembly.Function constructor. Until then,
  // we create a wasm module that takes the JS function as an import with a given
  // signature, and re-exports that as a wasm function.
  function convertJsFunctionToWasm(func, sig) {
  
    // The module is static, with the exception of the type section, which is
    // generated based on the signature passed in.
    var typeSection = [
      0x01, // id: section,
      0x00, // length: 0 (placeholder)
      0x01, // count: 1
      0x60, // form: func
    ];
    var sigRet = sig.slice(0, 1);
    var sigParam = sig.slice(1);
    var typeCodes = {
      'i': 0x7f, // i32
      'j': 0x7e, // i64
      'f': 0x7d, // f32
      'd': 0x7c, // f64
    };
  
    // Parameters, length + signatures
    typeSection.push(sigParam.length);
    for (var i = 0; i < sigParam.length; ++i) {
      typeSection.push(typeCodes[sigParam[i]]);
    }
  
    // Return values, length + signatures
    // With no multi-return in MVP, either 0 (void) or 1 (anything else)
    if (sigRet == 'v') {
      typeSection.push(0x00);
    } else {
      typeSection = typeSection.concat([0x01, typeCodes[sigRet]]);
    }
  
    // Write the overall length of the type section back into the section header
    // (excepting the 2 bytes for the section id and length)
    typeSection[1] = typeSection.length - 2;
  
    // Rest of the module is static
    var bytes = new Uint8Array([
      0x00, 0x61, 0x73, 0x6d, // magic ("\0asm")
      0x01, 0x00, 0x00, 0x00, // version: 1
    ].concat(typeSection, [
      0x02, 0x07, // import section
        // (import "e" "f" (func 0 (type 0)))
        0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00,
      0x07, 0x05, // export section
        // (export "f" (func 0 (type 0)))
        0x01, 0x01, 0x66, 0x00, 0x00,
    ]));
  
     // We can compile this wasm module synchronously because it is very small.
    // This accepts an import (at "e.f"), that it reroutes to an export (at "f")
    var module = new WebAssembly.Module(bytes);
    var instance = new WebAssembly.Instance(module, {
      e: {
        f: func
      }
    });
    var wrappedFunc = instance.exports.f;
    return wrappedFunc;
  }
  
  // Add a wasm function to the table.
  function addFunctionWasm(func, sig) {
    var table = wasmTable;
    var ret = table.length;
  
    // Grow the table
    try {
      table.grow(1);
    } catch (err) {
      if (!err instanceof RangeError) {
        throw err;
      }
      throw 'Unable to grow wasm table. Use a higher value for RESERVED_FUNCTION_POINTERS or set ALLOW_TABLE_GROWTH.';
    }
  
    // Insert new element
    try {
      // Attempting to call this with JS function will cause of table.set() to fail
      table.set(ret, func);
    } catch (err) {
      if (!err instanceof TypeError) {
        throw err;
      }
      assert(typeof sig !== 'undefined', 'Missing signature argument to addFunction');
      var wrapped = convertJsFunctionToWasm(func, sig);
      table.set(ret, wrapped);
    }
  
    return ret;
  }
  
  function removeFunctionWasm(index) {
    // TODO(sbc): Look into implementing this to allow re-using of table slots
  }
  
  // 'sig' parameter is required for the llvm backend but only when func is not
  // already a WebAssembly function.
  function addFunction(func, sig) {
  
    return addFunctionWasm(func, sig);
  }
  
  function removeFunction(index) {
    removeFunctionWasm(index);
  }
  
  var funcWrappers = {};
  
  function getFuncWrapper(func, sig) {
    if (!func) return; // on null pointer, return undefined
    assert(sig);
    if (!funcWrappers[sig]) {
      funcWrappers[sig] = {};
    }
    var sigCache = funcWrappers[sig];
    if (!sigCache[func]) {
      // optimize away arguments usage in common cases
      if (sig.length === 1) {
        sigCache[func] = function dynCall_wrapper() {
          return dynCall(sig, func);
        };
      } else if (sig.length === 2) {
        sigCache[func] = function dynCall_wrapper(arg) {
          return dynCall(sig, func, [arg]);
        };
      } else {
        // general case
        sigCache[func] = function dynCall_wrapper() {
          return dynCall(sig, func, Array.prototype.slice.call(arguments));
        };
      }
    }
    return sigCache[func];
  }
  
  
  function makeBigInt(low, high, unsigned) {
    return unsigned ? ((+((low>>>0)))+((+((high>>>0)))*4294967296.0)) : ((+((low>>>0)))+((+((high|0)))*4294967296.0));
  }
  
  function dynCall(sig, ptr, args) {
    if (args && args.length) {
      assert(args.length == sig.length-1);
      assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
      return Module['dynCall_' + sig].apply(null, [ptr].concat(args));
    } else {
      assert(sig.length == 1);
      assert(('dynCall_' + sig) in Module, 'bad function pointer type - no table for sig \'' + sig + '\'');
      return Module['dynCall_' + sig].call(null, ptr);
    }
  }
  
  var tempRet0 = 0;
  
  var setTempRet0 = function(value) {
    tempRet0 = value;
  }
  
  var getTempRet0 = function() {
    return tempRet0;
  }
  
  function getCompilerSetting(name) {
    throw 'You must build with -s RETAIN_COMPILER_SETTINGS=1 for getCompilerSetting or emscripten_get_compiler_setting to work';
  }
  
  var Runtime = {
    // helpful errors
    getTempRet0: function() { abort('getTempRet0() is now a top-level function, after removing the Runtime object. Remove "Runtime."') },
    staticAlloc: function() { abort('staticAlloc() is now a top-level function, after removing the Runtime object. Remove "Runtime."') },
    stackAlloc: function() { abort('stackAlloc() is now a top-level function, after removing the Runtime object. Remove "Runtime."') },
  };
  
  // The address globals begin at. Very low in memory, for code size and optimization opportunities.
  // Above 0 is static memory, starting with globals.
  // Then the stack.
  // Then 'dynamic' memory for sbrk.
  var GLOBAL_BASE = 1024;
  
  
  
  
  // === Preamble library stuff ===
  
  // Documentation for the public APIs defined in this file must be updated in:
  //    site/source/docs/api_reference/preamble.js.rst
  // A prebuilt local version of the documentation is available at:
  //    site/build/text/docs/api_reference/preamble.js.txt
  // You can also build docs locally as HTML or other formats in site/
  // An online HTML version (which may be of a different version of Emscripten)
  //    is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html
  
  
  
  if (typeof WebAssembly !== 'object') {
    abort('No WebAssembly support found. Build with -s WASM=0 to target JavaScript instead.');
  }
  
  
  // In MINIMAL_RUNTIME, setValue() and getValue() are only available when building with safe heap enabled, for heap safety checking.
  // In traditional runtime, setValue() and getValue() are always available (although their use is highly discouraged due to perf penalties)
  
  /** @type {function(number, number, string, boolean=)} */
  function setValue(ptr, value, type, noSafe) {
    type = type || 'i8';
    if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
      switch(type) {
        case 'i1': HEAP8[((ptr)>>0)]=value; break;
        case 'i8': HEAP8[((ptr)>>0)]=value; break;
        case 'i16': HEAP16[((ptr)>>1)]=value; break;
        case 'i32': HEAP32[((ptr)>>2)]=value; break;
        case 'i64': (tempI64 = [value>>>0,(tempDouble=value,(+(Math_abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math_min((+(Math_floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((ptr)>>2)]=tempI64[0],HEAP32[(((ptr)+(4))>>2)]=tempI64[1]); break;
        case 'float': HEAPF32[((ptr)>>2)]=value; break;
        case 'double': HEAPF64[((ptr)>>3)]=value; break;
        default: abort('invalid type for setValue: ' + type);
      }
  }
  
  /** @type {function(number, string, boolean=)} */
  function getValue(ptr, type, noSafe) {
    type = type || 'i8';
    if (type.charAt(type.length-1) === '*') type = 'i32'; // pointers are 32-bit
      switch(type) {
        case 'i1': return HEAP8[((ptr)>>0)];
        case 'i8': return HEAP8[((ptr)>>0)];
        case 'i16': return HEAP16[((ptr)>>1)];
        case 'i32': return HEAP32[((ptr)>>2)];
        case 'i64': return HEAP32[((ptr)>>2)];
        case 'float': return HEAPF32[((ptr)>>2)];
        case 'double': return HEAPF64[((ptr)>>3)];
        default: abort('invalid type for getValue: ' + type);
      }
    return null;
  }
  
  
  
  
  
  // Wasm globals
  
  var wasmMemory;
  
  // Potentially used for direct table calls.
  var wasmTable;
  
  
  //========================================
  // Runtime essentials
  //========================================
  
  // whether we are quitting the application. no code should run after this.
  // set in exit() and abort()
  var ABORT = false;
  
  // set by exit() and abort().  Passed to 'onExit' handler.
  // NOTE: This is also used as the process return code code in shell environments
  // but only when noExitRuntime is false.
  var EXITSTATUS = 0;
  
  /** @type {function(*, string=)} */
  function assert(condition, text) {
    if (!condition) {
      abort('Assertion failed: ' + text);
    }
  }
  
  // Returns the C function with a specified identifier (for C++, you need to do manual name mangling)
  function getCFunc(ident) {
    var func = Module['_' + ident]; // closure exported function
    assert(func, 'Cannot call unknown function ' + ident + ', make sure it is exported');
    return func;
  }
  
  // C calling interface.
  function ccall(ident, returnType, argTypes, args, opts) {
    // For fast lookup of conversion functions
    var toC = {
      'string': function(str) {
        var ret = 0;
        if (str !== null && str !== undefined && str !== 0) { // null string
          // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0'
          var len = (str.length << 2) + 1;
          ret = stackAlloc(len);
          stringToUTF8(str, ret, len);
        }
        return ret;
      },
      'array': function(arr) {
        var ret = stackAlloc(arr.length);
        writeArrayToMemory(arr, ret);
        return ret;
      }
    };
  
    function convertReturnValue(ret) {
      if (returnType === 'string') return UTF8ToString(ret);
      if (returnType === 'boolean') return Boolean(ret);
      return ret;
    }
  
    var func = getCFunc(ident);
    var cArgs = [];
    var stack = 0;
    assert(returnType !== 'array', 'Return type should not be "array".');
    if (args) {
      for (var i = 0; i < args.length; i++) {
        var converter = toC[argTypes[i]];
        if (converter) {
          if (stack === 0) stack = stackSave();
          cArgs[i] = converter(args[i]);
        } else {
          cArgs[i] = args[i];
        }
      }
    }
    var ret = func.apply(null, cArgs);
    ret = convertReturnValue(ret);
    if (stack !== 0) stackRestore(stack);
    return ret;
  }
  
  function cwrap(ident, returnType, argTypes, opts) {
    return function() {
      return ccall(ident, returnType, argTypes, arguments, opts);
    }
  }
  
  var ALLOC_NORMAL = 0; // Tries to use _malloc()
  var ALLOC_STACK = 1; // Lives for the duration of the current function call
  var ALLOC_DYNAMIC = 2; // Cannot be freed except through sbrk
  var ALLOC_NONE = 3; // Do not allocate
  
  // allocate(): This is for internal use. You can use it yourself as well, but the interface
  //             is a little tricky (see docs right below). The reason is that it is optimized
  //             for multiple syntaxes to save space in generated code. So you should
  //             normally not use allocate(), and instead allocate memory using _malloc(),
  //             initialize it with setValue(), and so forth.
  // @slab: An array of data, or a number. If a number, then the size of the block to allocate,
  //        in *bytes* (note that this is sometimes confusing: the next parameter does not
  //        affect this!)
  // @types: Either an array of types, one for each byte (or 0 if no type at that position),
  //         or a single type which is used for the entire block. This only matters if there
  //         is initial data - if @slab is a number, then this does not matter at all and is
  //         ignored.
  // @allocator: How to allocate memory, see ALLOC_*
  /** @type {function((TypedArray|Array<number>|number), string, number, number=)} */
  function allocate(slab, types, allocator, ptr) {
    var zeroinit, size;
    if (typeof slab === 'number') {
      zeroinit = true;
      size = slab;
    } else {
      zeroinit = false;
      size = slab.length;
    }
  
    var singleType = typeof types === 'string' ? types : null;
  
    var ret;
    if (allocator == ALLOC_NONE) {
      ret = ptr;
    } else {
      ret = [_malloc,
      stackAlloc,
      dynamicAlloc][allocator](Math.max(size, singleType ? 1 : types.length));
    }
  
    if (zeroinit) {
      var stop;
      ptr = ret;
      assert((ret & 3) == 0);
      stop = ret + (size & ~3);
      for (; ptr < stop; ptr += 4) {
        HEAP32[((ptr)>>2)]=0;
      }
      stop = ret + size;
      while (ptr < stop) {
        HEAP8[((ptr++)>>0)]=0;
      }
      return ret;
    }
  
    if (singleType === 'i8') {
      if (slab.subarray || slab.slice) {
        HEAPU8.set(/** @type {!Uint8Array} */ (slab), ret);
      } else {
        HEAPU8.set(new Uint8Array(slab), ret);
      }
      return ret;
    }
  
    var i = 0, type, typeSize, previousType;
    while (i < size) {
      var curr = slab[i];
  
      type = singleType || types[i];
      if (type === 0) {
        i++;
        continue;
      }
      assert(type, 'Must know what type to store in allocate!');
  
      if (type == 'i64') type = 'i32'; // special case: we have one i32 here, and one i32 later
  
      setValue(ret+i, curr, type);
  
      // no need to look up size unless type changes, so cache it
      if (previousType !== type) {
        typeSize = getNativeTypeSize(type);
        previousType = type;
      }
      i += typeSize;
    }
  
    return ret;
  }
  
  // Allocate memory during any stage of startup - static memory early on, dynamic memory later, malloc when ready
  function getMemory(size) {
    if (!runtimeInitialized) return dynamicAlloc(size);
    return _malloc(size);
  }
  
  
  
  
  /** @type {function(number, number=)} */
  function Pointer_stringify(ptr, length) {
    abort("this function has been removed - you should use UTF8ToString(ptr, maxBytesToRead) instead!");
  }
  
  // Given a pointer 'ptr' to a null-terminated ASCII-encoded string in the emscripten HEAP, returns
  // a copy of that string as a Javascript String object.
  
  function AsciiToString(ptr) {
    var str = '';
    while (1) {
      var ch = HEAPU8[((ptr++)>>0)];
      if (!ch) return str;
      str += String.fromCharCode(ch);
    }
  }
  
  // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
  // null-terminated and encoded in ASCII form. The copy will require at most str.length+1 bytes of space in the HEAP.
  
  function stringToAscii(str, outPtr) {
    return writeAsciiToMemory(str, outPtr, false);
  }
  
  
  // Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the given array that contains uint8 values, returns
  // a copy of that string as a Javascript String object.
  
  var UTF8Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined;
  
  /**
   * @param {number} idx
   * @param {number=} maxBytesToRead
   * @return {string}
   */
  function UTF8ArrayToString(u8Array, idx, maxBytesToRead) {
    var endIdx = idx + maxBytesToRead;
    var endPtr = idx;
    // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself.
    // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.
    // (As a tiny code save trick, compare endPtr against endIdx using a negation, so that undefined means Infinity)
    while (u8Array[endPtr] && !(endPtr >= endIdx)) ++endPtr;
  
    if (endPtr - idx > 16 && u8Array.subarray && UTF8Decoder) {
      return UTF8Decoder.decode(u8Array.subarray(idx, endPtr));
    } else {
      var str = '';
      // If building with TextDecoder, we have already computed the string length above, so test loop end condition against that
      while (idx < endPtr) {
        // For UTF8 byte structure, see:
        // http://en.wikipedia.org/wiki/UTF-8#Description
        // https://www.ietf.org/rfc/rfc2279.txt
        // https://tools.ietf.org/html/rfc3629
        var u0 = u8Array[idx++];
        if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; }
        var u1 = u8Array[idx++] & 63;
        if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; }
        var u2 = u8Array[idx++] & 63;
        if ((u0 & 0xF0) == 0xE0) {
          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2;
        } else {
          if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte 0x' + u0.toString(16) + ' encountered when deserializing a UTF-8 string on the asm.js/wasm heap to a JS string!');
          u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (u8Array[idx++] & 63);
        }
  
        if (u0 < 0x10000) {
          str += String.fromCharCode(u0);
        } else {
          var ch = u0 - 0x10000;
          str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
        }
      }
    }
    return str;
  }
  
  // Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the emscripten HEAP, returns a
  // copy of that string as a Javascript String object.
  // maxBytesToRead: an optional length that specifies the maximum number of bytes to read. You can omit
  //                 this parameter to scan the string until the first \0 byte. If maxBytesToRead is
  //                 passed, and the string at [ptr, ptr+maxBytesToReadr[ contains a null byte in the
  //                 middle, then the string will cut short at that byte index (i.e. maxBytesToRead will
  //                 not produce a string of exact length [ptr, ptr+maxBytesToRead[)
  //                 N.B. mixing frequent uses of UTF8ToString() with and without maxBytesToRead may
  //                 throw JS JIT optimizations off, so it is worth to consider consistently using one
  //                 style or the other.
  /**
   * @param {number} ptr
   * @param {number=} maxBytesToRead
   * @return {string}
   */
  function UTF8ToString(ptr, maxBytesToRead) {
    return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : '';
  }
  
  // Copies the given Javascript String object 'str' to the given byte array at address 'outIdx',
  // encoded in UTF8 form and null-terminated. The copy will require at most str.length*4+1 bytes of space in the HEAP.
  // Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write.
  // Parameters:
  //   str: the Javascript string to copy.
  //   outU8Array: the array to copy to. Each index in this array is assumed to be one 8-byte element.
  //   outIdx: The starting offset in the array to begin the copying.
  //   maxBytesToWrite: The maximum number of bytes this function can write to the array.
  //                    This count should include the null terminator,
  //                    i.e. if maxBytesToWrite=1, only the null terminator will be written and nothing else.
  //                    maxBytesToWrite=0 does not write any bytes to the output, not even the null terminator.
  // Returns the number of bytes written, EXCLUDING the null terminator.
  
  function stringToUTF8Array(str, outU8Array, outIdx, maxBytesToWrite) {
    if (!(maxBytesToWrite > 0)) // Parameter maxBytesToWrite is not optional. Negative values, 0, null, undefined and false each don't write out any bytes.
      return 0;
  
    var startIdx = outIdx;
    var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator.
    for (var i = 0; i < str.length; ++i) {
      // 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.
      // See http://unicode.org/faq/utf_bom.html#utf16-3
      // 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
      var u = str.charCodeAt(i); // possibly a lead surrogate
      if (u >= 0xD800 && u <= 0xDFFF) {
        var u1 = str.charCodeAt(++i);
        u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF);
      }
      if (u <= 0x7F) {
        if (outIdx >= endIdx) break;
        outU8Array[outIdx++] = u;
      } else if (u <= 0x7FF) {
        if (outIdx + 1 >= endIdx) break;
        outU8Array[outIdx++] = 0xC0 | (u >> 6);
        outU8Array[outIdx++] = 0x80 | (u & 63);
      } else if (u <= 0xFFFF) {
        if (outIdx + 2 >= endIdx) break;
        outU8Array[outIdx++] = 0xE0 | (u >> 12);
        outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);
        outU8Array[outIdx++] = 0x80 | (u & 63);
      } else {
        if (outIdx + 3 >= endIdx) break;
        if (u >= 0x200000) warnOnce('Invalid Unicode code point 0x' + u.toString(16) + ' encountered when serializing a JS string to an UTF-8 string on the asm.js/wasm heap! (Valid unicode code points should be in range 0-0x1FFFFF).');
        outU8Array[outIdx++] = 0xF0 | (u >> 18);
        outU8Array[outIdx++] = 0x80 | ((u >> 12) & 63);
        outU8Array[outIdx++] = 0x80 | ((u >> 6) & 63);
        outU8Array[outIdx++] = 0x80 | (u & 63);
      }
    }
    // Null-terminate the pointer to the buffer.
    outU8Array[outIdx] = 0;
    return outIdx - startIdx;
  }
  
  // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
  // null-terminated and encoded in UTF8 form. The copy will require at most str.length*4+1 bytes of space in the HEAP.
  // Use the function lengthBytesUTF8 to compute the exact number of bytes (excluding null terminator) that this function will write.
  // Returns the number of bytes written, EXCLUDING the null terminator.
  
  function stringToUTF8(str, outPtr, maxBytesToWrite) {
    assert(typeof maxBytesToWrite == 'number', 'stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
    return stringToUTF8Array(str, HEAPU8,outPtr, maxBytesToWrite);
  }
  
  // Returns the number of bytes the given Javascript string takes if encoded as a UTF8 byte array, EXCLUDING the null terminator byte.
  function lengthBytesUTF8(str) {
    var len = 0;
    for (var i = 0; i < str.length; ++i) {
      // 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.
      // See http://unicode.org/faq/utf_bom.html#utf16-3
      var u = str.charCodeAt(i); // possibly a lead surrogate
      if (u >= 0xD800 && u <= 0xDFFF) u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
      if (u <= 0x7F) ++len;
      else if (u <= 0x7FF) len += 2;
      else if (u <= 0xFFFF) len += 3;
      else len += 4;
    }
    return len;
  }
  
  
  // Given a pointer 'ptr' to a null-terminated UTF16LE-encoded string in the emscripten HEAP, returns
  // a copy of that string as a Javascript String object.
  
  var UTF16Decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-16le') : undefined;
  function UTF16ToString(ptr) {
    assert(ptr % 2 == 0, 'Pointer passed to UTF16ToString must be aligned to two bytes!');
    var endPtr = ptr;
    // TextDecoder needs to know the byte length in advance, it doesn't stop on null terminator by itself.
    // Also, use the length info to avoid running tiny strings through TextDecoder, since .subarray() allocates garbage.
    var idx = endPtr >> 1;
    while (HEAP16[idx]) ++idx;
    endPtr = idx << 1;
  
    if (endPtr - ptr > 32 && UTF16Decoder) {
      return UTF16Decoder.decode(HEAPU8.subarray(ptr, endPtr));
    } else {
      var i = 0;
  
      var str = '';
      while (1) {
        var codeUnit = HEAP16[(((ptr)+(i*2))>>1)];
        if (codeUnit == 0) return str;
        ++i;
        // fromCharCode constructs a character from a UTF-16 code unit, so we can pass the UTF16 string right through.
        str += String.fromCharCode(codeUnit);
      }
    }
  }
  
  // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
  // null-terminated and encoded in UTF16 form. The copy will require at most str.length*4+2 bytes of space in the HEAP.
  // Use the function lengthBytesUTF16() to compute the exact number of bytes (excluding null terminator) that this function will write.
  // Parameters:
  //   str: the Javascript string to copy.
  //   outPtr: Byte address in Emscripten HEAP where to write the string to.
  //   maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null
  //                    terminator, i.e. if maxBytesToWrite=2, only the null terminator will be written and nothing else.
  //                    maxBytesToWrite<2 does not write any bytes to the output, not even the null terminator.
  // Returns the number of bytes written, EXCLUDING the null terminator.
  
  function stringToUTF16(str, outPtr, maxBytesToWrite) {
    assert(outPtr % 2 == 0, 'Pointer passed to stringToUTF16 must be aligned to two bytes!');
    assert(typeof maxBytesToWrite == 'number', 'stringToUTF16(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
    // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed.
    if (maxBytesToWrite === undefined) {
      maxBytesToWrite = 0x7FFFFFFF;
    }
    if (maxBytesToWrite < 2) return 0;
    maxBytesToWrite -= 2; // Null terminator.
    var startPtr = outPtr;
    var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length;
    for (var i = 0; i < numCharsToWrite; ++i) {
      // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP.
      var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
      HEAP16[((outPtr)>>1)]=codeUnit;
      outPtr += 2;
    }
    // Null-terminate the pointer to the HEAP.
    HEAP16[((outPtr)>>1)]=0;
    return outPtr - startPtr;
  }
  
  // Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte.
  
  function lengthBytesUTF16(str) {
    return str.length*2;
  }
  
  function UTF32ToString(ptr) {
    assert(ptr % 4 == 0, 'Pointer passed to UTF32ToString must be aligned to four bytes!');
    var i = 0;
  
    var str = '';
    while (1) {
      var utf32 = HEAP32[(((ptr)+(i*4))>>2)];
      if (utf32 == 0)
        return str;
      ++i;
      // 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.
      // See http://unicode.org/faq/utf_bom.html#utf16-3
      if (utf32 >= 0x10000) {
        var ch = utf32 - 0x10000;
        str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF));
      } else {
        str += String.fromCharCode(utf32);
      }
    }
  }
  
  // Copies the given Javascript String object 'str' to the emscripten HEAP at address 'outPtr',
  // null-terminated and encoded in UTF32 form. The copy will require at most str.length*4+4 bytes of space in the HEAP.
  // Use the function lengthBytesUTF32() to compute the exact number of bytes (excluding null terminator) that this function will write.
  // Parameters:
  //   str: the Javascript string to copy.
  //   outPtr: Byte address in Emscripten HEAP where to write the string to.
  //   maxBytesToWrite: The maximum number of bytes this function can write to the array. This count should include the null
  //                    terminator, i.e. if maxBytesToWrite=4, only the null terminator will be written and nothing else.
  //                    maxBytesToWrite<4 does not write any bytes to the output, not even the null terminator.
  // Returns the number of bytes written, EXCLUDING the null terminator.
  
  function stringToUTF32(str, outPtr, maxBytesToWrite) {
    assert(outPtr % 4 == 0, 'Pointer passed to stringToUTF32 must be aligned to four bytes!');
    assert(typeof maxBytesToWrite == 'number', 'stringToUTF32(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!');
    // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed.
    if (maxBytesToWrite === undefined) {
      maxBytesToWrite = 0x7FFFFFFF;
    }
    if (maxBytesToWrite < 4) return 0;
    var startPtr = outPtr;
    var endPtr = startPtr + maxBytesToWrite - 4;
    for (var i = 0; i < str.length; ++i) {
      // 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.
      // See http://unicode.org/faq/utf_bom.html#utf16-3
      var codeUnit = str.charCodeAt(i); // possibly a lead surrogate
      if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) {
        var trailSurrogate = str.charCodeAt(++i);
        codeUnit = 0x10000 + ((codeUnit & 0x3FF) << 10) | (trailSurrogate & 0x3FF);
      }
      HEAP32[((outPtr)>>2)]=codeUnit;
      outPtr += 4;
      if (outPtr + 4 > endPtr) break;
    }
    // Null-terminate the pointer to the HEAP.
    HEAP32[((outPtr)>>2)]=0;
    return outPtr - startPtr;
  }
  
  // Returns the number of bytes the given Javascript string takes if encoded as a UTF16 byte array, EXCLUDING the null terminator byte.
  
  function lengthBytesUTF32(str) {
    var len = 0;
    for (var i = 0; i < str.length; ++i) {
      // 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.
      // See http://unicode.org/faq/utf_bom.html#utf16-3
      var codeUnit = str.charCodeAt(i);
      if (codeUnit >= 0xD800 && codeUnit <= 0xDFFF) ++i; // possibly a lead surrogate, so skip over the tail surrogate.
      len += 4;
    }
  
    return len;
  }
  
  // Allocate heap space for a JS string, and write it there.
  // It is the responsibility of the caller to free() that memory.
  function allocateUTF8(str) {
    var size = lengthBytesUTF8(str) + 1;
    var ret = _malloc(size);
    if (ret) stringToUTF8Array(str, HEAP8, ret, size);
    return ret;
  }
  
  // Allocate stack space for a JS string, and write it there.
  function allocateUTF8OnStack(str) {
    var size = lengthBytesUTF8(str) + 1;
    var ret = stackAlloc(size);
    stringToUTF8Array(str, HEAP8, ret, size);
    return ret;
  }
  
  // Deprecated: This function should not be called because it is unsafe and does not provide
  // a maximum length limit of how many bytes it is allowed to write. Prefer calling the
  // function stringToUTF8Array() instead, which takes in a maximum length that can be used
  // to be secure from out of bounds writes.
  /** @deprecated */
  function writeStringToMemory(string, buffer, dontAddNull) {
    warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!');
  
    var /** @type {number} */ lastChar, /** @type {number} */ end;
    if (dontAddNull) {
      // stringToUTF8Array always appends null. If we don't want to do that, remember the
      // character that existed at the location where the null will be placed, and restore
      // that after the write (below).
      end = buffer + lengthBytesUTF8(string);
      lastChar = HEAP8[end];
    }
    stringToUTF8(string, buffer, Infinity);
    if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character.
  }
  
  function writeArrayToMemory(array, buffer) {
    assert(array.length >= 0, 'writeArrayToMemory array must have a length (should be an array or typed array)')
    HEAP8.set(array, buffer);
  }
  
  function writeAsciiToMemory(str, buffer, dontAddNull) {
    for (var i = 0; i < str.length; ++i) {
      assert(str.charCodeAt(i) === str.charCodeAt(i)&0xff);
      HEAP8[((buffer++)>>0)]=str.charCodeAt(i);
    }
    // Null-terminate the pointer to the HEAP.
    if (!dontAddNull) HEAP8[((buffer)>>0)]=0;
  }
  
  
  
  
  
  function demangle(func) {
    return func;
  }
  
  function demangleAll(text) {
    var regex =
      /_Z[\w\d_]+/g;
    return text.replace(regex,
      function(x) {
        var y = demangle(x);
        return x === y ? x : (y + ' [' + x + ']');
      });
  }
  
  function jsStackTrace() {
    var err = new Error();
    if (!err.stack) {
      // IE10+ special cases: It does have callstack info, but it is only populated if an Error object is thrown,
      // so try that as a special-case.
      try {
        throw new Error(0);
      } catch(e) {
        err = e;
      }
      if (!err.stack) {
        return '(no stack trace available)';
      }
    }
    return err.stack.toString();
  }
  
  function stackTrace() {
    var js = jsStackTrace();
    if (Module['extraStackTrace']) js += '\n' + Module['extraStackTrace']();
    return demangleAll(js);
  }
  
  
  
  // Memory management
  
  var PAGE_SIZE = 16384;
  var WASM_PAGE_SIZE = 65536;
  var ASMJS_PAGE_SIZE = 16777216;
  
  function alignUp(x, multiple) {
    if (x % multiple > 0) {
      x += multiple - (x % multiple);
    }
    return x;
  }
  
  var HEAP,
  /** @type {ArrayBuffer} */
    buffer,
  /** @type {Int8Array} */
    HEAP8,
  /** @type {Uint8Array} */
    HEAPU8,
  /** @type {Int16Array} */
    HEAP16,
  /** @type {Uint16Array} */
    HEAPU16,
  /** @type {Int32Array} */
    HEAP32,
  /** @type {Uint32Array} */
    HEAPU32,
  /** @type {Float32Array} */
    HEAPF32,
  /** @type {Float64Array} */
    HEAPF64;
  
  function updateGlobalBufferViews() {
    Module['HEAP8'] = HEAP8 = new Int8Array(buffer);
    Module['HEAP16'] = HEAP16 = new Int16Array(buffer);
    Module['HEAP32'] = HEAP32 = new Int32Array(buffer);
    Module['HEAPU8'] = HEAPU8 = new Uint8Array(buffer);
    Module['HEAPU16'] = HEAPU16 = new Uint16Array(buffer);
    Module['HEAPU32'] = HEAPU32 = new Uint32Array(buffer);
    Module['HEAPF32'] = HEAPF32 = new Float32Array(buffer);
    Module['HEAPF64'] = HEAPF64 = new Float64Array(buffer);
  }
  
  
  var STATIC_BASE = 1024,
      STACK_BASE = 5979520,
      STACKTOP = STACK_BASE,
      STACK_MAX = 736640,
      DYNAMIC_BASE = 5979520,
      DYNAMICTOP_PTR = 736608;
  
  assert(STACK_BASE % 16 === 0, 'stack must start aligned');
  assert(DYNAMIC_BASE % 16 === 0, 'heap must start aligned');
  
  
  
  var TOTAL_STACK = 5242880;
  if (Module['TOTAL_STACK']) assert(TOTAL_STACK === Module['TOTAL_STACK'], 'the stack size can no longer be determined at runtime')
  
  var INITIAL_TOTAL_MEMORY = Module['TOTAL_MEMORY'] || 16777216;
  if (INITIAL_TOTAL_MEMORY < TOTAL_STACK) err('TOTAL_MEMORY should be larger than TOTAL_STACK, was ' + INITIAL_TOTAL_MEMORY + '! (TOTAL_STACK=' + TOTAL_STACK + ')');
  
  // Initialize the runtime's memory
  // check for full engine support (use string 'subarray' to avoid closure compiler confusion)
  assert(typeof Int32Array !== 'undefined' && typeof Float64Array !== 'undefined' && Int32Array.prototype.subarray !== undefined && Int32Array.prototype.set !== undefined,
         'JS engine does not provide full typed array support');
  
  
  
  
  
  
    if (Module['wasmMemory']) {
      wasmMemory = Module['wasmMemory'];
    } else {
      wasmMemory = new WebAssembly.Memory({
        'initial': INITIAL_TOTAL_MEMORY / WASM_PAGE_SIZE
      });
    }
  
  
  if (wasmMemory) {
    buffer = wasmMemory.buffer;
  }
  
  // If the user provides an incorrect length, just use that length instead rather than providing the user to
  // specifically provide the memory length with Module['TOTAL_MEMORY'].
  INITIAL_TOTAL_MEMORY = buffer.byteLength;
  assert(INITIAL_TOTAL_MEMORY % WASM_PAGE_SIZE === 0);
  updateGlobalBufferViews();
  
  HEAP32[DYNAMICTOP_PTR>>2] = DYNAMIC_BASE;
  
  
  // Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode.
  function writeStackCookie() {
    assert((STACK_MAX & 3) == 0);
    // The stack grows downwards
    HEAPU32[(STACK_MAX >> 2)+1] = 0x02135467;
    HEAPU32[(STACK_MAX >> 2)+2] = 0x89BACDFE;
  }
  
  function checkStackCookie() {
    var cookie1 = HEAPU32[(STACK_MAX >> 2)+1];
    var cookie2 = HEAPU32[(STACK_MAX >> 2)+2];
    if (cookie1 != 0x02135467 || cookie2 != 0x89BACDFE) {
      abort('Stack overflow! Stack cookie has been overwritten, expected hex dwords 0x89BACDFE and 0x02135467, but received 0x' + cookie2.toString(16) + ' ' + cookie1.toString(16));
    }
    // Also test the global address 0 for integrity.
    if (HEAP32[0] !== 0x63736d65 /* 'emsc' */) abort('Runtime error: The application has corrupted its heap memory area (address zero)!');
  }
  
  function abortStackOverflow(allocSize) {
    abort('Stack overflow! Attempted to allocate ' + allocSize + ' bytes on the stack, but stack has only ' + (STACK_MAX - stackSave() + allocSize) + ' bytes available!');
  }
  
  
    HEAP32[0] = 0x63736d65; /* 'emsc' */
  
  
  
  // Endianness check (note: assumes compiler arch was little-endian)
  HEAP16[1] = 0x6373;
  if (HEAPU8[2] !== 0x73 || HEAPU8[3] !== 0x63) throw 'Runtime error: expected the system to be little-endian!';
  
  function callRuntimeCallbacks(callbacks) {
    while(callbacks.length > 0) {
      var callback = callbacks.shift();
      if (typeof callback == 'function') {
        callback();
        continue;
      }
      var func = callback.func;
      if (typeof func === 'number') {
        if (callback.arg === undefined) {
          Module['dynCall_v'](func);
        } else {
          Module['dynCall_vi'](func, callback.arg);
        }
      } else {
        func(callback.arg === undefined ? null : callback.arg);
      }
    }
  }
  
  var __ATPRERUN__  = []; // functions called before the runtime is initialized
  var __ATINIT__    = []; // functions called during startup
  var __ATMAIN__    = []; // functions called when main() is to be run
  var __ATEXIT__    = []; // functions called during shutdown
  var __ATPOSTRUN__ = []; // functions called after the main() is called
  
  var runtimeInitialized = false;
  var runtimeExited = false;
  
  
  function preRun() {
    // compatibility - merge in anything from Module['preRun'] at this time
    if (Module['preRun']) {
      if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']];
      while (Module['preRun'].length) {
        addOnPreRun(Module['preRun'].shift());
      }
    }
    callRuntimeCallbacks(__ATPRERUN__);
  }
  
  function initRuntime() {
    checkStackCookie();
    assert(!runtimeInitialized);
    runtimeInitialized = true;
    if (!Module["noFSInit"] && !FS.init.initialized) FS.init();
  TTY.init();
  SOCKFS.root = FS.mount(SOCKFS, {}, null);
  PIPEFS.root = FS.mount(PIPEFS, {}, null);
    callRuntimeCallbacks(__ATINIT__);
  }
  
  function preMain() {
    checkStackCookie();
    FS.ignorePermissions = false;
    callRuntimeCallbacks(__ATMAIN__);
  }
  
  function exitRuntime() {
    checkStackCookie();
    runtimeExited = true;
  }
  
  function postRun() {
    checkStackCookie();
    // compatibility - merge in anything from Module['postRun'] at this time
    if (Module['postRun']) {
      if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']];
      while (Module['postRun'].length) {
        addOnPostRun(Module['postRun'].shift());
      }
    }
    callRuntimeCallbacks(__ATPOSTRUN__);
  }
  
  function addOnPreRun(cb) {
    __ATPRERUN__.unshift(cb);
  }
  
  function addOnInit(cb) {
    __ATINIT__.unshift(cb);
  }
  
  function addOnPreMain(cb) {
    __ATMAIN__.unshift(cb);
  }
  
  function addOnExit(cb) {
  }
  
  function addOnPostRun(cb) {
    __ATPOSTRUN__.unshift(cb);
  }
  
  function unSign(value, bits, ignore) {
    if (value >= 0) {
      return value;
    }
    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
                      : Math.pow(2, bits)         + value;
  }
  function reSign(value, bits, ignore) {
    if (value <= 0) {
      return value;
    }
    var half = bits <= 32 ? Math.abs(1 << (bits-1)) // abs is needed if bits == 32
                          : Math.pow(2, bits-1);
    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
                                                         // but, in general there is no perfect solution here. With 64-bit ints, we get rounding and errors
                                                         // TODO: In i64 mode 1, resign the two parts separately and safely
      value = -2*half + value; // Cannot bitshift half, as it may be at the limit of the bits JS uses in bitshifts
    }
    return value;
  }
  
  
  assert(Math.imul, 'This browser does not support Math.imul(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill');
  assert(Math.fround, 'This browser does not support Math.fround(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill');
  assert(Math.clz32, 'This browser does not support Math.clz32(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill');
  assert(Math.trunc, 'This browser does not support Math.trunc(), build with LEGACY_VM_SUPPORT or POLYFILL_OLD_MATH_FUNCTIONS to add in a polyfill');
  
  var Math_abs = Math.abs;
  var Math_cos = Math.cos;
  var Math_sin = Math.sin;
  var Math_tan = Math.tan;
  var Math_acos = Math.acos;
  var Math_asin = Math.asin;
  var Math_atan = Math.atan;
  var Math_atan2 = Math.atan2;
  var Math_exp = Math.exp;
  var Math_log = Math.log;
  var Math_sqrt = Math.sqrt;
  var Math_ceil = Math.ceil;
  var Math_floor = Math.floor;
  var Math_pow = Math.pow;
  var Math_imul = Math.imul;
  var Math_fround = Math.fround;
  var Math_round = Math.round;
  var Math_min = Math.min;
  var Math_max = Math.max;
  var Math_clz32 = Math.clz32;
  var Math_trunc = Math.trunc;
  
  
  
  // A counter of dependencies for calling run(). If we need to
  // do asynchronous work before running, increment this and
  // decrement it. Incrementing must happen in a place like
  // Module.preRun (used by emcc to add file preloading).
  // Note that you can add dependencies in preRun, even though
  // it happens right before run - run will be postponed until
  // the dependencies are met.
  var runDependencies = 0;
  var runDependencyWatcher = null;
  var dependenciesFulfilled = null; // overridden to take different actions when all run dependencies are fulfilled
  var runDependencyTracking = {};
  
  function getUniqueRunDependency(id) {
    var orig = id;
    while (1) {
      if (!runDependencyTracking[id]) return id;
      id = orig + Math.random();
    }
    return id;
  }
  
  function addRunDependency(id) {
    runDependencies++;
    if (Module['monitorRunDependencies']) {
      Module['monitorRunDependencies'](runDependencies);
    }
    if (id) {
      assert(!runDependencyTracking[id]);
      runDependencyTracking[id] = 1;
      if (runDependencyWatcher === null && typeof setInterval !== 'undefined') {
        // Check for missing dependencies every few seconds
        runDependencyWatcher = setInterval(function() {
          if (ABORT) {
            clearInterval(runDependencyWatcher);
            runDependencyWatcher = null;
            return;
          }
          var shown = false;
          for (var dep in runDependencyTracking) {
            if (!shown) {
              shown = true;
              err('still waiting on run dependencies:');
            }
            err('dependency: ' + dep);
          }
          if (shown) {
            err('(end of list)');
          }
        }, 10000);
      }
    } else {
      err('warning: run dependency added without ID');
    }
  }
  
  function removeRunDependency(id) {
    runDependencies--;
    if (Module['monitorRunDependencies']) {
      Module['monitorRunDependencies'](runDependencies);
    }
    if (id) {
      assert(runDependencyTracking[id]);
      delete runDependencyTracking[id];
    } else {
      err('warning: run dependency removed without ID');
    }
    if (runDependencies == 0) {
      if (runDependencyWatcher !== null) {
        clearInterval(runDependencyWatcher);
        runDependencyWatcher = null;
      }
      if (dependenciesFulfilled) {
        var callback = dependenciesFulfilled;
        dependenciesFulfilled = null;
        callback(); // can add another dependenciesFulfilled
      }
    }
  }
  
  Module["preloadedImages"] = {}; // maps url to image data
  Module["preloadedAudios"] = {}; // maps url to audio data
  
  
  var memoryInitializer = null;
  
  
  
  
  
  
  // Copyright 2017 The Emscripten Authors.  All rights reserved.
  // Emscripten is available under two separate licenses, the MIT license and the
  // University of Illinois/NCSA Open Source License.  Both these licenses can be
  // found in the LICENSE file.
  
  // Prefix of data URIs emitted by SINGLE_FILE and related options.
  var dataURIPrefix = 'data:application/octet-stream;base64,';
  
  // Indicates whether filename is a base64 data URI.
  function isDataURI(filename) {
    return String.prototype.startsWith ?
        filename.startsWith(dataURIPrefix) :
        filename.indexOf(dataURIPrefix) === 0;
  }
  
  
  
  
  var wasmBinaryFile = 'mono-dbg.wasm';
  if (!isDataURI(wasmBinaryFile)) {
    wasmBinaryFile = locateFile(wasmBinaryFile);
  }
  
  function getBinary() {
    try {
      if (Module['wasmBinary']) {
        return new Uint8Array(Module['wasmBinary']);
      }
      if (Module['readBinary']) {
        return Module['readBinary'](wasmBinaryFile);
      } else {
        throw "both async and sync fetching of the wasm failed";
      }
    }
    catch (err) {
      abort(err);
    }
  }
  
  function getBinaryPromise() {
    // if we don't have the binary yet, and have the Fetch api, use that
    // in some environments, like Electron's render process, Fetch api may be present, but have a different context than expected, let's only use it on the Web
    if (!Module['wasmBinary'] && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === 'function') {
      return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function(response) {
        if (!response['ok']) {
          throw "failed to load wasm binary file at '" + wasmBinaryFile + "'";
        }
        return response['arrayBuffer']();
      }).catch(function () {
        return getBinary();
      });
    }
    // Otherwise, getBinary should be able to get it synchronously
    return new Promise(function(resolve, reject) {
      resolve(getBinary());
    });
  }
  
  
  
  // Create the wasm instance.
  // Receives the wasm imports, returns the exports.
  function createWasm(env) {
  
    // prepare imports
    var info = {
      'env': env
    };
    // Load the wasm module and create an instance of using native support in the JS engine.
    // handle a generated wasm instance, receiving its exports and
    // performing other necessary setup
    function receiveInstance(instance, module) {
      var exports = instance.exports;
      Module['asm'] = exports;
      removeRunDependency('wasm-instantiate');
    }
    addRunDependency('wasm-instantiate');
  
  
    // Async compilation can be confusing when an error on the page overwrites Module
    // (for example, if the order of elements is wrong, and the one defining Module is
    // later), so we save Module and check it later.
    var trueModule = Module;
    function receiveInstantiatedSource(output) {
      // 'output' is a WebAssemblyInstantiatedSource object which has both the module and instance.
      // receiveInstance() will swap in the exports (to Module.asm) so they can be called
      assert(Module === trueModule, 'the Module object should not be replaced during async compilation - perhaps the order of HTML elements is wrong?');
      trueModule = null;
        // TODO: Due to Closure regression https://github.com/google/closure-compiler/issues/3193, the above line no longer optimizes out down to the following line.
        // When the regression is fixed, can restore the above USE_PTHREADS-enabled path.
      receiveInstance(output['instance']);
    }
  
  
    function instantiateArrayBuffer(receiver) {
      return getBinaryPromise().then(function(binary) {
        return WebAssembly.instantiate(binary, info);
      }).then(receiver, function(reason) {
        err('failed to asynchronously prepare wasm: ' + reason);
        abort(reason);
      });
    }
  
    // Prefer streaming instantiation if available.
    function instantiateAsync() {
      if (!Module['wasmBinary'] &&
          typeof WebAssembly.instantiateStreaming === 'function' &&
          !isDataURI(wasmBinaryFile) &&
          typeof fetch === 'function') {
        fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(function (response) {
          return WebAssembly.instantiateStreaming(response, info)
            .then(receiveInstantiatedSource, function(reason) {
              // We expect the most common failure cause to be a bad MIME type for the binary,
              // in which case falling back to ArrayBuffer instantiation should work.
              err('wasm streaming compile failed: ' + reason);
              err('falling back to ArrayBuffer instantiation');
              instantiateArrayBuffer(receiveInstantiatedSource);
            });
        });
      } else {
        return instantiateArrayBuffer(receiveInstantiatedSource);
      }
    }
    // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback
    // to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel
    // to any other async startup actions they are performing.
    if (Module['instantiateWasm']) {
      try {
        return Module['instantiateWasm'](info, receiveInstance);
      } catch(e) {
        err('Module.instantiateWasm callback failed with error: ' + e);
        return false;
      }
    }
  
    instantiateAsync();
    return {}; // no exports yet; we'll fill them in later
  }
  
  // Provide an "asm.js function" for the application, called to "link" the asm.js module. We instantiate
  // the wasm module at that time, and it receives imports and provides exports and so forth, the app
  // doesn't need to care that it is wasm or asm.js.
  
  Module['asm'] = function(global, env, providedBuffer) {
    // memory was already allocated (so js could use the buffer)
    env['memory'] = wasmMemory
    ;
    // import table
    env['table'] = wasmTable = new WebAssembly.Table({
      'initial': 1696,
      'maximum': 1696 + 0,
      'element': 'anyfunc'
    });
    // With the wasm backend __memory_base and __table_base and only needed for
    // relocatable output.
  
    var exports = createWasm(env);
    assert(exports, 'binaryen setup failed (no wasm support?)');
    return exports;
  };
  
  // === Body ===
  
  var ASM_CONSTS = [function($0, $1) {var str = UTF8ToString ($0); try { var res = eval (str); if (res === null || res == undefined) return 0; res = res.toString (); setValue ($1, 0, "i32"); } catch (e) { res = e.toString (); setValue ($1, 1, "i32"); if (res === null || res === undefined) res = "unknown exception"; } var buff = Module._malloc((res.length + 1) * 2); stringToUTF16 (res, buff, (res.length + 1) * 2); return buff;},
   function() {var err = new Error(); console.log ("Stacktrace: \n"); console.log (err.stack);},
   function() {return STACK_MAX;},
   function() {return TOTAL_STACK;}];
  
  function _emscripten_asm_const_iii(code, sig_ptr, argbuf) {
    var sig = AsciiToString(sig_ptr);
    var args = [];
    var align_to = function(ptr, align) {
      return (ptr+align-1) & ~(align-1);
    };
    var buf = argbuf;
    for (var i = 0; i < sig.length; i++) {
      var c = sig[i];
      if (c == 'd' || c == 'f') {
        buf = align_to(buf, 8);
        args.push(HEAPF64[(buf >> 3)]);
        buf += 8;
      } else if (c == 'i') {
        buf = align_to(buf, 4);
        args.push(HEAP32[(buf >> 2)]);
        buf += 4;
      }
    }
    return ASM_CONSTS[code].apply(null, args);
  }
  
  
  
  // STATICTOP = STATIC_BASE + 735616;
  /* global initializers */  __ATINIT__.push({ func: function() { ___wasm_call_ctors() } });
  
  
  
  /* no memory initializer */
  var tempDoublePtr = 736624
  assert(tempDoublePtr % 8 == 0);
  
  function copyTempFloat(ptr) { // functions, because inlining this code increases code size too much
    HEAP8[tempDoublePtr] = HEAP8[ptr];
    HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
    HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
    HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
  }
  
  function copyTempDouble(ptr) {
    HEAP8[tempDoublePtr] = HEAP8[ptr];
    HEAP8[tempDoublePtr+1] = HEAP8[ptr+1];
    HEAP8[tempDoublePtr+2] = HEAP8[ptr+2];
    HEAP8[tempDoublePtr+3] = HEAP8[ptr+3];
    HEAP8[tempDoublePtr+4] = HEAP8[ptr+4];
    HEAP8[tempDoublePtr+5] = HEAP8[ptr+5];
    HEAP8[tempDoublePtr+6] = HEAP8[ptr+6];
    HEAP8[tempDoublePtr+7] = HEAP8[ptr+7];
  }
  
  // {{PRE_LIBRARY}}
  
  
    function ___assert_fail(condition, filename, line, func) {
        abort('Assertion failed: ' + UTF8ToString(condition) + ', at: ' + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']);
      }
  
    
    var ENV={};function ___buildEnvironment(environ) {
        // WARNING: Arbitrary limit!
        var MAX_ENV_VALUES = 64;
        var TOTAL_ENV_SIZE = 1024;
    
        // Statically allocate memory for the environment.
        var poolPtr;
        var envPtr;
        if (!___buildEnvironment.called) {
          ___buildEnvironment.called = true;
          // Set default values. Use string keys for Closure Compiler compatibility.
          ENV['USER'] = ENV['LOGNAME'] = 'web_user';
          ENV['PATH'] = '/';
          ENV['PWD'] = '/';
          ENV['HOME'] = '/home/web_user';
          ENV['LANG'] = 'C.UTF-8';
          // Browser language detection #8751
          ENV['LANG'] = ((typeof navigator === 'object' && navigator.languages && navigator.languages[0]) || 'C').replace('-', '_') + '.UTF-8';
          ENV['_'] = Module['thisProgram'];
          // Allocate memory.
          poolPtr = getMemory(TOTAL_ENV_SIZE);
          envPtr = getMemory(MAX_ENV_VALUES * 4);
          HEAP32[((envPtr)>>2)]=poolPtr;
          HEAP32[((environ)>>2)]=envPtr;
        } else {
          envPtr = HEAP32[((environ)>>2)];
          poolPtr = HEAP32[((envPtr)>>2)];
        }
    
        // Collect key=value lines.
        var strings = [];
        var totalSize = 0;
        for (var key in ENV) {
          if (typeof ENV[key] === 'string') {
            var line = key + '=' + ENV[key];
            strings.push(line);
            totalSize += line.length;
          }
        }
        if (totalSize > TOTAL_ENV_SIZE) {
          throw new Error('Environment size exceeded TOTAL_ENV_SIZE!');
        }
    
        // Make new.
        var ptrSize = 4;
        for (var i = 0; i < strings.length; i++) {
          var line = strings[i];
          writeAsciiToMemory(line, poolPtr);
          HEAP32[(((envPtr)+(i * ptrSize))>>2)]=poolPtr;
          poolPtr += line.length + 1;
        }
        HEAP32[(((envPtr)+(strings.length * ptrSize))>>2)]=0;
      }
  
    
    
    function _emscripten_get_now() { abort() }
    
    function _emscripten_get_now_is_monotonic() {
        // return whether emscripten_get_now is guaranteed monotonic; the Date.now
        // implementation is not :(
        return (0
          || ENVIRONMENT_IS_NODE
          || (typeof dateNow !== 'undefined')
          || (typeof performance === 'object' && performance && typeof performance['now'] === 'function')
          );
      }
    
    function ___setErrNo(value) {
        if (Module['___errno_location']) HEAP32[((Module['___errno_location']())>>2)]=value;
        else err('failed to set errno from JS');
        return value;
      }function _clock_gettime(clk_id, tp) {
        // int clock_gettime(clockid_t clk_id, struct timespec *tp);
        var now;
        if (clk_id === 0) {
          now = Date.now();
        } else if (clk_id === 1 && _emscripten_get_now_is_monotonic()) {
          now = _emscripten_get_now();
        } else {
          ___setErrNo(22);
          return -1;
        }
        HEAP32[((tp)>>2)]=(now/1000)|0; // seconds
        HEAP32[(((tp)+(4))>>2)]=((now % 1000)*1000*1000)|0; // nanoseconds
        return 0;
      }function ___clock_gettime(a0,a1
    /*``*/) {
    return _clock_gettime(a0,a1);
    }
  
    function ___cxa_allocate_exception(size) {
        return _malloc(size);
      }
  
    
    var ___exception_infos={};
    
    var ___exception_caught= [];
    
    function ___exception_addRef(ptr) {
        if (!ptr) return;
        var info = ___exception_infos[ptr];
        info.refcount++;
      }
    
    function ___exception_deAdjust(adjusted) {
        if (!adjusted || ___exception_infos[adjusted]) return adjusted;
        for (var key in ___exception_infos) {
          var ptr = +key; // the iteration key is a string, and if we throw this, it must be an integer as that is what we look for
          var adj = ___exception_infos[ptr].adjusted;
          var len = adj.length;
          for (var i = 0; i < len; i++) {
            if (adj[i] === adjusted) {
              return ptr;
            }
          }
        }
        return adjusted;
      }function ___cxa_begin_catch(ptr) {
        var info = ___exception_infos[ptr];
        if (info && !info.caught) {
          info.caught = true;
          __ZSt18uncaught_exceptionv.uncaught_exception--;
        }
        if (info) info.rethrown = false;
        ___exception_caught.push(ptr);
        ___exception_addRef(___exception_deAdjust(ptr));
        return ptr;
      }
  
    
    var ___exception_last=0;
    
    
    function ___cxa_free_exception(ptr) {
        try {
          return _free(ptr);
        } catch(e) {
          err('exception during cxa_free_exception: ' + e);
        }
      }function ___exception_decRef(ptr) {
        if (!ptr) return;
        var info = ___exception_infos[ptr];
        assert(info.refcount > 0);
        info.refcount--;
        // A rethrown exception can reach refcount 0; it must not be discarded
        // Its next handler will clear the rethrown flag and addRef it, prior to
        // final decRef and destruction here
        if (info.refcount === 0 && !info.rethrown) {
          if (info.destructor) {
            // In Wasm, destructors return 'this' as in ARM
            Module['dynCall_ii'](info.destructor, ptr);
          }
          delete ___exception_infos[ptr];
          ___cxa_free_exception(ptr);
        }
      }function ___cxa_end_catch() {
        // Clear state flag.
        _setThrew(0);
        // Call destructor if one is registered then clear it.
        var ptr = ___exception_caught.pop();
        if (ptr) {
          ___exception_decRef(___exception_deAdjust(ptr));
          ___exception_last = 0; // XXX in decRef?
        }
      }
  
    
    
    function ___resumeException(ptr) {
        if (!___exception_last) { ___exception_last = ptr; }
        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.";
      }function ___cxa_find_matching_catch() {
        var thrown = ___exception_last;
        if (!thrown) {
          // just pass through the null ptr
          return ((setTempRet0(0),0)|0);
        }
        var info = ___exception_infos[thrown];
        var throwntype = info.type;
        if (!throwntype) {
          // just pass through the thrown ptr
          return ((setTempRet0(0),thrown)|0);
        }
        var typeArray = Array.prototype.slice.call(arguments);
    
        var pointer = ___cxa_is_pointer_type(throwntype);
        // can_catch receives a **, add indirection
        if (!___cxa_find_matching_catch.buffer) ___cxa_find_matching_catch.buffer = _malloc(4);
        HEAP32[((___cxa_find_matching_catch.buffer)>>2)]=thrown;
        thrown = ___cxa_find_matching_catch.buffer;
        // The different catch blocks are denoted by different types.
        // Due to inheritance, those types may not precisely match the
        // type of the thrown object. Find one which matches, and
        // return the type of the catch block which should be called.
        for (var i = 0; i < typeArray.length; i++) {
          if (typeArray[i] && ___cxa_can_catch(typeArray[i], throwntype, thrown)) {
            thrown = HEAP32[((thrown)>>2)]; // undo indirection
            info.adjusted.push(thrown);
            return ((setTempRet0(typeArray[i]),thrown)|0);
          }
        }
        // Shouldn't happen unless we have bogus data in typeArray
        // or encounter a type for which emscripten doesn't have suitable
        // typeinfo defined. Best-efforts match just in case.
        thrown = HEAP32[((thrown)>>2)]; // undo indirection
        return ((setTempRet0(throwntype),thrown)|0);
      }function ___cxa_find_matching_catch_3(a0,a1,a2
    /*``*/) {
    return ___cxa_find_matching_catch(a0,a1,a2);
    }
  
    function ___cxa_throw(ptr, type, destructor) {
        ___exception_infos[ptr] = {
          ptr: ptr,
          adjusted: [ptr],
          type: type,
          destructor: destructor,
          refcount: 0,
          caught: false,
          rethrown: false
        };
        ___exception_last = ptr;
        if (!("uncaught_exception" in __ZSt18uncaught_exceptionv)) {
          __ZSt18uncaught_exceptionv.uncaught_exception = 1;
        } else {
          __ZSt18uncaught_exceptionv.uncaught_exception++;
        }
        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.";
      }
  
    function ___cxa_uncaught_exception() {
        return !!__ZSt18uncaught_exceptionv.uncaught_exception;
      }
  
    function ___lock() {}
  
    function ___map_file(pathname, size) {
        ___setErrNo(1);
        return -1;
      }
  
  
    
    
    var PATH={splitPath:function (filename) {
          var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
          return splitPathRe.exec(filename).slice(1);
        },normalizeArray:function (parts, allowAboveRoot) {
          // if the path tries to go above the root, `up` ends up > 0
          var up = 0;
          for (var i = parts.length - 1; i >= 0; i--) {
            var last = parts[i];
            if (last === '.') {
              parts.splice(i, 1);
            } else if (last === '..') {
              parts.splice(i, 1);
              up++;
            } else if (up) {
              parts.splice(i, 1);
              up--;
            }
          }
          // if the path is allowed to go above the root, restore leading ..s
          if (allowAboveRoot) {
            for (; up; up--) {
              parts.unshift('..');
            }
          }
          return parts;
        },normalize:function (path) {
          var isAbsolute = path.charAt(0) === '/',
              trailingSlash = path.substr(-1) === '/';
          // Normalize the path
          path = PATH.normalizeArray(path.split('/').filter(function(p) {
            return !!p;
          }), !isAbsolute).join('/');
          if (!path && !isAbsolute) {
            path = '.';
          }
          if (path && trailingSlash) {
            path += '/';
          }
          return (isAbsolute ? '/' : '') + path;
        },dirname:function (path) {
          var result = PATH.splitPath(path),
              root = result[0],
              dir = result[1];
          if (!root && !dir) {
            // No dirname whatsoever
            return '.';
          }
          if (dir) {
            // It has a dirname, strip trailing slash
            dir = dir.substr(0, dir.length - 1);
          }
          return root + dir;
        },basename:function (path) {
          // EMSCRIPTEN return '/'' for '/', not an empty string
          if (path === '/') return '/';
          var lastSlash = path.lastIndexOf('/');
          if (lastSlash === -1) return path;
          return path.substr(lastSlash+1);
        },extname:function (path) {
          return PATH.splitPath(path)[3];
        },join:function () {
          var paths = Array.prototype.slice.call(arguments, 0);
          return PATH.normalize(paths.join('/'));
        },join2:function (l, r) {
          return PATH.normalize(l + '/' + r);
        }};
    
    
    var PATH_FS={resolve:function () {
          var resolvedPath = '',
            resolvedAbsolute = false;
          for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
            var path = (i >= 0) ? arguments[i] : FS.cwd();
            // Skip empty and invalid entries
            if (typeof path !== 'string') {
              throw new TypeError('Arguments to path.resolve must be strings');
            } else if (!path) {
              return ''; // an invalid portion invalidates the whole thing
            }
            resolvedPath = path + '/' + resolvedPath;
            resolvedAbsolute = path.charAt(0) === '/';
          }
          // At this point the path should be resolved to a full absolute path, but
          // handle relative paths to be safe (might happen when process.cwd() fails)
          resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter(function(p) {
            return !!p;
          }), !resolvedAbsolute).join('/');
          return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
        },relative:function (from, to) {
          from = PATH_FS.resolve(from).substr(1);
          to = PATH_FS.resolve(to).substr(1);
          function trim(arr) {
            var start = 0;
            for (; start < arr.length; start++) {
              if (arr[start] !== '') break;
            }
            var end = arr.length - 1;
            for (; end >= 0; end--) {
              if (arr[end] !== '') break;
            }
            if (start > end) return [];
            return arr.slice(start, end - start + 1);
          }
          var fromParts = trim(from.split('/'));
          var toParts = trim(to.split('/'));
          var length = Math.min(fromParts.length, toParts.length);
          var samePartsLength = length;
          for (var i = 0; i < length; i++) {
            if (fromParts[i] !== toParts[i]) {
              samePartsLength = i;
              break;
            }
          }
          var outputParts = [];
          for (var i = samePartsLength; i < fromParts.length; i++) {
            outputParts.push('..');
          }
          outputParts = outputParts.concat(toParts.slice(samePartsLength));
          return outputParts.join('/');
        }};
    
    var TTY={ttys:[],init:function () {
          // https://github.com/emscripten-core/emscripten/pull/1555
          // if (ENVIRONMENT_IS_NODE) {
          //   // currently, FS.init does not distinguish if process.stdin is a file or TTY
          //   // device, it always assumes it's a TTY device. because of this, we're forcing
          //   // process.stdin to UTF8 encoding to at least make stdin reading compatible
          //   // with text files until FS.init can be refactored.
          //   process['stdin']['setEncoding']('utf8');
          // }
        },shutdown:function () {
          // https://github.com/emscripten-core/emscripten/pull/1555
          // if (ENVIRONMENT_IS_NODE) {
          //   // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)?
          //   // 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
          //   // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists?
          //   // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle
          //   // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call
          //   process['stdin']['pause']();
          // }
        },register:function (dev, ops) {
          TTY.ttys[dev] = { input: [], output: [], ops: ops };
          FS.registerDevice(dev, TTY.stream_ops);
        },stream_ops:{open:function (stream) {
            var tty = TTY.ttys[stream.node.rdev];
            if (!tty) {
              throw new FS.ErrnoError(19);
            }
            stream.tty = tty;
            stream.seekable = false;
          },close:function (stream) {
            // flush any pending line data
            stream.tty.ops.flush(stream.tty);
          },flush:function (stream) {
            stream.tty.ops.flush(stream.tty);
          },read:function (stream, buffer, offset, length, pos /* ignored */) {
            if (!stream.tty || !stream.tty.ops.get_char) {
              throw new FS.ErrnoError(6);
            }
            var bytesRead = 0;
            for (var i = 0; i < length; i++) {
              var result;
              try {
                result = stream.tty.ops.get_char(stream.tty);
              } catch (e) {
                throw new FS.ErrnoError(5);
              }
              if (result === undefined && bytesRead === 0) {
                throw new FS.ErrnoError(11);
              }
              if (result === null || result === undefined) break;
              bytesRead++;
              buffer[offset+i] = result;
            }
            if (bytesRead) {
              stream.node.timestamp = Date.now();
            }
            return bytesRead;
          },write:function (stream, buffer, offset, length, pos) {
            if (!stream.tty || !stream.tty.ops.put_char) {
              throw new FS.ErrnoError(6);
            }
            try {
              for (var i = 0; i < length; i++) {
                stream.tty.ops.put_char(stream.tty, buffer[offset+i]);
              }
            } catch (e) {
              throw new FS.ErrnoError(5);
            }
            if (length) {
              stream.node.timestamp = Date.now();
            }
            return i;
          }},default_tty_ops:{get_char:function (tty) {
            if (!tty.input.length) {
              var result = null;
              if (ENVIRONMENT_IS_NODE) {
                // we will read data by chunks of BUFSIZE
                var BUFSIZE = 256;
                var buf = new Buffer(BUFSIZE);
                var bytesRead = 0;
    
                var isPosixPlatform = (process.platform != 'win32'); // Node doesn't offer a direct check, so test by exclusion
    
                var fd = process.stdin.fd;
                if (isPosixPlatform) {
                  // Linux and Mac cannot use process.stdin.fd (which isn't set up as sync)
                  var usingDevice = false;
                  try {
                    fd = fs.openSync('/dev/stdin', 'r');
                    usingDevice = true;
                  } catch (e) {}
                }
    
                try {
                  bytesRead = fs.readSync(fd, buf, 0, BUFSIZE, null);
                } catch(e) {
                  // Cross-platform differences: on Windows, reading EOF throws an exception, but on other OSes,
                  // reading EOF returns 0. Uniformize behavior by treating the EOF exception to return 0.
                  if (e.toString().indexOf('EOF') != -1) bytesRead = 0;
                  else throw e;
                }
    
                if (usingDevice) { fs.closeSync(fd); }
                if (bytesRead > 0) {
                  result = buf.slice(0, bytesRead).toString('utf-8');
                } else {
                  result = null;
                }
              } else
              if (typeof window != 'undefined' &&
                typeof window.prompt == 'function') {
                // Browser.
                result = window.prompt('Input: ');  // returns null on cancel
                if (result !== null) {
                  result += '\n';
                }
              } else if (typeof readline == 'function') {
                // Command line.
                result = readline();
                if (result !== null) {
                  result += '\n';
                }
              }
              if (!result) {
                return null;
              }
              tty.input = intArrayFromString(result, true);
            }
            return tty.input.shift();
          },put_char:function (tty, val) {
            if (val === null || val === 10) {
              out(UTF8ArrayToString(tty.output, 0));
              tty.output = [];
            } else {
              if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle.
            }
          },flush:function (tty) {
            if (tty.output && tty.output.length > 0) {
              out(UTF8ArrayToString(tty.output, 0));
              tty.output = [];
            }
          }},default_tty1_ops:{put_char:function (tty, val) {
            if (val === null || val === 10) {
              err(UTF8ArrayToString(tty.output, 0));
              tty.output = [];
            } else {
              if (val != 0) tty.output.push(val);
            }
          },flush:function (tty) {
            if (tty.output && tty.output.length > 0) {
              err(UTF8ArrayToString(tty.output, 0));
              tty.output = [];
            }
          }}};
    
    var MEMFS={ops_table:null,mount:function (mount) {
          return MEMFS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
        },createNode:function (parent, name, mode, dev) {
          if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {
            // no supported
            throw new FS.ErrnoError(1);
          }
          if (!MEMFS.ops_table) {
            MEMFS.ops_table = {
              dir: {
                node: {
                  getattr: MEMFS.node_ops.getattr,
                  setattr: MEMFS.node_ops.setattr,
                  lookup: MEMFS.node_ops.lookup,
                  mknod: MEMFS.node_ops.mknod,
                  rename: MEMFS.node_ops.rename,
                  unlink: MEMFS.node_ops.unlink,
                  rmdir: MEMFS.node_ops.rmdir,
                  readdir: MEMFS.node_ops.readdir,
                  symlink: MEMFS.node_ops.symlink
                },
                stream: {
                  llseek: MEMFS.stream_ops.llseek
                }
              },
              file: {
                node: {
                  getattr: MEMFS.node_ops.getattr,
                  setattr: MEMFS.node_ops.setattr
                },
                stream: {
                  llseek: MEMFS.stream_ops.llseek,
                  read: MEMFS.stream_ops.read,
                  write: MEMFS.stream_ops.write,
                  allocate: MEMFS.stream_ops.allocate,
                  mmap: MEMFS.stream_ops.mmap,
                  msync: MEMFS.stream_ops.msync
                }
              },
              link: {
                node: {
                  getattr: MEMFS.node_ops.getattr,
                  setattr: MEMFS.node_ops.setattr,
                  readlink: MEMFS.node_ops.readlink
                },
                stream: {}
              },
              chrdev: {
                node: {
                  getattr: MEMFS.node_ops.getattr,
                  setattr: MEMFS.node_ops.setattr
                },
                stream: FS.chrdev_stream_ops
              }
            };
          }
          var node = FS.createNode(parent, name, mode, dev);
          if (FS.isDir(node.mode)) {
            node.node_ops = MEMFS.ops_table.dir.node;
            node.stream_ops = MEMFS.ops_table.dir.stream;
            node.contents = {};
          } else if (FS.isFile(node.mode)) {
            node.node_ops = MEMFS.ops_table.file.node;
            node.stream_ops = MEMFS.ops_table.file.stream;
            node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity.
            // 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
            // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size
            // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme.
            node.contents = null; 
          } else if (FS.isLink(node.mode)) {
            node.node_ops = MEMFS.ops_table.link.node;
            node.stream_ops = MEMFS.ops_table.link.stream;
          } else if (FS.isChrdev(node.mode)) {
            node.node_ops = MEMFS.ops_table.chrdev.node;
            node.stream_ops = MEMFS.ops_table.chrdev.stream;
          }
          node.timestamp = Date.now();
          // add the new node to the parent
          if (parent) {
            parent.contents[name] = node;
          }
          return node;
        },getFileDataAsRegularArray:function (node) {
          if (node.contents && node.contents.subarray) {
            var arr = [];
            for (var i = 0; i < node.usedBytes; ++i) arr.push(node.contents[i]);
            return arr; // Returns a copy of the original data.
          }
          return node.contents; // No-op, the file contents are already in a JS array. Return as-is.
        },getFileDataAsTypedArray:function (node) {
          if (!node.contents) return new Uint8Array;
          if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes); // Make sure to not return excess unused bytes.
          return new Uint8Array(node.contents);
        },expandFileStorage:function (node, newCapacity) {
          var prevCapacity = node.contents ? node.contents.length : 0;
          if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough.
          // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity.
          // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to
          // avoid overshooting the allocation cap by a very large margin.
          var CAPACITY_DOUBLING_MAX = 1024 * 1024;
          newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) | 0);
          if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding.
          var oldContents = node.contents;
          node.contents = new Uint8Array(newCapacity); // Allocate new storage.
          if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); // Copy old data over to the new storage.
          return;
        },resizeFileStorage:function (node, newSize) {
          if (node.usedBytes == newSize) return;
          if (newSize == 0) {
            node.contents = null; // Fully decommit when requesting a resize to zero.
            node.usedBytes = 0;
            return;
          }
          if (!node.contents || node.contents.subarray) { // Resize a typed array if that is being used as the backing store.
            var oldContents = node.contents;
            node.contents = new Uint8Array(new ArrayBuffer(newSize)); // Allocate new storage.
            if (oldContents) {
              node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); // Copy old data over to the new storage.
            }
            node.usedBytes = newSize;
            return;
          }
          // Backing with a JS array.
          if (!node.contents) node.contents = [];
          if (node.contents.length > newSize) node.contents.length = newSize;
          else while (node.contents.length < newSize) node.contents.push(0);
          node.usedBytes = newSize;
        },node_ops:{getattr:function (node) {
            var attr = {};
            // device numbers reuse inode numbers.
            attr.dev = FS.isChrdev(node.mode) ? node.id : 1;
            attr.ino = node.id;
            attr.mode = node.mode;
            attr.nlink = 1;
            attr.uid = 0;
            attr.gid = 0;
            attr.rdev = node.rdev;
            if (FS.isDir(node.mode)) {
              attr.size = 4096;
            } else if (FS.isFile(node.mode)) {
              attr.size = node.usedBytes;
            } else if (FS.isLink(node.mode)) {
              attr.size = node.link.length;
            } else {
              attr.size = 0;
            }
            attr.atime = new Date(node.timestamp);
            attr.mtime = new Date(node.timestamp);
            attr.ctime = new Date(node.timestamp);
            // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize),
            //       but this is not required by the standard.
            attr.blksize = 4096;
            attr.blocks = Math.ceil(attr.size / attr.blksize);
            return attr;
          },setattr:function (node, attr) {
            if (attr.mode !== undefined) {
              node.mode = attr.mode;
            }
            if (attr.timestamp !== undefined) {
              node.timestamp = attr.timestamp;
            }
            if (attr.size !== undefined) {
              MEMFS.resizeFileStorage(node, attr.size);
            }
          },lookup:function (parent, name) {
            throw FS.genericErrors[2];
          },mknod:function (parent, name, mode, dev) {
            return MEMFS.createNode(parent, name, mode, dev);
          },rename:function (old_node, new_dir, new_name) {
            // if we're overwriting a directory at new_name, make sure it's empty.
            if (FS.isDir(old_node.mode)) {
              var new_node;
              try {
                new_node = FS.lookupNode(new_dir, new_name);
              } catch (e) {
              }
              if (new_node) {
                for (var i in new_node.contents) {
                  throw new FS.ErrnoError(39);
                }
              }
            }
            // do the internal rewiring
            delete old_node.parent.contents[old_node.name];
            old_node.name = new_name;
            new_dir.contents[new_name] = old_node;
            old_node.parent = new_dir;
          },unlink:function (parent, name) {
            delete parent.contents[name];
          },rmdir:function (parent, name) {
            var node = FS.lookupNode(parent, name);
            for (var i in node.contents) {
              throw new FS.ErrnoError(39);
            }
            delete parent.contents[name];
          },readdir:function (node) {
            var entries = ['.', '..']
            for (var key in node.contents) {
              if (!node.contents.hasOwnProperty(key)) {
                continue;
              }
              entries.push(key);
            }
            return entries;
          },symlink:function (parent, newname, oldpath) {
            var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | 40960, 0);
            node.link = oldpath;
            return node;
          },readlink:function (node) {
            if (!FS.isLink(node.mode)) {
              throw new FS.ErrnoError(22);
            }
            return node.link;
          }},stream_ops:{read:function (stream, buffer, offset, length, position) {
            var contents = stream.node.contents;
            if (position >= stream.node.usedBytes) return 0;
            var size = Math.min(stream.node.usedBytes - position, length);
            assert(size >= 0);
            if (size > 8 && contents.subarray) { // non-trivial, and typed array
              buffer.set(contents.subarray(position, position + size), offset);
            } else {
              for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i];
            }
            return size;
          },write:function (stream, buffer, offset, length, position, canOwn) {
            // If memory can grow, we don't want to hold on to references of
            // the memory Buffer, as they may get invalidated. That means
            // we need to do a copy here.
            // FIXME: this is inefficient as the file packager may have
            //        copied the data into memory already - we may want to
            //        integrate more there and let the file packager loading
            //        code be able to query if memory growth is on or off.
            if (canOwn) {
              warnOnce('file packager has copied file data into memory, but in memory growth we are forced to copy it again (see --no-heap-copy)');
            }
            canOwn = false;
    
            if (!length) return 0;
            var node = stream.node;
            node.timestamp = Date.now();
    
            if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array?
              if (canOwn) {
                assert(position === 0, 'canOwn must imply no weird position inside the file');
                node.contents = buffer.subarray(offset, offset + length);
                node.usedBytes = length;
                return length;
              } 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.
                node.contents = new Uint8Array(buffer.subarray(offset, offset + length));
                node.usedBytes = length;
                return length;
              } else if (position + length <= node.usedBytes) { // Writing to an already allocated and used subrange of the file?
                node.contents.set(buffer.subarray(offset, offset + length), position);
                return length;
              }
            }
    
            // Appending to an existing file and we need to reallocate, or source data did not come as a typed array.
            MEMFS.expandFileStorage(node, position+length);
            if (node.contents.subarray && buffer.subarray) node.contents.set(buffer.subarray(offset, offset + length), position); // Use typed array write if available.
            else {
              for (var i = 0; i < length; i++) {
               node.contents[position + i] = buffer[offset + i]; // Or fall back to manual write if not.
              }
            }
            node.usedBytes = Math.max(node.usedBytes, position+length);
            return length;
          },llseek:function (stream, offset, whence) {
            var position = offset;
            if (whence === 1) {  // SEEK_CUR.
              position += stream.position;
            } else if (whence === 2) {  // SEEK_END.
              if (FS.isFile(stream.node.mode)) {
                position += stream.node.usedBytes;
              }
            }
            if (position < 0) {
              throw new FS.ErrnoError(22);
            }
            return position;
          },allocate:function (stream, offset, length) {
            MEMFS.expandFileStorage(stream.node, offset + length);
            stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length);
          },mmap:function (stream, buffer, offset, length, position, prot, flags) {
            if (!FS.isFile(stream.node.mode)) {
              throw new FS.ErrnoError(19);
            }
            var ptr;
            var allocated;
            var contents = stream.node.contents;
            // Only make a new copy when MAP_PRIVATE is specified.
            if ( !(flags & 2) &&
                  (contents.buffer === buffer || contents.buffer === buffer.buffer) ) {
              // We can't emulate MAP_SHARED when the file is not backed by the buffer
              // we're mapping to (e.g. the HEAP buffer).
              allocated = false;
              ptr = contents.byteOffset;
            } else {
              // Try to avoid unnecessary slices.
              if (position > 0 || position + length < stream.node.usedBytes) {
                if (contents.subarray) {
                  contents = contents.subarray(position, position + length);
                } else {
                  contents = Array.prototype.slice.call(contents, position, position + length);
                }
              }
              allocated = true;
              ptr = _malloc(length);
              if (!ptr) {
                throw new FS.ErrnoError(12);
              }
              buffer.set(contents, ptr);
            }
            return { ptr: ptr, allocated: allocated };
          },msync:function (stream, buffer, offset, length, mmapFlags) {
            if (!FS.isFile(stream.node.mode)) {
              throw new FS.ErrnoError(19);
            }
            if (mmapFlags & 2) {
              // MAP_PRIVATE calls need not to be synced back to underlying fs
              return 0;
            }
    
            var bytesWritten = MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false);
            // should we check if bytesWritten and length are the same?
            return 0;
          }}};
    
    var IDBFS={dbs:{},indexedDB:function () {
          if (typeof indexedDB !== 'undefined') return indexedDB;
          var ret = null;
          if (typeof window === 'object') ret = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
          assert(ret, 'IDBFS used, but indexedDB not supported');
          return ret;
        },DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function (mount) {
          // reuse all of the core MEMFS functionality
          return MEMFS.mount.apply(null, arguments);
        },syncfs:function (mount, populate, callback) {
          IDBFS.getLocalSet(mount, function(err, local) {
            if (err) return callback(err);
    
            IDBFS.getRemoteSet(mount, function(err, remote) {
              if (err) return callback(err);
    
              var src = populate ? remote : local;
              var dst = populate ? local : remote;
    
              IDBFS.reconcile(src, dst, callback);
            });
          });
        },getDB:function (name, callback) {
          // check the cache first
          var db = IDBFS.dbs[name];
          if (db) {
            return callback(null, db);
          }
    
          var req;
          try {
            req = IDBFS.indexedDB().open(name, IDBFS.DB_VERSION);
          } catch (e) {
            return callback(e);
          }
          if (!req) {
            return callback("Unable to connect to IndexedDB");
          }
          req.onupgradeneeded = function(e) {
            var db = e.target.result;
            var transaction = e.target.transaction;
    
            var fileStore;
    
            if (db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)) {
              fileStore = transaction.objectStore(IDBFS.DB_STORE_NAME);
            } else {
              fileStore = db.createObjectStore(IDBFS.DB_STORE_NAME);
            }
    
            if (!fileStore.indexNames.contains('timestamp')) {
              fileStore.createIndex('timestamp', 'timestamp', { unique: false });
            }
          };
          req.onsuccess = function() {
            db = req.result;
    
            // add to the cache
            IDBFS.dbs[name] = db;
            callback(null, db);
          };
          req.onerror = function(e) {
            callback(this.error);
            e.preventDefault();
          };
        },getLocalSet:function (mount, callback) {
          var entries = {};
    
          function isRealDir(p) {
            return p !== '.' && p !== '..';
          };
          function toAbsolute(root) {
            return function(p) {
              return PATH.join2(root, p);
            }
          };
    
          var check = FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));
    
          while (check.length) {
            var path = check.pop();
            var stat;
    
            try {
              stat = FS.stat(path);
            } catch (e) {
              return callback(e);
            }
    
            if (FS.isDir(stat.mode)) {
              check.push.apply(check, FS.readdir(path).filter(isRealDir).map(toAbsolute(path)));
            }
    
            entries[path] = { timestamp: stat.mtime };
          }
    
          return callback(null, { type: 'local', entries: entries });
        },getRemoteSet:function (mount, callback) {
          var entries = {};
    
          IDBFS.getDB(mount.mountpoint, function(err, db) {
            if (err) return callback(err);
    
            try {
              var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readonly');
              transaction.onerror = function(e) {
                callback(this.error);
                e.preventDefault();
              };
    
              var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
              var index = store.index('timestamp');
    
              index.openKeyCursor().onsuccess = function(event) {
                var cursor = event.target.result;
    
                if (!cursor) {
                  return callback(null, { type: 'remote', db: db, entries: entries });
                }
    
                entries[cursor.primaryKey] = { timestamp: cursor.key };
    
                cursor.continue();
              };
            } catch (e) {
              return callback(e);
            }
          });
        },loadLocalEntry:function (path, callback) {
          var stat, node;
    
          try {
            var lookup = FS.lookupPath(path);
            node = lookup.node;
            stat = FS.stat(path);
          } catch (e) {
            return callback(e);
          }
    
          if (FS.isDir(stat.mode)) {
            return callback(null, { timestamp: stat.mtime, mode: stat.mode });
          } else if (FS.isFile(stat.mode)) {
            // Performance consideration: storing a normal JavaScript array to a IndexedDB is much slower than storing a typed array.
            // Therefore always convert the file contents to a typed array first before writing the data to IndexedDB.
            node.contents = MEMFS.getFileDataAsTypedArray(node);
            return callback(null, { timestamp: stat.mtime, mode: stat.mode, contents: node.contents });
          } else {
            return callback(new Error('node type not supported'));
          }
        },storeLocalEntry:function (path, entry, callback) {
          try {
            if (FS.isDir(entry.mode)) {
              FS.mkdir(path, entry.mode);
            } else if (FS.isFile(entry.mode)) {
              FS.writeFile(path, entry.contents, { canOwn: true });
            } else {
              return callback(new Error('node type not supported'));
            }
    
            FS.chmod(path, entry.mode);
            FS.utime(path, entry.timestamp, entry.timestamp);
          } catch (e) {
            return callback(e);
          }
    
          callback(null);
        },removeLocalEntry:function (path, callback) {
          try {
            var lookup = FS.lookupPath(path);
            var stat = FS.stat(path);
    
            if (FS.isDir(stat.mode)) {
              FS.rmdir(path);
            } else if (FS.isFile(stat.mode)) {
              FS.unlink(path);
            }
          } catch (e) {
            return callback(e);
          }
    
          callback(null);
        },loadRemoteEntry:function (store, path, callback) {
          var req = store.get(path);
          req.onsuccess = function(event) { callback(null, event.target.result); };
          req.onerror = function(e) {
            callback(this.error);
            e.preventDefault();
          };
        },storeRemoteEntry:function (store, path, entry, callback) {
          var req = store.put(entry, path);
          req.onsuccess = function() { callback(null); };
          req.onerror = function(e) {
            callback(this.error);
            e.preventDefault();
          };
        },removeRemoteEntry:function (store, path, callback) {
          var req = store.delete(path);
          req.onsuccess = function() { callback(null); };
          req.onerror = function(e) {
            callback(this.error);
            e.preventDefault();
          };
        },reconcile:function (src, dst, callback) {
          var total = 0;
    
          var create = [];
          Object.keys(src.entries).forEach(function (key) {
            var e = src.entries[key];
            var e2 = dst.entries[key];
            if (!e2 || e.timestamp > e2.timestamp) {
              create.push(key);
              total++;
            }
          });
    
          var remove = [];
          Object.keys(dst.entries).forEach(function (key) {
            var e = dst.entries[key];
            var e2 = src.entries[key];
            if (!e2) {
              remove.push(key);
              total++;
            }
          });
    
          if (!total) {
            return callback(null);
          }
    
          var errored = false;
          var db = src.type === 'remote' ? src.db : dst.db;
          var transaction = db.transaction([IDBFS.DB_STORE_NAME], 'readwrite');
          var store = transaction.objectStore(IDBFS.DB_STORE_NAME);
    
          function done(err) {
            if (err && !errored) {
              errored = true;
              return callback(err);
            }
          };
    
          transaction.onerror = function(e) {
            done(this.error);
            e.preventDefault();
          };
    
          transaction.oncomplete = function(e) {
            if (!errored) {
              callback(null);
            }
          };
    
          // sort paths in ascending order so directory entries are created
          // before the files inside them
          create.sort().forEach(function (path) {
            if (dst.type === 'local') {
              IDBFS.loadRemoteEntry(store, path, function (err, entry) {
                if (err) return done(err);
                IDBFS.storeLocalEntry(path, entry, done);
              });
            } else {
              IDBFS.loadLocalEntry(path, function (err, entry) {
                if (err) return done(err);
                IDBFS.storeRemoteEntry(store, path, entry, done);
              });
            }
          });
    
          // sort paths in descending order so files are deleted before their
          // parent directories
          remove.sort().reverse().forEach(function(path) {
            if (dst.type === 'local') {
              IDBFS.removeLocalEntry(path, done);
            } else {
              IDBFS.removeRemoteEntry(store, path, done);
            }
          });
        }};
    
    var NODEFS={isWindows:false,staticInit:function () {
          NODEFS.isWindows = !!process.platform.match(/^win/);
          var flags = process["binding"]("constants");
          // Node.js 4 compatibility: it has no namespaces for constants
          if (flags["fs"]) {
            flags = flags["fs"];
          }
          NODEFS.flagsForNodeMap = {
            "1024": flags["O_APPEND"],
            "64": flags["O_CREAT"],
            "128": flags["O_EXCL"],
            "0": flags["O_RDONLY"],
            "2": flags["O_RDWR"],
            "4096": flags["O_SYNC"],
            "512": flags["O_TRUNC"],
            "1": flags["O_WRONLY"]
          };
        },bufferFrom:function (arrayBuffer) {
          // Node.js < 4.5 compatibility: Buffer.from does not support ArrayBuffer
          // Buffer.from before 4.5 was just a method inherited from Uint8Array
          // Buffer.alloc has been added with Buffer.from together, so check it instead
          return Buffer.alloc ? Buffer.from(arrayBuffer) : new Buffer(arrayBuffer);
        },mount:function (mount) {
          assert(ENVIRONMENT_HAS_NODE);
          return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0);
        },createNode:function (parent, name, mode, dev) {
          if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {
            throw new FS.ErrnoError(22);
          }
          var node = FS.createNode(parent, name, mode);
          node.node_ops = NODEFS.node_ops;
          node.stream_ops = NODEFS.stream_ops;
          return node;
        },getMode:function (path) {
          var stat;
          try {
            stat = fs.lstatSync(path);
            if (NODEFS.isWindows) {
              // Node.js on Windows never represents permission bit 'x', so
              // propagate read bits to execute bits
              stat.mode = stat.mode | ((stat.mode & 292) >> 2);
            }
          } catch (e) {
            if (!e.code) throw e;
            throw new FS.ErrnoError(-e.errno); // syscall errnos are negated, node's are not
          }
          return stat.mode;
        },realPath:function (node) {
          var parts = [];
          while (node.parent !== node) {
            parts.push(node.name);
            node = node.parent;
          }
          parts.push(node.mount.opts.root);
          parts.reverse();
          return PATH.join.apply(null, parts);
        },flagsForNode:function (flags) {
          flags &= ~0x200000 /*O_PATH*/; // Ignore this flag from musl, otherwise node.js fails to open the file.
          flags &= ~0x800 /*O_NONBLOCK*/; // Ignore this flag from musl, otherwise node.js fails to open the file.
          flags &= ~0x8000 /*O_LARGEFILE*/; // Ignore this flag from musl, otherwise node.js fails to open the file.
          flags &= ~0x80000 /*O_CLOEXEC*/; // Some applications may pass it; it makes no sense for a single process.
          var newFlags = 0;
          for (var k in NODEFS.flagsForNodeMap) {
            if (flags & k) {
              newFlags |= NODEFS.flagsForNodeMap[k];
              flags ^= k;
            }
          }
    
          if (!flags) {
            return newFlags;
          } else {
            throw new FS.ErrnoError(22);
          }
        },node_ops:{getattr:function (node) {
            var path = NODEFS.realPath(node);
            var stat;
            try {
              stat = fs.lstatSync(path);
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
            // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096.
            // See http://support.microsoft.com/kb/140365
            if (NODEFS.isWindows && !stat.blksize) {
              stat.blksize = 4096;
            }
            if (NODEFS.isWindows && !stat.blocks) {
              stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0;
            }
            return {
              dev: stat.dev,
              ino: stat.ino,
              mode: stat.mode,
              nlink: stat.nlink,
              uid: stat.uid,
              gid: stat.gid,
              rdev: stat.rdev,
              size: stat.size,
              atime: stat.atime,
              mtime: stat.mtime,
              ctime: stat.ctime,
              blksize: stat.blksize,
              blocks: stat.blocks
            };
          },setattr:function (node, attr) {
            var path = NODEFS.realPath(node);
            try {
              if (attr.mode !== undefined) {
                fs.chmodSync(path, attr.mode);
                // update the common node structure mode as well
                node.mode = attr.mode;
              }
              if (attr.timestamp !== undefined) {
                var date = new Date(attr.timestamp);
                fs.utimesSync(path, date, date);
              }
              if (attr.size !== undefined) {
                fs.truncateSync(path, attr.size);
              }
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
          },lookup:function (parent, name) {
            var path = PATH.join2(NODEFS.realPath(parent), name);
            var mode = NODEFS.getMode(path);
            return NODEFS.createNode(parent, name, mode);
          },mknod:function (parent, name, mode, dev) {
            var node = NODEFS.createNode(parent, name, mode, dev);
            // create the backing node for this in the fs root as well
            var path = NODEFS.realPath(node);
            try {
              if (FS.isDir(node.mode)) {
                fs.mkdirSync(path, node.mode);
              } else {
                fs.writeFileSync(path, '', { mode: node.mode });
              }
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
            return node;
          },rename:function (oldNode, newDir, newName) {
            var oldPath = NODEFS.realPath(oldNode);
            var newPath = PATH.join2(NODEFS.realPath(newDir), newName);
            try {
              fs.renameSync(oldPath, newPath);
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
          },unlink:function (parent, name) {
            var path = PATH.join2(NODEFS.realPath(parent), name);
            try {
              fs.unlinkSync(path);
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
          },rmdir:function (parent, name) {
            var path = PATH.join2(NODEFS.realPath(parent), name);
            try {
              fs.rmdirSync(path);
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
          },readdir:function (node) {
            var path = NODEFS.realPath(node);
            try {
              return fs.readdirSync(path);
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
          },symlink:function (parent, newName, oldPath) {
            var newPath = PATH.join2(NODEFS.realPath(parent), newName);
            try {
              fs.symlinkSync(oldPath, newPath);
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
          },readlink:function (node) {
            var path = NODEFS.realPath(node);
            try {
              path = fs.readlinkSync(path);
              path = NODEJS_PATH.relative(NODEJS_PATH.resolve(node.mount.opts.root), path);
              return path;
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
          }},stream_ops:{open:function (stream) {
            var path = NODEFS.realPath(stream.node);
            try {
              if (FS.isFile(stream.node.mode)) {
                stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags));
              }
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
          },close:function (stream) {
            try {
              if (FS.isFile(stream.node.mode) && stream.nfd) {
                fs.closeSync(stream.nfd);
              }
            } catch (e) {
              if (!e.code) throw e;
              throw new FS.ErrnoError(-e.errno);
            }
          },read:function (stream, buffer, offset, length, position) {
            // Node.js < 6 compatibility: node errors on 0 length reads
            if (length === 0) return 0;
            try {
              return fs.readSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position);
            } catch (e) {
              throw new FS.ErrnoError(-e.errno);
            }
          },write:function (stream, buffer, offset, length, position) {
            try {
              return fs.writeSync(stream.nfd, NODEFS.bufferFrom(buffer.buffer), offset, length, position);
            } catch (e) {
              throw new FS.ErrnoError(-e.errno);
            }
          },llseek:function (stream, offset, whence) {
            var position = offset;
            if (whence === 1) {  // SEEK_CUR.
              position += stream.position;
            } else if (whence === 2) {  // SEEK_END.
              if (FS.isFile(stream.node.mode)) {
                try {
                  var stat = fs.fstatSync(stream.nfd);
                  position += stat.size;
                } catch (e) {
                  throw new FS.ErrnoError(-e.errno);
                }
              }
            }
    
            if (position < 0) {
              throw new FS.ErrnoError(22);
            }
    
            return position;
          }}};
    
    var WORKERFS={DIR_MODE:16895,FILE_MODE:33279,reader:null,mount:function (mount) {
          assert(ENVIRONMENT_IS_WORKER);
          if (!WORKERFS.reader) WORKERFS.reader = new FileReaderSync();
          var root = WORKERFS.createNode(null, '/', WORKERFS.DIR_MODE, 0);
          var createdParents = {};
          function ensureParent(path) {
            // return the parent node, creating subdirs as necessary
            var parts = path.split('/');
            var parent = root;
            for (var i = 0; i < parts.length-1; i++) {
              var curr = parts.slice(0, i+1).join('/');
              // Issue 4254: Using curr as a node name will prevent the node
              // from being found in FS.nameTable when FS.open is called on
              // a path which holds a child of this node,
              // given that all FS functions assume node names
              // are just their corresponding parts within their given path,
              // rather than incremental aggregates which include their parent's
              // directories.
              if (!createdParents[curr]) {
                createdParents[curr] = WORKERFS.createNode(parent, parts[i], WORKERFS.DIR_MODE, 0);
              }
              parent = createdParents[curr];
            }
            return parent;
          }
          function base(path) {
            var parts = path.split('/');
            return parts[parts.length-1];
          }
          // We also accept FileList here, by using Array.prototype
          Array.prototype.forEach.call(mount.opts["files"] || [], function(file) {
            WORKERFS.createNode(ensureParent(file.name), base(file.name), WORKERFS.FILE_MODE, 0, file, file.lastModifiedDate);
          });
          (mount.opts["blobs"] || []).forEach(function(obj) {
            WORKERFS.createNode(ensureParent(obj["name"]), base(obj["name"]), WORKERFS.FILE_MODE, 0, obj["data"]);
          });
          (mount.opts["packages"] || []).forEach(function(pack) {
            pack['metadata'].files.forEach(function(file) {
              var name = file.filename.substr(1); // remove initial slash
              WORKERFS.createNode(ensureParent(name), base(name), WORKERFS.FILE_MODE, 0, pack['blob'].slice(file.start, file.end));
            });
          });
          return root;
        },createNode:function (parent, name, mode, dev, contents, mtime) {
          var node = FS.createNode(parent, name, mode);
          node.mode = mode;
          node.node_ops = WORKERFS.node_ops;
          node.stream_ops = WORKERFS.stream_ops;
          node.timestamp = (mtime || new Date).getTime();
          assert(WORKERFS.FILE_MODE !== WORKERFS.DIR_MODE);
          if (mode === WORKERFS.FILE_MODE) {
            node.size = contents.size;
            node.contents = contents;
          } else {
            node.size = 4096;
            node.contents = {};
          }
          if (parent) {
            parent.contents[name] = node;
          }
          return node;
        },node_ops:{getattr:function (node) {
            return {
              dev: 1,
              ino: undefined,
              mode: node.mode,
              nlink: 1,
              uid: 0,
              gid: 0,
              rdev: undefined,
              size: node.size,
              atime: new Date(node.timestamp),
              mtime: new Date(node.timestamp),
              ctime: new Date(node.timestamp),
              blksize: 4096,
              blocks: Math.ceil(node.size / 4096),
            };
          },setattr:function (node, attr) {
            if (attr.mode !== undefined) {
              node.mode = attr.mode;
            }
            if (attr.timestamp !== undefined) {
              node.timestamp = attr.timestamp;
            }
          },lookup:function (parent, name) {
            throw new FS.ErrnoError(2);
          },mknod:function (parent, name, mode, dev) {
            throw new FS.ErrnoError(1);
          },rename:function (oldNode, newDir, newName) {
            throw new FS.ErrnoError(1);
          },unlink:function (parent, name) {
            throw new FS.ErrnoError(1);
          },rmdir:function (parent, name) {
            throw new FS.ErrnoError(1);
          },readdir:function (node) {
            var entries = ['.', '..'];
            for (var key in node.contents) {
              if (!node.contents.hasOwnProperty(key)) {
                continue;
              }
              entries.push(key);
            }
            return entries;
          },symlink:function (parent, newName, oldPath) {
            throw new FS.ErrnoError(1);
          },readlink:function (node) {
            throw new FS.ErrnoError(1);
          }},stream_ops:{read:function (stream, buffer, offset, length, position) {
            if (position >= stream.node.size) return 0;
            var chunk = stream.node.contents.slice(position, position + length);
            var ab = WORKERFS.reader.readAsArrayBuffer(chunk);
            buffer.set(new Uint8Array(ab), offset);
            return chunk.size;
          },write:function (stream, buffer, offset, length, position) {
            throw new FS.ErrnoError(5);
          },llseek:function (stream, offset, whence) {
            var position = offset;
            if (whence === 1) {  // SEEK_CUR.
              position += stream.position;
            } else if (whence === 2) {  // SEEK_END.
              if (FS.isFile(stream.node.mode)) {
                position += stream.node.size;
              }
            }
            if (position < 0) {
              throw new FS.ErrnoError(22);
            }
            return position;
          }}};
    
    var 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"};
    
    var 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};var FS={root:null,mounts:[],devices:{},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) {
          if (!(e instanceof FS.ErrnoError)) throw e + ' : ' + stackTrace();
          return ___setErrNo(e.errno);
        },lookupPath:function (path, opts) {
          path = PATH_FS.resolve(FS.cwd(), path);
          opts = opts || {};
    
          if (!path) return { path: '', node: null };
    
          var defaults = {
            follow_mount: true,
            recurse_count: 0
          };
          for (var key in defaults) {
            if (opts[key] === undefined) {
              opts[key] = defaults[key];
            }
          }
    
          if (opts.recurse_count > 8) {  // max recursive lookup of 8
            throw new FS.ErrnoError(40);
          }
    
          // split the path
          var parts = PATH.normalizeArray(path.split('/').filter(function(p) {
            return !!p;
          }), false);
    
          // start at the root
          var current = FS.root;
          var current_path = '/';
    
          for (var i = 0; i < parts.length; i++) {
            var islast = (i === parts.length-1);
            if (islast && opts.parent) {
              // stop resolving
              break;
            }
    
            current = FS.lookupNode(current, parts[i]);
            current_path = PATH.join2(current_path, parts[i]);
    
            // jump to the mount's root node if this is a mountpoint
            if (FS.isMountpoint(current)) {
              if (!islast || (islast && opts.follow_mount)) {
                current = current.mounted.root;
              }
            }
    
            // by default, lookupPath will not follow a symlink if it is the final path component.
            // setting opts.follow = true will override this behavior.
            if (!islast || opts.follow) {
              var count = 0;
              while (FS.isLink(current.mode)) {
                var link = FS.readlink(current_path);
                current_path = PATH_FS.resolve(PATH.dirname(current_path), link);
    
                var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
                current = lookup.node;
    
                if (count++ > 40) {  // limit max consecutive symlinks to 40 (SYMLOOP_MAX).
                  throw new FS.ErrnoError(40);
                }
              }
            }
          }
    
          return { path: current_path, node: current };
        },getPath:function (node) {
          var path;
          while (true) {
            if (FS.isRoot(node)) {
              var mount = node.mount.mountpoint;
              if (!path) return mount;
              return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path;
            }
            path = path ? node.name + '/' + path : node.name;
            node = node.parent;
          }
        },hashName:function (parentid, name) {
          var hash = 0;
    
    
          for (var i = 0; i < name.length; i++) {
            hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0;
          }
          return ((parentid + hash) >>> 0) % FS.nameTable.length;
        },hashAddNode:function (node) {
          var hash = FS.hashName(node.parent.id, node.name);
          node.name_next = FS.nameTable[hash];
          FS.nameTable[hash] = node;
        },hashRemoveNode:function (node) {
          var hash = FS.hashName(node.parent.id, node.name);
          if (FS.nameTable[hash] === node) {
            FS.nameTable[hash] = node.name_next;
          } else {
            var current = FS.nameTable[hash];
            while (current) {
              if (current.name_next === node) {
                current.name_next = node.name_next;
                break;
              }
              current = current.name_next;
            }
          }
        },lookupNode:function (parent, name) {
          var err = FS.mayLookup(parent);
          if (err) {
            throw new FS.ErrnoError(err, parent);
          }
          var hash = FS.hashName(parent.id, name);
          for (var node = FS.nameTable[hash]; node; node = node.name_next) {
            var nodeName = node.name;
            if (node.parent.id === parent.id && nodeName === name) {
              return node;
            }
          }
          // if we failed to find it in the cache, call into the VFS
          return FS.lookup(parent, name);
        },createNode:function (parent, name, mode, rdev) {
          if (!FS.FSNode) {
            FS.FSNode = function(parent, name, mode, rdev) {
              if (!parent) {
                parent = this;  // root node sets parent to itself
              }
              this.parent = parent;
              this.mount = parent.mount;
              this.mounted = null;
              this.id = FS.nextInode++;
              this.name = name;
              this.mode = mode;
              this.node_ops = {};
              this.stream_ops = {};
              this.rdev = rdev;
            };
    
            FS.FSNode.prototype = {};
    
            // compatibility
            var readMode = 292 | 73;
            var writeMode = 146;
    
            // NOTE we must use Object.defineProperties instead of individual calls to
            // Object.defineProperty in order to make closure compiler happy
            Object.defineProperties(FS.FSNode.prototype, {
              read: {
                get: function() { return (this.mode & readMode) === readMode; },
                set: function(val) { val ? this.mode |= readMode : this.mode &= ~readMode; }
              },
              write: {
                get: function() { return (this.mode & writeMode) === writeMode; },
                set: function(val) { val ? this.mode |= writeMode : this.mode &= ~writeMode; }
              },
              isFolder: {
                get: function() { return FS.isDir(this.mode); }
              },
              isDevice: {
                get: function() { return FS.isChrdev(this.mode); }
              }
            });
          }
    
          var node = new FS.FSNode(parent, name, mode, rdev);
    
          FS.hashAddNode(node);
    
          return node;
        },destroyNode:function (node) {
          FS.hashRemoveNode(node);
        },isRoot:function (node) {
          return node === node.parent;
        },isMountpoint:function (node) {
          return !!node.mounted;
        },isFile:function (mode) {
          return (mode & 61440) === 32768;
        },isDir:function (mode) {
          return (mode & 61440) === 16384;
        },isLink:function (mode) {
          return (mode & 61440) === 40960;
        },isChrdev:function (mode) {
          return (mode & 61440) === 8192;
        },isBlkdev:function (mode) {
          return (mode & 61440) === 24576;
        },isFIFO:function (mode) {
          return (mode & 61440) === 4096;
        },isSocket:function (mode) {
          return (mode & 49152) === 49152;
        },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) {
          var flags = FS.flagModes[str];
          if (typeof flags === 'undefined') {
            throw new Error('Unknown file open mode: ' + str);
          }
          return flags;
        },flagsToPermissionString:function (flag) {
          var perms = ['r', 'w', 'rw'][flag & 3];
          if ((flag & 512)) {
            perms += 'w';
          }
          return perms;
        },nodePermissions:function (node, perms) {
          if (FS.ignorePermissions) {
            return 0;
          }
          // return 0 if any user, group or owner bits are set.
          if (perms.indexOf('r') !== -1 && !(node.mode & 292)) {
            return 13;
          } else if (perms.indexOf('w') !== -1 && !(node.mode & 146)) {
            return 13;
          } else if (perms.indexOf('x') !== -1 && !(node.mode & 73)) {
            return 13;
          }
          return 0;
        },mayLookup:function (dir) {
          var err = FS.nodePermissions(dir, 'x');
          if (err) return err;
          if (!dir.node_ops.lookup) return 13;
          return 0;
        },mayCreate:function (dir, name) {
          try {
            var node = FS.lookupNode(dir, name);
            return 17;
          } catch (e) {
          }
          return FS.nodePermissions(dir, 'wx');
        },mayDelete:function (dir, name, isdir) {
          var node;
          try {
            node = FS.lookupNode(dir, name);
          } catch (e) {
            return e.errno;
          }
          var err = FS.nodePermissions(dir, 'wx');
          if (err) {
            return err;
          }
          if (isdir) {
            if (!FS.isDir(node.mode)) {
              return 20;
            }
            if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {
              return 16;
            }
          } else {
            if (FS.isDir(node.mode)) {
              return 21;
            }
          }
          return 0;
        },mayOpen:function (node, flags) {
          if (!node) {
            return 2;
          }
          if (FS.isLink(node.mode)) {
            return 40;
          } else if (FS.isDir(node.mode)) {
            if (FS.flagsToPermissionString(flags) !== 'r' || // opening for write
                (flags & 512)) { // TODO: check for O_SEARCH? (== search for dir only)
              return 21;
            }
          }
          return FS.nodePermissions(node, FS.flagsToPermissionString(flags));
        },MAX_OPEN_FDS:4096,nextfd:function (fd_start, fd_end) {
          fd_start = fd_start || 0;
          fd_end = fd_end || FS.MAX_OPEN_FDS;
          for (var fd = fd_start; fd <= fd_end; fd++) {
            if (!FS.streams[fd]) {
              return fd;
            }
          }
          throw new FS.ErrnoError(24);
        },getStream:function (fd) {
          return FS.streams[fd];
        },createStream:function (stream, fd_start, fd_end) {
          if (!FS.FSStream) {
            FS.FSStream = function(){};
            FS.FSStream.prototype = {};
            // compatibility
            Object.defineProperties(FS.FSStream.prototype, {
              object: {
                get: function() { return this.node; },
                set: function(val) { this.node = val; }
              },
              isRead: {
                get: function() { return (this.flags & 2097155) !== 1; }
              },
              isWrite: {
                get: function() { return (this.flags & 2097155) !== 0; }
              },
              isAppend: {
                get: function() { return (this.flags & 1024); }
              }
            });
          }
          // clone it, so we can return an instance of FSStream
          var newStream = new FS.FSStream();
          for (var p in stream) {
            newStream[p] = stream[p];
          }
          stream = newStream;
          var fd = FS.nextfd(fd_start, fd_end);
          stream.fd = fd;
          FS.streams[fd] = stream;
          return stream;
        },closeStream:function (fd) {
          FS.streams[fd] = null;
        },chrdev_stream_ops:{open:function (stream) {
            var device = FS.getDevice(stream.node.rdev);
            // override node's stream ops with the device's
            stream.stream_ops = device.stream_ops;
            // forward the open call
            if (stream.stream_ops.open) {
              stream.stream_ops.open(stream);
            }
          },llseek:function () {
            throw new FS.ErrnoError(29);
          }},major:function (dev) {
          return ((dev) >> 8);
        },minor:function (dev) {
          return ((dev) & 0xff);
        },makedev:function (ma, mi) {
          return ((ma) << 8 | (mi));
        },registerDevice:function (dev, ops) {
          FS.devices[dev] = { stream_ops: ops };
        },getDevice:function (dev) {
          return FS.devices[dev];
        },getMounts:function (mount) {
          var mounts = [];
          var check = [mount];
    
          while (check.length) {
            var m = check.pop();
    
            mounts.push(m);
    
            check.push.apply(check, m.mounts);
          }
    
          return mounts;
        },syncfs:function (populate, callback) {
          if (typeof(populate) === 'function') {
            callback = populate;
            populate = false;
          }
    
          FS.syncFSRequests++;
    
          if (FS.syncFSRequests > 1) {
            console.log('warning: ' + FS.syncFSRequests + ' FS.syncfs operations in flight at once, probably just doing extra work');
          }
    
          var mounts = FS.getMounts(FS.root.mount);
          var completed = 0;
    
          function doCallback(err) {
            assert(FS.syncFSRequests > 0);
            FS.syncFSRequests--;
            return callback(err);
          }
    
          function done(err) {
            if (err) {
              if (!done.errored) {
                done.errored = true;
                return doCallback(err);
              }
              return;
            }
            if (++completed >= mounts.length) {
              doCallback(null);
            }
          };
    
          // sync all mounts
          mounts.forEach(function (mount) {
            if (!mount.type.syncfs) {
              return done(null);
            }
            mount.type.syncfs(mount, populate, done);
          });
        },mount:function (type, opts, mountpoint) {
          var root = mountpoint === '/';
          var pseudo = !mountpoint;
          var node;
    
          if (root && FS.root) {
            throw new FS.ErrnoError(16);
          } else if (!root && !pseudo) {
            var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
    
            mountpoint = lookup.path;  // use the absolute path
            node = lookup.node;
    
            if (FS.isMountpoint(node)) {
              throw new FS.ErrnoError(16);
            }
    
            if (!FS.isDir(node.mode)) {
              throw new FS.ErrnoError(20);
            }
          }
    
          var mount = {
            type: type,
            opts: opts,
            mountpoint: mountpoint,
            mounts: []
          };
    
          // create a root node for the fs
          var mountRoot = type.mount(mount);
          mountRoot.mount = mount;
          mount.root = mountRoot;
    
          if (root) {
            FS.root = mountRoot;
          } else if (node) {
            // set as a mountpoint
            node.mounted = mount;
    
            // add the new mount to the current mount's children
            if (node.mount) {
              node.mount.mounts.push(mount);
            }
          }
    
          return mountRoot;
        },unmount:function (mountpoint) {
          var lookup = FS.lookupPath(mountpoint, { follow_mount: false });
    
          if (!FS.isMountpoint(lookup.node)) {
            throw new FS.ErrnoError(22);
          }
    
          // destroy the nodes for this mount, and all its child mounts
          var node = lookup.node;
          var mount = node.mounted;
          var mounts = FS.getMounts(mount);
    
          Object.keys(FS.nameTable).forEach(function (hash) {
            var current = FS.nameTable[hash];
    
            while (current) {
              var next = current.name_next;
    
              if (mounts.indexOf(current.mount) !== -1) {
                FS.destroyNode(current);
              }
    
              current = next;
            }
          });
    
          // no longer a mountpoint
          node.mounted = null;
    
          // remove this mount from the child mounts
          var idx = node.mount.mounts.indexOf(mount);
          assert(idx !== -1);
          node.mount.mounts.splice(idx, 1);
        },lookup:function (parent, name) {
          return parent.node_ops.lookup(parent, name);
        },mknod:function (path, mode, dev) {
          var lookup = FS.lookupPath(path, { parent: true });
          var parent = lookup.node;
          var name = PATH.basename(path);
          if (!name || name === '.' || name === '..') {
            throw new FS.ErrnoError(22);
          }
          var err = FS.mayCreate(parent, name);
          if (err) {
            throw new FS.ErrnoError(err);
          }
          if (!parent.node_ops.mknod) {
            throw new FS.ErrnoError(1);
          }
          return parent.node_ops.mknod(parent, name, mode, dev);
        },create:function (path, mode) {
          mode = mode !== undefined ? mode : 438 /* 0666 */;
          mode &= 4095;
          mode |= 32768;
          return FS.mknod(path, mode, 0);
        },mkdir:function (path, mode) {
          mode = mode !== undefined ? mode : 511 /* 0777 */;
          mode &= 511 | 512;
          mode |= 16384;
          return FS.mknod(path, mode, 0);
        },mkdirTree:function (path, mode) {
          var dirs = path.split('/');
          var d = '';
          for (var i = 0; i < dirs.length; ++i) {
            if (!dirs[i]) continue;
            d += '/' + dirs[i];
            try {
              FS.mkdir(d, mode);
            } catch(e) {
              if (e.errno != 17) throw e;
            }
          }
        },mkdev:function (path, mode, dev) {
          if (typeof(dev) === 'undefined') {
            dev = mode;
            mode = 438 /* 0666 */;
          }
          mode |= 8192;
          return FS.mknod(path, mode, dev);
        },symlink:function (oldpath, newpath) {
          if (!PATH_FS.resolve(oldpath)) {
            throw new FS.ErrnoError(2);
          }
          var lookup = FS.lookupPath(newpath, { parent: true });
          var parent = lookup.node;
          if (!parent) {
            throw new FS.ErrnoError(2);
          }
          var newname = PATH.basename(newpath);
          var err = FS.mayCreate(parent, newname);
          if (err) {
            throw new FS.ErrnoError(err);
          }
          if (!parent.node_ops.symlink) {
            throw new FS.ErrnoError(1);
          }
          return parent.node_ops.symlink(parent, newname, oldpath);
        },rename:function (old_path, new_path) {
          var old_dirname = PATH.dirname(old_path);
          var new_dirname = PATH.dirname(new_path);
          var old_name = PATH.basename(old_path);
          var new_name = PATH.basename(new_path);
          // parents must exist
          var lookup, old_dir, new_dir;
          try {
            lookup = FS.lookupPath(old_path, { parent: true });
            old_dir = lookup.node;
            lookup = FS.lookupPath(new_path, { parent: true });
            new_dir = lookup.node;
          } catch (e) {
            throw new FS.ErrnoError(16);
          }
          if (!old_dir || !new_dir) throw new FS.ErrnoError(2);
          // need to be part of the same mount
          if (old_dir.mount !== new_dir.mount) {
            throw new FS.ErrnoError(18);
          }
          // source must exist
          var old_node = FS.lookupNode(old_dir, old_name);
          // old path should not be an ancestor of the new path
          var relative = PATH_FS.relative(old_path, new_dirname);
          if (relative.charAt(0) !== '.') {
            throw new FS.ErrnoError(22);
          }
          // new path should not be an ancestor of the old path
          relative = PATH_FS.relative(new_path, old_dirname);
          if (relative.charAt(0) !== '.') {
            throw new FS.ErrnoError(39);
          }
          // see if the new path already exists
          var new_node;
          try {
            new_node = FS.lookupNode(new_dir, new_name);
          } catch (e) {
            // not fatal
          }
          // early out if nothing needs to change
          if (old_node === new_node) {
            return;
          }
          // we'll need to delete the old entry
          var isdir = FS.isDir(old_node.mode);
          var err = FS.mayDelete(old_dir, old_name, isdir);
          if (err) {
            throw new FS.ErrnoError(err);
          }
          // need delete permissions if we'll be overwriting.
          // need create permissions if new doesn't already exist.
          err = new_node ?
            FS.mayDelete(new_dir, new_name, isdir) :
            FS.mayCreate(new_dir, new_name);
          if (err) {
            throw new FS.ErrnoError(err);
          }
          if (!old_dir.node_ops.rename) {
            throw new FS.ErrnoError(1);
          }
          if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) {
            throw new FS.ErrnoError(16);
          }
          // if we are going to change the parent, check write permissions
          if (new_dir !== old_dir) {
            err = FS.nodePermissions(old_dir, 'w');
            if (err) {
              throw new FS.ErrnoError(err);
            }
          }
          try {
            if (FS.trackingDelegate['willMovePath']) {
              FS.trackingDelegate['willMovePath'](old_path, new_path);
            }
          } catch(e) {
            console.log("FS.trackingDelegate['willMovePath']('"+old_path+"', '"+new_path+"') threw an exception: " + e.message);
          }
          // remove the node from the lookup hash
          FS.hashRemoveNode(old_node);
          // do the underlying fs rename
          try {
            old_dir.node_ops.rename(old_node, new_dir, new_name);
          } catch (e) {
            throw e;
          } finally {
            // add the node back to the hash (in case node_ops.rename
            // changed its name)
            FS.hashAddNode(old_node);
          }
          try {
            if (FS.trackingDelegate['onMovePath']) FS.trackingDelegate['onMovePath'](old_path, new_path);
          } catch(e) {
            console.log("FS.trackingDelegate['onMovePath']('"+old_path+"', '"+new_path+"') threw an exception: " + e.message);
          }
        },rmdir:function (path) {
          var lookup = FS.lookupPath(path, { parent: true });
          var parent = lookup.node;
          var name = PATH.basename(path);
          var node = FS.lookupNode(parent, name);
          var err = FS.mayDelete(parent, name, true);
          if (err) {
            throw new FS.ErrnoError(err);
          }
          if (!parent.node_ops.rmdir) {
            throw new FS.ErrnoError(1);
          }
          if (FS.isMountpoint(node)) {
            throw new FS.ErrnoError(16);
          }
          try {
            if (FS.trackingDelegate['willDeletePath']) {
              FS.trackingDelegate['willDeletePath'](path);
            }
          } catch(e) {
            console.log("FS.trackingDelegate['willDeletePath']('"+path+"') threw an exception: " + e.message);
          }
          parent.node_ops.rmdir(parent, name);
          FS.destroyNode(node);
          try {
            if (FS.trackingDelegate['onDeletePath']) FS.trackingDelegate['onDeletePath'](path);
          } catch(e) {
            console.log("FS.trackingDelegate['onDeletePath']('"+path+"') threw an exception: " + e.message);
          }
        },readdir:function (path) {
          var lookup = FS.lookupPath(path, { follow: true });
          var node = lookup.node;
          if (!node.node_ops.readdir) {
            throw new FS.ErrnoError(20);
          }
          return node.node_ops.readdir(node);
        },unlink:function (path) {
          var lookup = FS.lookupPath(path, { parent: true });
          var parent = lookup.node;
          var name = PATH.basename(path);
          var node = FS.lookupNode(parent, name);
          var err = FS.mayDelete(parent, name, false);
          if (err) {
            // According to POSIX, we should map EISDIR to EPERM, but
            // we instead do what Linux does (and we must, as we use
            // the musl linux libc).
            throw new FS.ErrnoError(err);
          }
          if (!parent.node_ops.unlink) {
            throw new FS.ErrnoError(1);
          }
          if (FS.isMountpoint(node)) {
            throw new FS.ErrnoError(16);
          }
          try {
            if (FS.trackingDelegate['willDeletePath']) {
              FS.trackingDelegate['willDeletePath'](path);
            }
          } catch(e) {
            console.log("FS.trackingDelegate['willDeletePath']('"+path+"') threw an exception: " + e.message);
          }
          parent.node_ops.unlink(parent, name);
          FS.destroyNode(node);
          try {
            if (FS.trackingDelegate['onDeletePath']) FS.trackingDelegate['onDeletePath'](path);
          } catch(e) {
            console.log("FS.trackingDelegate['onDeletePath']('"+path+"') threw an exception: " + e.message);
          }
        },readlink:function (path) {
          var lookup = FS.lookupPath(path);
          var link = lookup.node;
          if (!link) {
            throw new FS.ErrnoError(2);
          }
          if (!link.node_ops.readlink) {
            throw new FS.ErrnoError(22);
          }
          return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link));
        },stat:function (path, dontFollow) {
          var lookup = FS.lookupPath(path, { follow: !dontFollow });
          var node = lookup.node;
          if (!node) {
            throw new FS.ErrnoError(2);
          }
          if (!node.node_ops.getattr) {
            throw new FS.ErrnoError(1);
          }
          return node.node_ops.getattr(node);
        },lstat:function (path) {
          return FS.stat(path, true);
        },chmod:function (path, mode, dontFollow) {
          var node;
          if (typeof path === 'string') {
            var lookup = FS.lookupPath(path, { follow: !dontFollow });
            node = lookup.node;
          } else {
            node = path;
          }
          if (!node.node_ops.setattr) {
            throw new FS.ErrnoError(1);
          }
          node.node_ops.setattr(node, {
            mode: (mode & 4095) | (node.mode & ~4095),
            timestamp: Date.now()
          });
        },lchmod:function (path, mode) {
          FS.chmod(path, mode, true);
        },fchmod:function (fd, mode) {
          var stream = FS.getStream(fd);
          if (!stream) {
            throw new FS.ErrnoError(9);
          }
          FS.chmod(stream.node, mode);
        },chown:function (path, uid, gid, dontFollow) {
          var node;
          if (typeof path === 'string') {
            var lookup = FS.lookupPath(path, { follow: !dontFollow });
            node = lookup.node;
          } else {
            node = path;
          }
          if (!node.node_ops.setattr) {
            throw new FS.ErrnoError(1);
          }
          node.node_ops.setattr(node, {
            timestamp: Date.now()
            // we ignore the uid / gid for now
          });
        },lchown:function (path, uid, gid) {
          FS.chown(path, uid, gid, true);
        },fchown:function (fd, uid, gid) {
          var stream = FS.getStream(fd);
          if (!stream) {
            throw new FS.ErrnoError(9);
          }
          FS.chown(stream.node, uid, gid);
        },truncate:function (path, len) {
          if (len < 0) {
            throw new FS.ErrnoError(22);
          }
          var node;
          if (typeof path === 'string') {
            var lookup = FS.lookupPath(path, { follow: true });
            node = lookup.node;
          } else {
            node = path;
          }
          if (!node.node_ops.setattr) {
            throw new FS.ErrnoError(1);
          }
          if (FS.isDir(node.mode)) {
            throw new FS.ErrnoError(21);
          }
          if (!FS.isFile(node.mode)) {
            throw new FS.ErrnoError(22);
          }
          var err = FS.nodePermissions(node, 'w');
          if (err) {
            throw new FS.ErrnoError(err);
          }
          node.node_ops.setattr(node, {
            size: len,
            timestamp: Date.now()
          });
        },ftruncate:function (fd, len) {
          var stream = FS.getStream(fd);
          if (!stream) {
            throw new FS.ErrnoError(9);
          }
          if ((stream.flags & 2097155) === 0) {
            throw new FS.ErrnoError(22);
          }
          FS.truncate(stream.node, len);
        },utime:function (path, atime, mtime) {
          var lookup = FS.lookupPath(path, { follow: true });
          var node = lookup.node;
          node.node_ops.setattr(node, {
            timestamp: Math.max(atime, mtime)
          });
        },open:function (path, flags, mode, fd_start, fd_end) {
          if (path === "") {
            throw new FS.ErrnoError(2);
          }
          flags = typeof flags === 'string' ? FS.modeStringToFlags(flags) : flags;
          mode = typeof mode === 'undefined' ? 438 /* 0666 */ : mode;
          if ((flags & 64)) {
            mode = (mode & 4095) | 32768;
          } else {
            mode = 0;
          }
          var node;
          if (typeof path === 'object') {
            node = path;
          } else {
            path = PATH.normalize(path);
            try {
              var lookup = FS.lookupPath(path, {
                follow: !(flags & 131072)
              });
              node = lookup.node;
            } catch (e) {
              // ignore
            }
          }
          // perhaps we need to create the node
          var created = false;
          if ((flags & 64)) {
            if (node) {
              // if O_CREAT and O_EXCL are set, error out if the node already exists
              if ((flags & 128)) {
                throw new FS.ErrnoError(17);
              }
            } else {
              // node doesn't exist, try to create it
              node = FS.mknod(path, mode, 0);
              created = true;
            }
          }
          if (!node) {
            throw new FS.ErrnoError(2);
          }
          // can't truncate a device
          if (FS.isChrdev(node.mode)) {
            flags &= ~512;
          }
          // if asked only for a directory, then this must be one
          if ((flags & 65536) && !FS.isDir(node.mode)) {
            throw new FS.ErrnoError(20);
          }
          // check permissions, if this is not a file we just created now (it is ok to
          // create and write to a file with read-only permissions; it is read-only
          // for later use)
          if (!created) {
            var err = FS.mayOpen(node, flags);
            if (err) {
              throw new FS.ErrnoError(err);
            }
          }
          // do truncation if necessary
          if ((flags & 512)) {
            FS.truncate(node, 0);
          }
          // we've already handled these, don't pass down to the underlying vfs
          flags &= ~(128 | 512);
    
          // register the stream with the filesystem
          var stream = FS.createStream({
            node: node,
            path: FS.getPath(node),  // we want the absolute path to the node
            flags: flags,
            seekable: true,
            position: 0,
            stream_ops: node.stream_ops,
            // used by the file family libc calls (fopen, fwrite, ferror, etc.)
            ungotten: [],
            error: false
          }, fd_start, fd_end);
          // call the new stream's open function
          if (stream.stream_ops.open) {
            stream.stream_ops.open(stream);
          }
          if (Module['logReadFiles'] && !(flags & 1)) {
            if (!FS.readFiles) FS.readFiles = {};
            if (!(path in FS.readFiles)) {
              FS.readFiles[path] = 1;
              console.log("FS.trackingDelegate error on read file: " + path);
            }
          }
          try {
            if (FS.trackingDelegate['onOpenFile']) {
              var trackingFlags = 0;
              if ((flags & 2097155) !== 1) {
                trackingFlags |= FS.tracking.openFlags.READ;
              }
              if ((flags & 2097155) !== 0) {
                trackingFlags |= FS.tracking.openFlags.WRITE;
              }
              FS.trackingDelegate['onOpenFile'](path, trackingFlags);
            }
          } catch(e) {
            console.log("FS.trackingDelegate['onOpenFile']('"+path+"', flags) threw an exception: " + e.message);
          }
          return stream;
        },close:function (stream) {
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(9);
          }
          if (stream.getdents) stream.getdents = null; // free readdir state
          try {
            if (stream.stream_ops.close) {
              stream.stream_ops.close(stream);
            }
          } catch (e) {
            throw e;
          } finally {
            FS.closeStream(stream.fd);
          }
          stream.fd = null;
        },isClosed:function (stream) {
          return stream.fd === null;
        },llseek:function (stream, offset, whence) {
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(9);
          }
          if (!stream.seekable || !stream.stream_ops.llseek) {
            throw new FS.ErrnoError(29);
          }
          if (whence != 0 /* SEEK_SET */ && whence != 1 /* SEEK_CUR */ && whence != 2 /* SEEK_END */) {
            throw new FS.ErrnoError(22);
          }
          stream.position = stream.stream_ops.llseek(stream, offset, whence);
          stream.ungotten = [];
          return stream.position;
        },read:function (stream, buffer, offset, length, position) {
          if (length < 0 || position < 0) {
            throw new FS.ErrnoError(22);
          }
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(9);
          }
          if ((stream.flags & 2097155) === 1) {
            throw new FS.ErrnoError(9);
          }
          if (FS.isDir(stream.node.mode)) {
            throw new FS.ErrnoError(21);
          }
          if (!stream.stream_ops.read) {
            throw new FS.ErrnoError(22);
          }
          var seeking = typeof position !== 'undefined';
          if (!seeking) {
            position = stream.position;
          } else if (!stream.seekable) {
            throw new FS.ErrnoError(29);
          }
          var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position);
          if (!seeking) stream.position += bytesRead;
          return bytesRead;
        },write:function (stream, buffer, offset, length, position, canOwn) {
          if (length < 0 || position < 0) {
            throw new FS.ErrnoError(22);
          }
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(9);
          }
          if ((stream.flags & 2097155) === 0) {
            throw new FS.ErrnoError(9);
          }
          if (FS.isDir(stream.node.mode)) {
            throw new FS.ErrnoError(21);
          }
          if (!stream.stream_ops.write) {
            throw new FS.ErrnoError(22);
          }
          if (stream.flags & 1024) {
            // seek to the end before writing in append mode
            FS.llseek(stream, 0, 2);
          }
          var seeking = typeof position !== 'undefined';
          if (!seeking) {
            position = stream.position;
          } else if (!stream.seekable) {
            throw new FS.ErrnoError(29);
          }
          var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn);
          if (!seeking) stream.position += bytesWritten;
          try {
            if (stream.path && FS.trackingDelegate['onWriteToFile']) FS.trackingDelegate['onWriteToFile'](stream.path);
          } catch(e) {
            console.log("FS.trackingDelegate['onWriteToFile']('"+stream.path+"') threw an exception: " + e.message);
          }
          return bytesWritten;
        },allocate:function (stream, offset, length) {
          if (FS.isClosed(stream)) {
            throw new FS.ErrnoError(9);
          }
          if (offset < 0 || length <= 0) {
            throw new FS.ErrnoError(22);
          }
          if ((stream.flags & 2097155) === 0) {
            throw new FS.ErrnoError(9);
          }
          if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {
            throw new FS.ErrnoError(19);
          }
          if (!stream.stream_ops.allocate) {
            throw new FS.ErrnoError(95);
          }
          stream.stream_ops.allocate(stream, offset, length);
        },mmap:function (stream, buffer, offset, length, position, prot, flags) {
          // User requests writing to file (prot & PROT_WRITE != 0).
          // Checking if we have permissions to write to the file unless
          // MAP_PRIVATE flag is set. According to POSIX spec it is possible
          // to write to file opened in read-only mode with MAP_PRIVATE flag,
          // as all modifications will be visible only in the memory of
          // the current process.
          if ((prot & 2) !== 0
              && (flags & 2) === 0
              && (stream.flags & 2097155) !== 2) {
            throw new FS.ErrnoError(13);
          }
          if ((stream.flags & 2097155) === 1) {
            throw new FS.ErrnoError(13);
          }
          if (!stream.stream_ops.mmap) {
            throw new FS.ErrnoError(19);
          }
          return stream.stream_ops.mmap(stream, buffer, offset, length, position, prot, flags);
        },msync:function (stream, buffer, offset, length, mmapFlags) {
          if (!stream || !stream.stream_ops.msync) {
            return 0;
          }
          return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags);
        },munmap:function (stream) {
          return 0;
        },ioctl:function (stream, cmd, arg) {
          if (!stream.stream_ops.ioctl) {
            throw new FS.ErrnoError(25);
          }
          return stream.stream_ops.ioctl(stream, cmd, arg);
        },readFile:function (path, opts) {
          opts = opts || {};
          opts.flags = opts.flags || 'r';
          opts.encoding = opts.encoding || 'binary';
          if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {
            throw new Error('Invalid encoding type "' + opts.encoding + '"');
          }
          var ret;
          var stream = FS.open(path, opts.flags);
          var stat = FS.stat(path);
          var length = stat.size;
          var buf = new Uint8Array(length);
          FS.read(stream, buf, 0, length, 0);
          if (opts.encoding === 'utf8') {
            ret = UTF8ArrayToString(buf, 0);
          } else if (opts.encoding === 'binary') {
            ret = buf;
          }
          FS.close(stream);
          return ret;
        },writeFile:function (path, data, opts) {
          opts = opts || {};
          opts.flags = opts.flags || 'w';
          var stream = FS.open(path, opts.flags, opts.mode);
          if (typeof data === 'string') {
            var buf = new Uint8Array(lengthBytesUTF8(data)+1);
            var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length);
            FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn);
          } else if (ArrayBuffer.isView(data)) {
            FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn);
          } else {
            throw new Error('Unsupported data type');
          }
          FS.close(stream);
        },cwd:function () {
          return FS.currentPath;
        },chdir:function (path) {
          var lookup = FS.lookupPath(path, { follow: true });
          if (lookup.node === null) {
            throw new FS.ErrnoError(2);
          }
          if (!FS.isDir(lookup.node.mode)) {
            throw new FS.ErrnoError(20);
          }
          var err = FS.nodePermissions(lookup.node, 'x');
          if (err) {
            throw new FS.ErrnoError(err);
          }
          FS.currentPath = lookup.path;
        },createDefaultDirectories:function () {
          FS.mkdir('/tmp');
          FS.mkdir('/home');
          FS.mkdir('/home/web_user');
        },createDefaultDevices:function () {
          // create /dev
          FS.mkdir('/dev');
          // setup /dev/null
          FS.registerDevice(FS.makedev(1, 3), {
            read: function() { return 0; },
            write: function(stream, buffer, offset, length, pos) { return length; }
          });
          FS.mkdev('/dev/null', FS.makedev(1, 3));
          // setup /dev/tty and /dev/tty1
          // stderr needs to print output using Module['printErr']
          // so we register a second tty just for it.
          TTY.register(FS.makedev(5, 0), TTY.default_tty_ops);
          TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops);
          FS.mkdev('/dev/tty', FS.makedev(5, 0));
          FS.mkdev('/dev/tty1', FS.makedev(6, 0));
          // setup /dev/[u]random
          var random_device;
          if (typeof crypto === 'object' && typeof crypto['getRandomValues'] === 'function') {
            // for modern web browsers
            var randomBuffer = new Uint8Array(1);
            random_device = function() { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; };
          } else
          if (ENVIRONMENT_IS_NODE) {
            // for nodejs with or without crypto support included
            try {
              var crypto_module = require('crypto');
              // nodejs has crypto support
              random_device = function() { return crypto_module['randomBytes'](1)[0]; };
            } catch (e) {
              // nodejs doesn't have crypto support
            }
          } else
          {}
          if (!random_device) {
            // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096
            random_device = function() { abort("no cryptographic support found for random_device. consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: function(array) { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };"); };
          }
          FS.createDevice('/dev', 'random', random_device);
          FS.createDevice('/dev', 'urandom', random_device);
          // we're not going to emulate the actual shm device,
          // just create the tmp dirs that reside in it commonly
          FS.mkdir('/dev/shm');
          FS.mkdir('/dev/shm/tmp');
        },createSpecialDirectories:function () {
          // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the name of the stream for fd 6 (see test_unistd_ttyname)
          FS.mkdir('/proc');
          FS.mkdir('/proc/self');
          FS.mkdir('/proc/self/fd');
          FS.mount({
            mount: function() {
              var node = FS.createNode('/proc/self', 'fd', 16384 | 511 /* 0777 */, 73);
              node.node_ops = {
                lookup: function(parent, name) {
                  var fd = +name;
                  var stream = FS.getStream(fd);
                  if (!stream) throw new FS.ErrnoError(9);
                  var ret = {
                    parent: null,
                    mount: { mountpoint: 'fake' },
                    node_ops: { readlink: function() { return stream.path } }
                  };
                  ret.parent = ret; // make it look like a simple root node
                  return ret;
                }
              };
              return node;
            }
          }, {}, '/proc/self/fd');
        },createStandardStreams:function () {
          // TODO deprecate the old functionality of a single
          // input / output callback and that utilizes FS.createDevice
          // and instead require a unique set of stream ops
    
          // by default, we symlink the standard streams to the
          // default tty devices. however, if the standard streams
          // have been overwritten we create a unique device for
          // them instead.
          if (Module['stdin']) {
            FS.createDevice('/dev', 'stdin', Module['stdin']);
          } else {
            FS.symlink('/dev/tty', '/dev/stdin');
          }
          if (Module['stdout']) {
            FS.createDevice('/dev', 'stdout', null, Module['stdout']);
          } else {
            FS.symlink('/dev/tty', '/dev/stdout');
          }
          if (Module['stderr']) {
            FS.createDevice('/dev', 'stderr', null, Module['stderr']);
          } else {
            FS.symlink('/dev/tty1', '/dev/stderr');
          }
    
          // open default streams for the stdin, stdout and stderr devices
          var stdin = FS.open('/dev/stdin', 'r');
          var stdout = FS.open('/dev/stdout', 'w');
          var stderr = FS.open('/dev/stderr', 'w');
          assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')');
          assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')');
          assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')');
        },ensureErrnoError:function () {
          if (FS.ErrnoError) return;
          FS.ErrnoError = function ErrnoError(errno, node) {
            this.node = node;
            this.setErrno = function(errno) {
              this.errno = errno;
              for (var key in ERRNO_CODES) {
                if (ERRNO_CODES[key] === errno) {
                  this.code = key;
                  break;
                }
              }
            };
            this.setErrno(errno);
            this.message = ERRNO_MESSAGES[errno];
            // Node.js compatibility: assigning on this.stack fails on Node 4 (but fixed on Node 8)
            if (this.stack) Object.defineProperty(this, "stack", { value: (new Error).stack, writable: true });
            if (this.stack) this.stack = demangleAll(this.stack);
          };
          FS.ErrnoError.prototype = new Error();
          FS.ErrnoError.prototype.constructor = FS.ErrnoError;
          // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info)
          [2].forEach(function(code) {
            FS.genericErrors[code] = new FS.ErrnoError(code);
            FS.genericErrors[code].stack = '<generic error, no stack>';
          });
        },staticInit:function () {
          FS.ensureErrnoError();
    
          FS.nameTable = new Array(4096);
    
          FS.mount(MEMFS, {}, '/');
    
          FS.createDefaultDirectories();
          FS.createDefaultDevices();
          FS.createSpecialDirectories();
    
          FS.filesystems = {
            'MEMFS': MEMFS,
            'IDBFS': IDBFS,
            'NODEFS': NODEFS,
            'WORKERFS': WORKERFS,
          };
        },init:function (input, output, error) {
          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)');
          FS.init.initialized = true;
    
          FS.ensureErrnoError();
    
          // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here
          Module['stdin'] = input || Module['stdin'];
          Module['stdout'] = output || Module['stdout'];
          Module['stderr'] = error || Module['stderr'];
    
          FS.createStandardStreams();
        },quit:function () {
          FS.init.initialized = false;
          // force-flush all streams, so we get musl std streams printed out
          var fflush = Module['_fflush'];
          if (fflush) fflush(0);
          // close all of our streams
          for (var i = 0; i < FS.streams.length; i++) {
            var stream = FS.streams[i];
            if (!stream) {
              continue;
            }
            FS.close(stream);
          }
        },getMode:function (canRead, canWrite) {
          var mode = 0;
          if (canRead) mode |= 292 | 73;
          if (canWrite) mode |= 146;
          return mode;
        },joinPath:function (parts, forceRelative) {
          var path = PATH.join.apply(null, parts);
          if (forceRelative && path[0] == '/') path = path.substr(1);
          return path;
        },absolutePath:function (relative, base) {
          return PATH_FS.resolve(base, relative);
        },standardizePath:function (path) {
          return PATH.normalize(path);
        },findObject:function (path, dontResolveLastLink) {
          var ret = FS.analyzePath(path, dontResolveLastLink);
          if (ret.exists) {
            return ret.object;
          } else {
            ___setErrNo(ret.error);
            return null;
          }
        },analyzePath:function (path, dontResolveLastLink) {
          // operate from within the context of the symlink's target
          try {
            var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
            path = lookup.path;
          } catch (e) {
          }
          var ret = {
            isRoot: false, exists: false, error: 0, name: null, path: null, object: null,
            parentExists: false, parentPath: null, parentObject: null
          };
          try {
            var lookup = FS.lookupPath(path, { parent: true });
            ret.parentExists = true;
            ret.parentPath = lookup.path;
            ret.parentObject = lookup.node;
            ret.name = PATH.basename(path);
            lookup = FS.lookupPath(path, { follow: !dontResolveLastLink });
            ret.exists = true;
            ret.path = lookup.path;
            ret.object = lookup.node;
            ret.name = lookup.node.name;
            ret.isRoot = lookup.path === '/';
          } catch (e) {
            ret.error = e.errno;
          };
          return ret;
        },createFolder:function (parent, name, canRead, canWrite) {
          var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
          var mode = FS.getMode(canRead, canWrite);
          return FS.mkdir(path, mode);
        },createPath:function (parent, path, canRead, canWrite) {
          parent = typeof parent === 'string' ? parent : FS.getPath(parent);
          var parts = path.split('/').reverse();
          while (parts.length) {
            var part = parts.pop();
            if (!part) continue;
            var current = PATH.join2(parent, part);
            try {
              FS.mkdir(current);
            } catch (e) {
              // ignore EEXIST
            }
            parent = current;
          }
          return current;
        },createFile:function (parent, name, properties, canRead, canWrite) {
          var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
          var mode = FS.getMode(canRead, canWrite);
          return FS.create(path, mode);
        },createDataFile:function (parent, name, data, canRead, canWrite, canOwn) {
          var path = name ? PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name) : parent;
          var mode = FS.getMode(canRead, canWrite);
          var node = FS.create(path, mode);
          if (data) {
            if (typeof data === 'string') {
              var arr = new Array(data.length);
              for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i);
              data = arr;
            }
            // make sure we can write to the file
            FS.chmod(node, mode | 146);
            var stream = FS.open(node, 'w');
            FS.write(stream, data, 0, data.length, 0, canOwn);
            FS.close(stream);
            FS.chmod(node, mode);
          }
          return node;
        },createDevice:function (parent, name, input, output) {
          var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
          var mode = FS.getMode(!!input, !!output);
          if (!FS.createDevice.major) FS.createDevice.major = 64;
          var dev = FS.makedev(FS.createDevice.major++, 0);
          // Create a fake device that a set of stream ops to emulate
          // the old behavior.
          FS.registerDevice(dev, {
            open: function(stream) {
              stream.seekable = false;
            },
            close: function(stream) {
              // flush any pending line data
              if (output && output.buffer && output.buffer.length) {
                output(10);
              }
            },
            read: function(stream, buffer, offset, length, pos /* ignored */) {
              var bytesRead = 0;
              for (var i = 0; i < length; i++) {
                var result;
                try {
                  result = input();
                } catch (e) {
                  throw new FS.ErrnoError(5);
                }
                if (result === undefined && bytesRead === 0) {
                  throw new FS.ErrnoError(11);
                }
                if (result === null || result === undefined) break;
                bytesRead++;
                buffer[offset+i] = result;
              }
              if (bytesRead) {
                stream.node.timestamp = Date.now();
              }
              return bytesRead;
            },
            write: function(stream, buffer, offset, length, pos) {
              for (var i = 0; i < length; i++) {
                try {
                  output(buffer[offset+i]);
                } catch (e) {
                  throw new FS.ErrnoError(5);
                }
              }
              if (length) {
                stream.node.timestamp = Date.now();
              }
              return i;
            }
          });
          return FS.mkdev(path, mode, dev);
        },createLink:function (parent, name, target, canRead, canWrite) {
          var path = PATH.join2(typeof parent === 'string' ? parent : FS.getPath(parent), name);
          return FS.symlink(target, path);
        },forceLoadFile:function (obj) {
          if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true;
          var success = true;
          if (typeof XMLHttpRequest !== 'undefined') {
            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.");
          } else if (Module['read']) {
            // Command-line.
            try {
              // WARNING: Can't read binary files in V8's d8 or tracemonkey's js, as
              //          read() will try to parse UTF8.
              obj.contents = intArrayFromString(Module['read'](obj.url), true);
              obj.usedBytes = obj.contents.length;
            } catch (e) {
              success = false;
            }
          } else {
            throw new Error('Cannot load without read() or XMLHttpRequest.');
          }
          if (!success) ___setErrNo(5);
          return success;
        },createLazyFile:function (parent, name, url, canRead, canWrite) {
          // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse.
          function LazyUint8Array() {
            this.lengthKnown = false;
            this.chunks = []; // Loaded chunks. Index is the chunk number
          }
          LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {
            if (idx > this.length-1 || idx < 0) {
              return undefined;
            }
            var chunkOffset = idx % this.chunkSize;
            var chunkNum = (idx / this.chunkSize)|0;
            return this.getter(chunkNum)[chunkOffset];
          }
          LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) {
            this.getter = getter;
          }
          LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {
            // Find length
            var xhr = new XMLHttpRequest();
            xhr.open('HEAD', url, false);
            xhr.send(null);
            if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
            var datalength = Number(xhr.getResponseHeader("Content-length"));
            var header;
            var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes";
            var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip";
    
            var chunkSize = 1024*1024; // Chunk size in bytes
    
            if (!hasByteServing) chunkSize = datalength;
    
            // Function to get a range from the remote URL.
            var doXHR = (function(from, to) {
              if (from > to) throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!");
              if (to > datalength-1) throw new Error("only " + datalength + " bytes available! programmer error!");
    
              // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available.
              var xhr = new XMLHttpRequest();
              xhr.open('GET', url, false);
              if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to);
    
              // Some hints to the browser that we want binary data.
              if (typeof Uint8Array != 'undefined') xhr.responseType = 'arraybuffer';
              if (xhr.overrideMimeType) {
                xhr.overrideMimeType('text/plain; charset=x-user-defined');
              }
    
              xhr.send(null);
              if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) throw new Error("Couldn't load " + url + ". Status: " + xhr.status);
              if (xhr.response !== undefined) {
                return new Uint8Array(xhr.response || []);
              } else {
                return intArrayFromString(xhr.responseText || '', true);
              }
            });
            var lazyArray = this;
            lazyArray.setDataGetter(function(chunkNum) {
              var start = chunkNum * chunkSize;
              var end = (chunkNum+1) * chunkSize - 1; // including this byte
              end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block
              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") {
                lazyArray.chunks[chunkNum] = doXHR(start, end);
              }
              if (typeof(lazyArray.chunks[chunkNum]) === "undefined") throw new Error("doXHR failed!");
              return lazyArray.chunks[chunkNum];
            });
    
            if (usesGzip || !datalength) {
              // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length
              chunkSize = datalength = 1; // this will force getter(0)/doXHR do download the whole file
              datalength = this.getter(0).length;
              chunkSize = datalength;
              console.log("LazyFiles on gzip forces download of the whole file when length is accessed");
            }
    
            this._length = datalength;
            this._chunkSize = chunkSize;
            this.lengthKnown = true;
          }
          if (typeof XMLHttpRequest !== 'undefined') {
            if (!ENVIRONMENT_IS_WORKER) throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc';
            var lazyArray = new LazyUint8Array();
            Object.defineProperties(lazyArray, {
              length: {
                get: function() {
                  if(!this.lengthKnown) {
                    this.cacheLength();
                  }
                  return this._length;
                }
              },
              chunkSize: {
                get: function() {
                  if(!this.lengthKnown) {
                    this.cacheLength();
                  }
                  return this._chunkSize;
                }
              }
            });
    
            var properties = { isDevice: false, contents: lazyArray };
          } else {
            var properties = { isDevice: false, url: url };
          }
    
          var node = FS.createFile(parent, name, properties, canRead, canWrite);
          // This is a total hack, but I want to get this lazy file code out of the
          // core of MEMFS. If we want to keep this lazy file concept I feel it should
          // be its own thin LAZYFS proxying calls to MEMFS.
          if (properties.contents) {
            node.contents = properties.contents;
          } else if (properties.url) {
            node.contents = null;
            node.url = properties.url;
          }
          // Add a function that defers querying the file size until it is asked the first time.
          Object.defineProperties(node, {
            usedBytes: {
              get: function() { return this.contents.length; }
            }
          });
          // override each stream op with one that tries to force load the lazy file first
          var stream_ops = {};
          var keys = Object.keys(node.stream_ops);
          keys.forEach(function(key) {
            var fn = node.stream_ops[key];
            stream_ops[key] = function forceLoadLazyFile() {
              if (!FS.forceLoadFile(node)) {
                throw new FS.ErrnoError(5);
              }
              return fn.apply(null, arguments);
            };
          });
          // use a custom read function
          stream_ops.read = function stream_ops_read(stream, buffer, offset, length, position) {
            if (!FS.forceLoadFile(node)) {
              throw new FS.ErrnoError(5);
            }
            var contents = stream.node.contents;
            if (position >= contents.length)
              return 0;
            var size = Math.min(contents.length - position, length);
            assert(size >= 0);
            if (contents.slice) { // normal array
              for (var i = 0; i < size; i++) {
                buffer[offset + i] = contents[position + i];
              }
            } else {
              for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR
                buffer[offset + i] = contents.get(position + i);
              }
            }
            return size;
          };
          node.stream_ops = stream_ops;
          return node;
        },createPreloadedFile:function (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) {
          Browser.init(); // XXX perhaps this method should move onto Browser?
          // TODO we should allow people to just pass in a complete filename instead
          // of parent and name being that we just join them anyways
          var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent;
          var dep = getUniqueRunDependency('cp ' + fullname); // might have several active requests for the same fullname
          function processData(byteArray) {
            function finish(byteArray) {
              if (preFinish) preFinish();
              if (!dontCreateFile) {
                FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn);
              }
              if (onload) onload();
              removeRunDependency(dep);
            }
            var handled = false;
            Module['preloadPlugins'].forEach(function(plugin) {
              if (handled) return;
              if (plugin['canHandle'](fullname)) {
                plugin['handle'](byteArray, fullname, finish, function() {
                  if (onerror) onerror();
                  removeRunDependency(dep);
                });
                handled = true;
              }
            });
            if (!handled) finish(byteArray);
          }
          addRunDependency(dep);
          if (typeof url == 'string') {
            Browser.asyncLoad(url, function(byteArray) {
              processData(byteArray);
            }, onerror);
          } else {
            processData(url);
          }
        },indexedDB:function () {
          return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
        },DB_NAME:function () {
          return 'EM_FS_' + window.location.pathname;
        },DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:function (paths, onload, onerror) {
          onload = onload || function(){};
          onerror = onerror || function(){};
          var indexedDB = FS.indexedDB();
          try {
            var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
          } catch (e) {
            return onerror(e);
          }
          openRequest.onupgradeneeded = function openRequest_onupgradeneeded() {
            console.log('creating db');
            var db = openRequest.result;
            db.createObjectStore(FS.DB_STORE_NAME);
          };
          openRequest.onsuccess = function openRequest_onsuccess() {
            var db = openRequest.result;
            var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite');
            var files = transaction.objectStore(FS.DB_STORE_NAME);
            var ok = 0, fail = 0, total = paths.length;
            function finish() {
              if (fail == 0) onload(); else onerror();
            }
            paths.forEach(function(path) {
              var putRequest = files.put(FS.analyzePath(path).object.contents, path);
              putRequest.onsuccess = function putRequest_onsuccess() { ok++; if (ok + fail == total) finish() };
              putRequest.onerror = function putRequest_onerror() { fail++; if (ok + fail == total) finish() };
            });
            transaction.onerror = onerror;
          };
          openRequest.onerror = onerror;
        },loadFilesFromDB:function (paths, onload, onerror) {
          onload = onload || function(){};
          onerror = onerror || function(){};
          var indexedDB = FS.indexedDB();
          try {
            var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION);
          } catch (e) {
            return onerror(e);
          }
          openRequest.onupgradeneeded = onerror; // no database to load from
          openRequest.onsuccess = function openRequest_onsuccess() {
            var db = openRequest.result;
            try {
              var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly');
            } catch(e) {
              onerror(e);
              return;
            }
            var files = transaction.objectStore(FS.DB_STORE_NAME);
            var ok = 0, fail = 0, total = paths.length;
            function finish() {
              if (fail == 0) onload(); else onerror();
            }
            paths.forEach(function(path) {
              var getRequest = files.get(path);
              getRequest.onsuccess = function getRequest_onsuccess() {
                if (FS.analyzePath(path).exists) {
                  FS.unlink(path);
                }
                FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true);
                ok++;
                if (ok + fail == total) finish();
              };
              getRequest.onerror = function getRequest_onerror() { fail++; if (ok + fail == total) finish() };
            });
            transaction.onerror = onerror;
          };
          openRequest.onerror = onerror;
        }};var SYSCALLS={DEFAULT_POLLMASK:5,mappings:{},umask:511,calculateAt:function (dirfd, path) {
          if (path[0] !== '/') {
            // relative path
            var dir;
            if (dirfd === -100) {
              dir = FS.cwd();
            } else {
              var dirstream = FS.getStream(dirfd);
              if (!dirstream) throw new FS.ErrnoError(9);
              dir = dirstream.path;
            }
            path = PATH.join2(dir, path);
          }
          return path;
        },doStat:function (func, path, buf) {
          try {
            var stat = func(path);
          } catch (e) {
            if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) {
              // an error occurred while trying to look up the path; we should just report ENOTDIR
              return -20;
            }
            throw e;
          }
          HEAP32[((buf)>>2)]=stat.dev;
          HEAP32[(((buf)+(4))>>2)]=0;
          HEAP32[(((buf)+(8))>>2)]=stat.ino;
          HEAP32[(((buf)+(12))>>2)]=stat.mode;
          HEAP32[(((buf)+(16))>>2)]=stat.nlink;
          HEAP32[(((buf)+(20))>>2)]=stat.uid;
          HEAP32[(((buf)+(24))>>2)]=stat.gid;
          HEAP32[(((buf)+(28))>>2)]=stat.rdev;
          HEAP32[(((buf)+(32))>>2)]=0;
          (tempI64 = [stat.size>>>0,(tempDouble=stat.size,(+(Math_abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math_min((+(Math_floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[(((buf)+(40))>>2)]=tempI64[0],HEAP32[(((buf)+(44))>>2)]=tempI64[1]);
          HEAP32[(((buf)+(48))>>2)]=4096;
          HEAP32[(((buf)+(52))>>2)]=stat.blocks;
          HEAP32[(((buf)+(56))>>2)]=(stat.atime.getTime() / 1000)|0;
          HEAP32[(((buf)+(60))>>2)]=0;
          HEAP32[(((buf)+(64))>>2)]=(stat.mtime.getTime() / 1000)|0;
          HEAP32[(((buf)+(68))>>2)]=0;
          HEAP32[(((buf)+(72))>>2)]=(stat.ctime.getTime() / 1000)|0;
          HEAP32[(((buf)+(76))>>2)]=0;
          (tempI64 = [stat.ino>>>0,(tempDouble=stat.ino,(+(Math_abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math_min((+(Math_floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[(((buf)+(80))>>2)]=tempI64[0],HEAP32[(((buf)+(84))>>2)]=tempI64[1]);
          return 0;
        },doMsync:function (addr, stream, len, flags) {
          var buffer = new Uint8Array(HEAPU8.subarray(addr, addr + len));
          FS.msync(stream, buffer, 0, len, flags);
        },doMkdir:function (path, mode) {
          // remove a trailing slash, if one - /a/b/ has basename of '', but
          // we want to create b in the context of this function
          path = PATH.normalize(path);
          if (path[path.length-1] === '/') path = path.substr(0, path.length-1);
          FS.mkdir(path, mode, 0);
          return 0;
        },doMknod:function (path, mode, dev) {
          // we don't want this in the JS API as it uses mknod to create all nodes.
          switch (mode & 61440) {
            case 32768:
            case 8192:
            case 24576:
            case 4096:
            case 49152:
              break;
            default: return -22;
          }
          FS.mknod(path, mode, dev);
          return 0;
        },doReadlink:function (path, buf, bufsize) {
          if (bufsize <= 0) return -22;
          var ret = FS.readlink(path);
    
          var len = Math.min(bufsize, lengthBytesUTF8(ret));
          var endChar = HEAP8[buf+len];
          stringToUTF8(ret, buf, bufsize+1);
          // readlink is one of the rare functions that write out a C string, but does never append a null to the output buffer(!)
          // stringToUTF8() always appends a null byte, so restore the character under the null byte after the write.
          HEAP8[buf+len] = endChar;
    
          return len;
        },doAccess:function (path, amode) {
          if (amode & ~7) {
            // need a valid mode
            return -22;
          }
          var node;
          var lookup = FS.lookupPath(path, { follow: true });
          node = lookup.node;
          var perms = '';
          if (amode & 4) perms += 'r';
          if (amode & 2) perms += 'w';
          if (amode & 1) perms += 'x';
          if (perms /* otherwise, they've just passed F_OK */ && FS.nodePermissions(node, perms)) {
            return -13;
          }
          return 0;
        },doDup:function (path, flags, suggestFD) {
          var suggest = FS.getStream(suggestFD);
          if (suggest) FS.close(suggest);
          return FS.open(path, flags, 0, suggestFD, suggestFD).fd;
        },doReadv:function (stream, iov, iovcnt, offset) {
          var ret = 0;
          for (var i = 0; i < iovcnt; i++) {
            var ptr = HEAP32[(((iov)+(i*8))>>2)];
            var len = HEAP32[(((iov)+(i*8 + 4))>>2)];
            var curr = FS.read(stream, HEAP8,ptr, len, offset);
            if (curr < 0) return -1;
            ret += curr;
            if (curr < len) break; // nothing more to read
          }
          return ret;
        },doWritev:function (stream, iov, iovcnt, offset) {
          var ret = 0;
          for (var i = 0; i < iovcnt; i++) {
            var ptr = HEAP32[(((iov)+(i*8))>>2)];
            var len = HEAP32[(((iov)+(i*8 + 4))>>2)];
            var curr = FS.write(stream, HEAP8,ptr, len, offset);
            if (curr < 0) return -1;
            ret += curr;
          }
          return ret;
        },varargs:0,get:function (varargs) {
          SYSCALLS.varargs += 4;
          var ret = HEAP32[(((SYSCALLS.varargs)-(4))>>2)];
          return ret;
        },getStr:function () {
          var ret = UTF8ToString(SYSCALLS.get());
          return ret;
        },getStreamFromFD:function () {
          var stream = FS.getStream(SYSCALLS.get());
          if (!stream) throw new FS.ErrnoError(9);
          return stream;
        },get64:function () {
          var low = SYSCALLS.get(), high = SYSCALLS.get();
          if (low >= 0) assert(high === 0);
          else assert(high === -1);
          return low;
        },getZero:function () {
          assert(SYSCALLS.get() === 0);
        }};function ___syscall10(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // unlink
        var path = SYSCALLS.getStr();
        FS.unlink(path);
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    
    var SOCKFS={mount:function (mount) {
          // If Module['websocket'] has already been defined (e.g. for configuring
          // the subprotocol/url) use that, if not initialise it to a new object.
          Module['websocket'] = (Module['websocket'] && 
                                 ('object' === typeof Module['websocket'])) ? Module['websocket'] : {};
    
          // Add the Event registration mechanism to the exported websocket configuration
          // object so we can register network callbacks from native JavaScript too.
          // For more documentation see system/include/emscripten/emscripten.h
          Module['websocket']._callbacks = {};
          Module['websocket']['on'] = function(event, callback) {
    	    if ('function' === typeof callback) {
    		  this._callbacks[event] = callback;
            }
    	    return this;
          };
    
          Module['websocket'].emit = function(event, param) {
    	    if ('function' === typeof this._callbacks[event]) {
    		  this._callbacks[event].call(this, param);
            }
          };
    
          // If debug is enabled register simple default logging callbacks for each Event.
    
          return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
        },createSocket:function (family, type, protocol) {
          var streaming = type == 1;
          if (protocol) {
            assert(streaming == (protocol == 6)); // if SOCK_STREAM, must be tcp
          }
    
          // create our internal socket structure
          var sock = {
            family: family,
            type: type,
            protocol: protocol,
            server: null,
            error: null, // Used in getsockopt for SOL_SOCKET/SO_ERROR test
            peers: {},
            pending: [],
            recv_queue: [],
            sock_ops: SOCKFS.websocket_sock_ops
          };
    
          // create the filesystem node to store the socket structure
          var name = SOCKFS.nextname();
          var node = FS.createNode(SOCKFS.root, name, 49152, 0);
          node.sock = sock;
    
          // and the wrapping stream that enables library functions such
          // as read and write to indirectly interact with the socket
          var stream = FS.createStream({
            path: name,
            node: node,
            flags: FS.modeStringToFlags('r+'),
            seekable: false,
            stream_ops: SOCKFS.stream_ops
          });
    
          // map the new stream to the socket structure (sockets have a 1:1
          // relationship with a stream)
          sock.stream = stream;
    
          return sock;
        },getSocket:function (fd) {
          var stream = FS.getStream(fd);
          if (!stream || !FS.isSocket(stream.node.mode)) {
            return null;
          }
          return stream.node.sock;
        },stream_ops:{poll:function (stream) {
            var sock = stream.node.sock;
            return sock.sock_ops.poll(sock);
          },ioctl:function (stream, request, varargs) {
            var sock = stream.node.sock;
            return sock.sock_ops.ioctl(sock, request, varargs);
          },read:function (stream, buffer, offset, length, position /* ignored */) {
            var sock = stream.node.sock;
            var msg = sock.sock_ops.recvmsg(sock, length);
            if (!msg) {
              // socket is closed
              return 0;
            }
            buffer.set(msg.buffer, offset);
            return msg.buffer.length;
          },write:function (stream, buffer, offset, length, position /* ignored */) {
            var sock = stream.node.sock;
            return sock.sock_ops.sendmsg(sock, buffer, offset, length);
          },close:function (stream) {
            var sock = stream.node.sock;
            sock.sock_ops.close(sock);
          }},nextname:function () {
          if (!SOCKFS.nextname.current) {
            SOCKFS.nextname.current = 0;
          }
          return 'socket[' + (SOCKFS.nextname.current++) + ']';
        },websocket_sock_ops:{createPeer:function (sock, addr, port) {
            var ws;
    
            if (typeof addr === 'object') {
              ws = addr;
              addr = null;
              port = null;
            }
    
            if (ws) {
              // for sockets that've already connected (e.g. we're the server)
              // we can inspect the _socket property for the address
              if (ws._socket) {
                addr = ws._socket.remoteAddress;
                port = ws._socket.remotePort;
              }
              // if we're just now initializing a connection to the remote,
              // inspect the url property
              else {
                var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);
                if (!result) {
                  throw new Error('WebSocket URL must be in the format ws(s)://address:port');
                }
                addr = result[1];
                port = parseInt(result[2], 10);
              }
            } else {
              // create the actual websocket object and connect
              try {
                // runtimeConfig gets set to true if WebSocket runtime configuration is available.
                var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket']));
    
                // The default value is 'ws://' the replace is needed because the compiler replaces '//' comments with '#'
                // comments without checking context, so we'd end up with ws:#, the replace swaps the '#' for '//' again.
                var url = 'ws:#'.replace('#', '//');
    
                if (runtimeConfig) {
                  if ('string' === typeof Module['websocket']['url']) {
                    url = Module['websocket']['url']; // Fetch runtime WebSocket URL config.
                  }
                }
    
                if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it.
                  var parts = addr.split('/');
                  url = url + parts[0] + ":" + port + "/" + parts.slice(1).join('/');
                }
    
                // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set.
                var subProtocols = 'binary'; // The default value is 'binary'
    
                if (runtimeConfig) {
                  if ('string' === typeof Module['websocket']['subprotocol']) {
                    subProtocols = Module['websocket']['subprotocol']; // Fetch runtime WebSocket subprotocol config.
                  }
                }
    
                // The regex trims the string (removes spaces at the beginning and end, then splits the string by
                // <any space>,<any space> into an Array. Whitespace removal is important for Websockify and ws.
                subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */);
    
                // The node ws library API for specifying optional subprotocol is slightly different than the browser's.
                var opts = ENVIRONMENT_IS_NODE ? {'protocol': subProtocols.toString()} : subProtocols;
    
                // some webservers (azure) does not support subprotocol header
                if (runtimeConfig && null === Module['websocket']['subprotocol']) {
                  subProtocols = 'null';
                  opts = undefined;
                }
    
                // If node we use the ws library.
                var WebSocketConstructor;
                if (ENVIRONMENT_IS_NODE) {
                  WebSocketConstructor = require('ws');
                } else
                if (ENVIRONMENT_IS_WEB) {
                  WebSocketConstructor = window['WebSocket'];
                } else
                {
                  WebSocketConstructor = WebSocket;
                }
                ws = new WebSocketConstructor(url, opts);
                ws.binaryType = 'arraybuffer';
              } catch (e) {
                throw new FS.ErrnoError(ERRNO_CODES.EHOSTUNREACH);
              }
            }
    
    
            var peer = {
              addr: addr,
              port: port,
              socket: ws,
              dgram_send_queue: []
            };
    
            SOCKFS.websocket_sock_ops.addPeer(sock, peer);
            SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer);
    
            // if this is a bound dgram socket, send the port number first to allow
            // us to override the ephemeral port reported to us by remotePort on the
            // remote end.
            if (sock.type === 2 && typeof sock.sport !== 'undefined') {
              peer.dgram_send_queue.push(new Uint8Array([
                  255, 255, 255, 255,
                  'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0),
                  ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff)
              ]));
            }
    
            return peer;
          },getPeer:function (sock, addr, port) {
            return sock.peers[addr + ':' + port];
          },addPeer:function (sock, peer) {
            sock.peers[peer.addr + ':' + peer.port] = peer;
          },removePeer:function (sock, peer) {
            delete sock.peers[peer.addr + ':' + peer.port];
          },handlePeerEvents:function (sock, peer) {
            var first = true;
    
            var handleOpen = function () {
    
              Module['websocket'].emit('open', sock.stream.fd);
    
              try {
                var queued = peer.dgram_send_queue.shift();
                while (queued) {
                  peer.socket.send(queued);
                  queued = peer.dgram_send_queue.shift();
                }
              } catch (e) {
                // not much we can do here in the way of proper error handling as we've already
                // lied and said this data was sent. shut it down.
                peer.socket.close();
              }
            };
    
            function handleMessage(data) {
              assert(typeof data !== 'string' && data.byteLength !== undefined);  // must receive an ArrayBuffer
    
              // An empty ArrayBuffer will emit a pseudo disconnect event
              // as recv/recvmsg will return zero which indicates that a socket
              // has performed a shutdown although the connection has not been disconnected yet.
              if (data.byteLength == 0) {
                return;
              }
              data = new Uint8Array(data);  // make a typed array view on the array buffer
    
    
              // if this is the port message, override the peer's port with it
              var wasfirst = first;
              first = false;
              if (wasfirst &&
                  data.length === 10 &&
                  data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 &&
                  data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) {
                // update the peer's port and it's key in the peer map
                var newport = ((data[8] << 8) | data[9]);
                SOCKFS.websocket_sock_ops.removePeer(sock, peer);
                peer.port = newport;
                SOCKFS.websocket_sock_ops.addPeer(sock, peer);
                return;
              }
    
              sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data });
              Module['websocket'].emit('message', sock.stream.fd);
            };
    
            if (ENVIRONMENT_IS_NODE) {
              peer.socket.on('open', handleOpen);
              peer.socket.on('message', function(data, flags) {
                if (!flags.binary) {
                  return;
                }
                handleMessage((new Uint8Array(data)).buffer);  // copy from node Buffer -> ArrayBuffer
              });
              peer.socket.on('close', function() {
                Module['websocket'].emit('close', sock.stream.fd);
              });
              peer.socket.on('error', function(error) {
                // Although the ws library may pass errors that may be more descriptive than
                // ECONNREFUSED they are not necessarily the expected error code e.g. 
                // ENOTFOUND on getaddrinfo seems to be node.js specific, so using ECONNREFUSED
                // is still probably the most useful thing to do.
                sock.error = ERRNO_CODES.ECONNREFUSED; // Used in getsockopt for SOL_SOCKET/SO_ERROR test.
                Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']);
                // don't throw
              });
            } else {
              peer.socket.onopen = handleOpen;
              peer.socket.onclose = function() {
                Module['websocket'].emit('close', sock.stream.fd);
              };
              peer.socket.onmessage = function peer_socket_onmessage(event) {
                handleMessage(event.data);
              };
              peer.socket.onerror = function(error) {
                // The WebSocket spec only allows a 'simple event' to be thrown on error,
                // so we only really know as much as ECONNREFUSED.
                sock.error = ERRNO_CODES.ECONNREFUSED; // Used in getsockopt for SOL_SOCKET/SO_ERROR test.
                Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']);
              };
            }
          },poll:function (sock) {
            if (sock.type === 1 && sock.server) {
              // listen sockets should only say they're available for reading
              // if there are pending clients.
              return sock.pending.length ? (64 | 1) : 0;
            }
    
            var mask = 0;
            var dest = sock.type === 1 ?  // we only care about the socket state for connection-based sockets
              SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) :
              null;
    
            if (sock.recv_queue.length ||
                !dest ||  // connection-less sockets are always ready to read
                (dest && dest.socket.readyState === dest.socket.CLOSING) ||
                (dest && dest.socket.readyState === dest.socket.CLOSED)) {  // let recv return 0 once closed
              mask |= (64 | 1);
            }
    
            if (!dest ||  // connection-less sockets are always ready to write
                (dest && dest.socket.readyState === dest.socket.OPEN)) {
              mask |= 4;
            }
    
            if ((dest && dest.socket.readyState === dest.socket.CLOSING) ||
                (dest && dest.socket.readyState === dest.socket.CLOSED)) {
              mask |= 16;
            }
    
            return mask;
          },ioctl:function (sock, request, arg) {
            switch (request) {
              case 21531:
                var bytes = 0;
                if (sock.recv_queue.length) {
                  bytes = sock.recv_queue[0].data.length;
                }
                HEAP32[((arg)>>2)]=bytes;
                return 0;
              default:
                return ERRNO_CODES.EINVAL;
            }
          },close:function (sock) {
            // if we've spawned a listen server, close it
            if (sock.server) {
              try {
                sock.server.close();
              } catch (e) {
              }
              sock.server = null;
            }
            // close any peer connections
            var peers = Object.keys(sock.peers);
            for (var i = 0; i < peers.length; i++) {
              var peer = sock.peers[peers[i]];
              try {
                peer.socket.close();
              } catch (e) {
              }
              SOCKFS.websocket_sock_ops.removePeer(sock, peer);
            }
            return 0;
          },bind:function (sock, addr, port) {
            if (typeof sock.saddr !== 'undefined' || typeof sock.sport !== 'undefined') {
              throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already bound
            }
            sock.saddr = addr;
            sock.sport = port;
            // in order to emulate dgram sockets, we need to launch a listen server when
            // binding on a connection-less socket
            // note: this is only required on the server side
            if (sock.type === 2) {
              // close the existing server if it exists
              if (sock.server) {
                sock.server.close();
                sock.server = null;
              }
              // swallow error operation not supported error that occurs when binding in the
              // browser where this isn't supported
              try {
                sock.sock_ops.listen(sock, 0);
              } catch (e) {
                if (!(e instanceof FS.ErrnoError)) throw e;
                if (e.errno !== ERRNO_CODES.EOPNOTSUPP) throw e;
              }
            }
          },connect:function (sock, addr, port) {
            if (sock.server) {
              throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
            }
    
            // TODO autobind
            // if (!sock.addr && sock.type == 2) {
            // }
    
            // early out if we're already connected / in the middle of connecting
            if (typeof sock.daddr !== 'undefined' && typeof sock.dport !== 'undefined') {
              var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
              if (dest) {
                if (dest.socket.readyState === dest.socket.CONNECTING) {
                  throw new FS.ErrnoError(ERRNO_CODES.EALREADY);
                } else {
                  throw new FS.ErrnoError(ERRNO_CODES.EISCONN);
                }
              }
            }
    
            // add the socket to our peer list and set our
            // destination address / port to match
            var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
            sock.daddr = peer.addr;
            sock.dport = peer.port;
    
            // always "fail" in non-blocking mode
            throw new FS.ErrnoError(ERRNO_CODES.EINPROGRESS);
          },listen:function (sock, backlog) {
            if (!ENVIRONMENT_IS_NODE) {
              throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP);
            }
            if (sock.server) {
               throw new FS.ErrnoError(ERRNO_CODES.EINVAL);  // already listening
            }
            var WebSocketServer = require('ws').Server;
            var host = sock.saddr;
            sock.server = new WebSocketServer({
              host: host,
              port: sock.sport
              // TODO support backlog
            });
            Module['websocket'].emit('listen', sock.stream.fd); // Send Event with listen fd.
    
            sock.server.on('connection', function(ws) {
              if (sock.type === 1) {
                var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol);
    
                // create a peer on the new socket
                var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws);
                newsock.daddr = peer.addr;
                newsock.dport = peer.port;
    
                // push to queue for accept to pick up
                sock.pending.push(newsock);
                Module['websocket'].emit('connection', newsock.stream.fd);
              } else {
                // create a peer on the listen socket so calling sendto
                // with the listen socket and an address will resolve
                // to the correct client
                SOCKFS.websocket_sock_ops.createPeer(sock, ws);
                Module['websocket'].emit('connection', sock.stream.fd);
              }
            });
            sock.server.on('closed', function() {
              Module['websocket'].emit('close', sock.stream.fd);
              sock.server = null;
            });
            sock.server.on('error', function(error) {
              // Although the ws library may pass errors that may be more descriptive than
              // ECONNREFUSED they are not necessarily the expected error code e.g. 
              // ENOTFOUND on getaddrinfo seems to be node.js specific, so using EHOSTUNREACH
              // is still probably the most useful thing to do. This error shouldn't
              // occur in a well written app as errors should get trapped in the compiled
              // app's own getaddrinfo call.
              sock.error = ERRNO_CODES.EHOSTUNREACH; // Used in getsockopt for SOL_SOCKET/SO_ERROR test.
              Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'EHOSTUNREACH: Host is unreachable']);
              // don't throw
            });
          },accept:function (listensock) {
            if (!listensock.server) {
              throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
            }
            var newsock = listensock.pending.shift();
            newsock.stream.flags = listensock.stream.flags;
            return newsock;
          },getname:function (sock, peer) {
            var addr, port;
            if (peer) {
              if (sock.daddr === undefined || sock.dport === undefined) {
                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
              }
              addr = sock.daddr;
              port = sock.dport;
            } else {
              // TODO saddr and sport will be set for bind()'d UDP sockets, but what
              // should we be returning for TCP sockets that've been connect()'d?
              addr = sock.saddr || 0;
              port = sock.sport || 0;
            }
            return { addr: addr, port: port };
          },sendmsg:function (sock, buffer, offset, length, addr, port) {
            if (sock.type === 2) {
              // connection-less sockets will honor the message address,
              // and otherwise fall back to the bound destination address
              if (addr === undefined || port === undefined) {
                addr = sock.daddr;
                port = sock.dport;
              }
              // if there was no address to fall back to, error out
              if (addr === undefined || port === undefined) {
                throw new FS.ErrnoError(ERRNO_CODES.EDESTADDRREQ);
              }
            } else {
              // connection-based sockets will only use the bound
              addr = sock.daddr;
              port = sock.dport;
            }
    
            // find the peer for the destination address
            var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port);
    
            // early out if not connected with a connection-based socket
            if (sock.type === 1) {
              if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
                throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
              } else if (dest.socket.readyState === dest.socket.CONNECTING) {
                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
              }
            }
    
            // create a copy of the incoming data to send, as the WebSocket API
            // doesn't work entirely with an ArrayBufferView, it'll just send
            // the entire underlying buffer
            if (ArrayBuffer.isView(buffer)) {
              offset += buffer.byteOffset;
              buffer = buffer.buffer;
            }
    
            var data;
              data = buffer.slice(offset, offset + length);
    
            // if we're emulating a connection-less dgram socket and don't have
            // a cached connection, queue the buffer to send upon connect and
            // lie, saying the data was sent now.
            if (sock.type === 2) {
              if (!dest || dest.socket.readyState !== dest.socket.OPEN) {
                // if we're not connected, open a new connection
                if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
                  dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port);
                }
                dest.dgram_send_queue.push(data);
                return length;
              }
            }
    
            try {
              // send the actual data
              dest.socket.send(data);
              return length;
            } catch (e) {
              throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
            }
          },recvmsg:function (sock, length) {
            // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html
            if (sock.type === 1 && sock.server) {
              // tcp servers should not be recv()'ing on the listen socket
              throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
            }
    
            var queued = sock.recv_queue.shift();
            if (!queued) {
              if (sock.type === 1) {
                var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport);
    
                if (!dest) {
                  // if we have a destination address but are not connected, error out
                  throw new FS.ErrnoError(ERRNO_CODES.ENOTCONN);
                }
                else if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) {
                  // return null if the socket has closed
                  return null;
                }
                else {
                  // else, our socket is in a valid state but truly has nothing available
                  throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
                }
              } else {
                throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
              }
            }
    
            // queued.data will be an ArrayBuffer if it's unadulterated, but if it's
            // requeued TCP data it'll be an ArrayBufferView
            var queuedLength = queued.data.byteLength || queued.data.length;
            var queuedOffset = queued.data.byteOffset || 0;
            var queuedBuffer = queued.data.buffer || queued.data;
            var bytesRead = Math.min(length, queuedLength);
            var res = {
              buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead),
              addr: queued.addr,
              port: queued.port
            };
    
    
            // push back any unread data for TCP connections
            if (sock.type === 1 && bytesRead < queuedLength) {
              var bytesRemaining = queuedLength - bytesRead;
              queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining);
              sock.recv_queue.unshift(queued);
            }
    
            return res;
          }}};
    
    
    function __inet_pton4_raw(str) {
        var b = str.split('.');
        for (var i = 0; i < 4; i++) {
          var tmp = Number(b[i]);
          if (isNaN(tmp)) return null;
          b[i] = tmp;
        }
        return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0;
      }
    
    function __inet_pton6_raw(str) {
        var words;
        var w, offset, z, i;
        /* http://home.deds.nl/~aeron/regex/ */
        var valid6regx = /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i
        var parts = [];
        if (!valid6regx.test(str)) {
          return null;
        }
        if (str === "::") {
          return [0, 0, 0, 0, 0, 0, 0, 0];
        }
        // Z placeholder to keep track of zeros when splitting the string on ":"
        if (str.indexOf("::") === 0) {
          str = str.replace("::", "Z:"); // leading zeros case
        } else {
          str = str.replace("::", ":Z:");
        }
    
        if (str.indexOf(".") > 0) {
          // parse IPv4 embedded stress
          str = str.replace(new RegExp('[.]', 'g'), ":");
          words = str.split(":");
          words[words.length-4] = parseInt(words[words.length-4]) + parseInt(words[words.length-3])*256;
          words[words.length-3] = parseInt(words[words.length-2]) + parseInt(words[words.length-1])*256;
          words = words.slice(0, words.length-2);
        } else {
          words = str.split(":");
        }
    
        offset = 0; z = 0;
        for (w=0; w < words.length; w++) {
          if (typeof words[w] === 'string') {
            if (words[w] === 'Z') {
              // compressed zeros - write appropriate number of zero words
              for (z = 0; z < (8 - words.length+1); z++) {
                parts[w+z] = 0;
              }
              offset = z-1;
            } else {
              // parse hex to field to 16-bit value and write it in network byte-order
              parts[w+offset] = _htons(parseInt(words[w],16));
            }
          } else {
            // parsed IPv4 words
            parts[w+offset] = words[w];
          }
        }
        return [
          (parts[1] << 16) | parts[0],
          (parts[3] << 16) | parts[2],
          (parts[5] << 16) | parts[4],
          (parts[7] << 16) | parts[6]
        ];
      }var DNS={address_map:{id:1,addrs:{},names:{}},lookup_name:function (name) {
          // If the name is already a valid ipv4 / ipv6 address, don't generate a fake one.
          var res = __inet_pton4_raw(name);
          if (res !== null) {
            return name;
          }
          res = __inet_pton6_raw(name);
          if (res !== null) {
            return name;
          }
    
          // See if this name is already mapped.
          var addr;
    
          if (DNS.address_map.addrs[name]) {
            addr = DNS.address_map.addrs[name];
          } else {
            var id = DNS.address_map.id++;
            assert(id < 65535, 'exceeded max address mappings of 65535');
    
            addr = '172.29.' + (id & 0xff) + '.' + (id & 0xff00);
    
            DNS.address_map.names[addr] = name;
            DNS.address_map.addrs[name] = addr;
          }
    
          return addr;
        },lookup_addr:function (addr) {
          if (DNS.address_map.names[addr]) {
            return DNS.address_map.names[addr];
          }
    
          return null;
        }};
    
    
    var Sockets={BUFFER_SIZE:10240,MAX_BUFFER_SIZE:10485760,nextFd:1,fds:{},nextport:1,maxport:65535,peer:null,connections:{},portmap:{},localAddr:4261412874,addrPool:[33554442,50331658,67108874,83886090,100663306,117440522,134217738,150994954,167772170,184549386,201326602,218103818,234881034]};
    
    function __inet_ntop4_raw(addr) {
        return (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff)
      }
    
    function __inet_ntop6_raw(ints) {
        //  ref:  http://www.ietf.org/rfc/rfc2373.txt - section 2.5.4
        //  Format for IPv4 compatible and mapped  128-bit IPv6 Addresses
        //  128-bits are split into eight 16-bit words
        //  stored in network byte order (big-endian)
        //  |                80 bits               | 16 |      32 bits        |
        //  +-----------------------------------------------------------------+
        //  |               10 bytes               |  2 |      4 bytes        |
        //  +--------------------------------------+--------------------------+
        //  +               5 words                |  1 |      2 words        |
        //  +--------------------------------------+--------------------------+
        //  |0000..............................0000|0000|    IPv4 ADDRESS     | (compatible)
        //  +--------------------------------------+----+---------------------+
        //  |0000..............................0000|FFFF|    IPv4 ADDRESS     | (mapped)
        //  +--------------------------------------+----+---------------------+
        var str = "";
        var word = 0;
        var longest = 0;
        var lastzero = 0;
        var zstart = 0;
        var len = 0;
        var i = 0;
        var parts = [
          ints[0] & 0xffff,
          (ints[0] >> 16),
          ints[1] & 0xffff,
          (ints[1] >> 16),
          ints[2] & 0xffff,
          (ints[2] >> 16),
          ints[3] & 0xffff,
          (ints[3] >> 16)
        ];
    
        // Handle IPv4-compatible, IPv4-mapped, loopback and any/unspecified addresses
    
        var hasipv4 = true;
        var v4part = "";
        // check if the 10 high-order bytes are all zeros (first 5 words)
        for (i = 0; i < 5; i++) {
          if (parts[i] !== 0) { hasipv4 = false; break; }
        }
    
        if (hasipv4) {
          // low-order 32-bits store an IPv4 address (bytes 13 to 16) (last 2 words)
          v4part = __inet_ntop4_raw(parts[6] | (parts[7] << 16));
          // IPv4-mapped IPv6 address if 16-bit value (bytes 11 and 12) == 0xFFFF (6th word)
          if (parts[5] === -1) {
            str = "::ffff:";
            str += v4part;
            return str;
          }
          // IPv4-compatible IPv6 address if 16-bit value (bytes 11 and 12) == 0x0000 (6th word)
          if (parts[5] === 0) {
            str = "::";
            //special case IPv6 addresses
            if(v4part === "0.0.0.0") v4part = ""; // any/unspecified address
            if(v4part === "0.0.0.1") v4part = "1";// loopback address
            str += v4part;
            return str;
          }
        }
    
        // Handle all other IPv6 addresses
    
        // first run to find the longest contiguous zero words
        for (word = 0; word < 8; word++) {
          if (parts[word] === 0) {
            if (word - lastzero > 1) {
              len = 0;
            }
            lastzero = word;
            len++;
          }
          if (len > longest) {
            longest = len;
            zstart = word - longest + 1;
          }
        }
    
        for (word = 0; word < 8; word++) {
          if (longest > 1) {
            // compress contiguous zeros - to produce "::"
            if (parts[word] === 0 && word >= zstart && word < (zstart + longest) ) {
              if (word === zstart) {
                str += ":";
                if (zstart === 0) str += ":"; //leading zeros case
              }
              continue;
            }
          }
          // converts 16-bit words from big-endian to little-endian before converting to hex string
          str += Number(_ntohs(parts[word] & 0xffff)).toString(16);
          str += word < 7 ? ":" : "";
        }
        return str;
      }function __read_sockaddr(sa, salen) {
        // family / port offsets are common to both sockaddr_in and sockaddr_in6
        var family = HEAP16[((sa)>>1)];
        var port = _ntohs(HEAP16[(((sa)+(2))>>1)]);
        var addr;
    
        switch (family) {
          case 2:
            if (salen !== 16) {
              return { errno: 22 };
            }
            addr = HEAP32[(((sa)+(4))>>2)];
            addr = __inet_ntop4_raw(addr);
            break;
          case 10:
            if (salen !== 28) {
              return { errno: 22 };
            }
            addr = [
              HEAP32[(((sa)+(8))>>2)],
              HEAP32[(((sa)+(12))>>2)],
              HEAP32[(((sa)+(16))>>2)],
              HEAP32[(((sa)+(20))>>2)]
            ];
            addr = __inet_ntop6_raw(addr);
            break;
          default:
            return { errno: 97 };
        }
    
        return { family: family, addr: addr, port: port };
      }
    
    function __write_sockaddr(sa, family, addr, port) {
        switch (family) {
          case 2:
            addr = __inet_pton4_raw(addr);
            HEAP16[((sa)>>1)]=family;
            HEAP32[(((sa)+(4))>>2)]=addr;
            HEAP16[(((sa)+(2))>>1)]=_htons(port);
            break;
          case 10:
            addr = __inet_pton6_raw(addr);
            HEAP32[((sa)>>2)]=family;
            HEAP32[(((sa)+(8))>>2)]=addr[0];
            HEAP32[(((sa)+(12))>>2)]=addr[1];
            HEAP32[(((sa)+(16))>>2)]=addr[2];
            HEAP32[(((sa)+(20))>>2)]=addr[3];
            HEAP16[(((sa)+(2))>>1)]=_htons(port);
            HEAP32[(((sa)+(4))>>2)]=0;
            HEAP32[(((sa)+(24))>>2)]=0;
            break;
          default:
            return { errno: 97 };
        }
        // kind of lame, but let's match _read_sockaddr's interface
        return {};
      }function ___syscall102(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // socketcall
        var call = SYSCALLS.get(), socketvararg = SYSCALLS.get();
        // socketcalls pass the rest of the arguments in a struct
        SYSCALLS.varargs = socketvararg;
    
        var getSocketFromFD = function() {
          var socket = SOCKFS.getSocket(SYSCALLS.get());
          if (!socket) throw new FS.ErrnoError(9);
          return socket;
        };
        var getSocketAddress = function(allowNull) {
          var addrp = SYSCALLS.get(), addrlen = SYSCALLS.get();
          if (allowNull && addrp === 0) return null;
          var info = __read_sockaddr(addrp, addrlen);
          if (info.errno) throw new FS.ErrnoError(info.errno);
          info.addr = DNS.lookup_addr(info.addr) || info.addr;
          return info;
        };
    
        switch (call) {
          case 1: { // socket
            var domain = SYSCALLS.get(), type = SYSCALLS.get(), protocol = SYSCALLS.get();
            var sock = SOCKFS.createSocket(domain, type, protocol);
            assert(sock.stream.fd < 64); // XXX ? select() assumes socket fd values are in 0..63
            return sock.stream.fd;
          }
          case 2: { // bind
            var sock = getSocketFromFD(), info = getSocketAddress();
            sock.sock_ops.bind(sock, info.addr, info.port);
            return 0;
          }
          case 3: { // connect
            var sock = getSocketFromFD(), info = getSocketAddress();
            sock.sock_ops.connect(sock, info.addr, info.port);
            return 0;
          }
          case 4: { // listen
            var sock = getSocketFromFD(), backlog = SYSCALLS.get();
            sock.sock_ops.listen(sock, backlog);
            return 0;
          }
          case 5: { // accept
            var sock = getSocketFromFD(), addr = SYSCALLS.get(), addrlen = SYSCALLS.get();
            var newsock = sock.sock_ops.accept(sock);
            if (addr) {
              var res = __write_sockaddr(addr, newsock.family, DNS.lookup_name(newsock.daddr), newsock.dport);
              assert(!res.errno);
            }
            return newsock.stream.fd;
          }
          case 6: { // getsockname
            var sock = getSocketFromFD(), addr = SYSCALLS.get(), addrlen = SYSCALLS.get();
            // TODO: sock.saddr should never be undefined, see TODO in websocket_sock_ops.getname
            var res = __write_sockaddr(addr, sock.family, DNS.lookup_name(sock.saddr || '0.0.0.0'), sock.sport);
            assert(!res.errno);
            return 0;
          }
          case 7: { // getpeername
            var sock = getSocketFromFD(), addr = SYSCALLS.get(), addrlen = SYSCALLS.get();
            if (!sock.daddr) {
              return -107; // The socket is not connected.
            }
            var res = __write_sockaddr(addr, sock.family, DNS.lookup_name(sock.daddr), sock.dport);
            assert(!res.errno);
            return 0;
          }
          case 11: { // sendto
            var sock = getSocketFromFD(), message = SYSCALLS.get(), length = SYSCALLS.get(), flags = SYSCALLS.get(), dest = getSocketAddress(true);
            if (!dest) {
              // send, no address provided
              return FS.write(sock.stream, HEAP8,message, length);
            } else {
              // sendto an address
              return sock.sock_ops.sendmsg(sock, HEAP8,message, length, dest.addr, dest.port);
            }
          }
          case 12: { // recvfrom
            var sock = getSocketFromFD(), buf = SYSCALLS.get(), len = SYSCALLS.get(), flags = SYSCALLS.get(), addr = SYSCALLS.get(), addrlen = SYSCALLS.get();
            var msg = sock.sock_ops.recvmsg(sock, len);
            if (!msg) return 0; // socket is closed
            if (addr) {
              var res = __write_sockaddr(addr, sock.family, DNS.lookup_name(msg.addr), msg.port);
              assert(!res.errno);
            }
            HEAPU8.set(msg.buffer, buf);
            return msg.buffer.byteLength;
          }
          case 14: { // setsockopt
            return -92; // The option is unknown at the level indicated.
          }
          case 15: { // getsockopt
            var sock = getSocketFromFD(), level = SYSCALLS.get(), optname = SYSCALLS.get(), optval = SYSCALLS.get(), optlen = SYSCALLS.get();
            // Minimal getsockopt aimed at resolving https://github.com/emscripten-core/emscripten/issues/2211
            // so only supports SOL_SOCKET with SO_ERROR.
            if (level === 1) {
              if (optname === 4) {
                HEAP32[((optval)>>2)]=sock.error;
                HEAP32[((optlen)>>2)]=4;
                sock.error = null; // Clear the error (The SO_ERROR option obtains and then clears this field).
                return 0;
              }
            }
            return -92; // The option is unknown at the level indicated.
          }
          case 16: { // sendmsg
            var sock = getSocketFromFD(), message = SYSCALLS.get(), flags = SYSCALLS.get();
            var iov = HEAP32[(((message)+(8))>>2)];
            var num = HEAP32[(((message)+(12))>>2)];
            // read the address and port to send to
            var addr, port;
            var name = HEAP32[((message)>>2)];
            var namelen = HEAP32[(((message)+(4))>>2)];
            if (name) {
              var info = __read_sockaddr(name, namelen);
              if (info.errno) return -info.errno;
              port = info.port;
              addr = DNS.lookup_addr(info.addr) || info.addr;
            }
            // concatenate scatter-gather arrays into one message buffer
            var total = 0;
            for (var i = 0; i < num; i++) {
              total += HEAP32[(((iov)+((8 * i) + 4))>>2)];
            }
            var view = new Uint8Array(total);
            var offset = 0;
            for (var i = 0; i < num; i++) {
              var iovbase = HEAP32[(((iov)+((8 * i) + 0))>>2)];
              var iovlen = HEAP32[(((iov)+((8 * i) + 4))>>2)];
              for (var j = 0; j < iovlen; j++) {  
                view[offset++] = HEAP8[(((iovbase)+(j))>>0)];
              }
            }
            // write the buffer
            return sock.sock_ops.sendmsg(sock, view, 0, total, addr, port);
          }
          case 17: { // recvmsg
            var sock = getSocketFromFD(), message = SYSCALLS.get(), flags = SYSCALLS.get();
            var iov = HEAP32[(((message)+(8))>>2)];
            var num = HEAP32[(((message)+(12))>>2)];
            // get the total amount of data we can read across all arrays
            var total = 0;
            for (var i = 0; i < num; i++) {
              total += HEAP32[(((iov)+((8 * i) + 4))>>2)];
            }
            // try to read total data
            var msg = sock.sock_ops.recvmsg(sock, total);
            if (!msg) return 0; // socket is closed
    
            // TODO honor flags:
            // MSG_OOB
            // Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific.
            // MSG_PEEK
            // Peeks at the incoming message.
            // MSG_WAITALL
            // Requests that the function block until the full amount of data requested can be returned. The function may return a smaller amount of data if a signal is caught, if the connection is terminated, if MSG_PEEK was specified, or if an error is pending for the socket.
    
            // write the source address out
            var name = HEAP32[((message)>>2)];
            if (name) {
              var res = __write_sockaddr(name, sock.family, DNS.lookup_name(msg.addr), msg.port);
              assert(!res.errno);
            }
            // write the buffer out to the scatter-gather arrays
            var bytesRead = 0;
            var bytesRemaining = msg.buffer.byteLength;
            for (var i = 0; bytesRemaining > 0 && i < num; i++) {
              var iovbase = HEAP32[(((iov)+((8 * i) + 0))>>2)];
              var iovlen = HEAP32[(((iov)+((8 * i) + 4))>>2)];
              if (!iovlen) {
                continue;
              }
              var length = Math.min(iovlen, bytesRemaining);
              var buf = msg.buffer.subarray(bytesRead, bytesRead + length);
              HEAPU8.set(buf, iovbase + bytesRead);
              bytesRead += length;
              bytesRemaining -= length;
            }
    
            // TODO set msghdr.msg_flags
            // MSG_EOR
            // End of record was received (if supported by the protocol).
            // MSG_OOB
            // Out-of-band data was received.
            // MSG_TRUNC
            // Normal data was truncated.
            // MSG_CTRUNC
    
            return bytesRead;
          }
          default: abort('unsupported socketcall syscall ' + call);
        }
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall118(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // fsync
        var stream = SYSCALLS.getStreamFromFD();
        if (stream.stream_ops && stream.stream_ops.fsync) {
          return -stream.stream_ops.fsync(stream);
        }
        return 0; // we can't do anything synchronously; the in-memory FS is already synced to
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall12(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // chdir
        var path = SYSCALLS.getStr();
        FS.chdir(path);
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall122(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // uname
        var buf = SYSCALLS.get();
        if (!buf) return -14
        var layout = {"sysname":0,"nodename":65,"domainname":325,"machine":260,"version":195,"release":130,"__size__":390};
        var copyString = function(element, value) {
          var offset = layout[element];
          writeAsciiToMemory(value, buf + offset);
        };
        copyString('sysname', 'Emscripten');
        copyString('nodename', 'emscripten');
        copyString('release', '1.0');
        copyString('version', '#1');
        copyString('machine', 'x86-JS');
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall140(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // llseek
        var stream = SYSCALLS.getStreamFromFD(), offset_high = SYSCALLS.get(), offset_low = SYSCALLS.get(), result = SYSCALLS.get(), whence = SYSCALLS.get();
        var HIGH_OFFSET = 0x100000000; // 2^32
        // use an unsigned operator on low and shift high by 32-bits
        var offset = offset_high * HIGH_OFFSET + (offset_low >>> 0);
    
        var DOUBLE_LIMIT = 0x20000000000000; // 2^53
        // we also check for equality since DOUBLE_LIMIT + 1 == DOUBLE_LIMIT
        if (offset <= -DOUBLE_LIMIT || offset >= DOUBLE_LIMIT) {
          return -75;
        }
    
        FS.llseek(stream, offset, whence);
        (tempI64 = [stream.position>>>0,(tempDouble=stream.position,(+(Math_abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math_min((+(Math_floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((result)>>2)]=tempI64[0],HEAP32[(((result)+(4))>>2)]=tempI64[1]);
        if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; // reset readdir state
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall142(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // newselect
        // readfds are supported,
        // writefds checks socket open status
        // exceptfds not supported
        // timeout is always 0 - fully async
        var nfds = SYSCALLS.get(), readfds = SYSCALLS.get(), writefds = SYSCALLS.get(), exceptfds = SYSCALLS.get(), timeout = SYSCALLS.get();
    
        assert(nfds <= 64, 'nfds must be less than or equal to 64');  // fd sets have 64 bits // TODO: this could be 1024 based on current musl headers
        assert(!exceptfds, 'exceptfds not supported');
    
        var total = 0;
        
        var srcReadLow = (readfds ? HEAP32[((readfds)>>2)] : 0),
            srcReadHigh = (readfds ? HEAP32[(((readfds)+(4))>>2)] : 0);
        var srcWriteLow = (writefds ? HEAP32[((writefds)>>2)] : 0),
            srcWriteHigh = (writefds ? HEAP32[(((writefds)+(4))>>2)] : 0);
        var srcExceptLow = (exceptfds ? HEAP32[((exceptfds)>>2)] : 0),
            srcExceptHigh = (exceptfds ? HEAP32[(((exceptfds)+(4))>>2)] : 0);
    
        var dstReadLow = 0,
            dstReadHigh = 0;
        var dstWriteLow = 0,
            dstWriteHigh = 0;
        var dstExceptLow = 0,
            dstExceptHigh = 0;
    
        var allLow = (readfds ? HEAP32[((readfds)>>2)] : 0) |
                     (writefds ? HEAP32[((writefds)>>2)] : 0) |
                     (exceptfds ? HEAP32[((exceptfds)>>2)] : 0);
        var allHigh = (readfds ? HEAP32[(((readfds)+(4))>>2)] : 0) |
                      (writefds ? HEAP32[(((writefds)+(4))>>2)] : 0) |
                      (exceptfds ? HEAP32[(((exceptfds)+(4))>>2)] : 0);
    
        var check = function(fd, low, high, val) {
          return (fd < 32 ? (low & val) : (high & val));
        };
    
        for (var fd = 0; fd < nfds; fd++) {
          var mask = 1 << (fd % 32);
          if (!(check(fd, allLow, allHigh, mask))) {
            continue;  // index isn't in the set
          }
    
          var stream = FS.getStream(fd);
          if (!stream) throw new FS.ErrnoError(9);
    
          var flags = SYSCALLS.DEFAULT_POLLMASK;
    
          if (stream.stream_ops.poll) {
            flags = stream.stream_ops.poll(stream);
          }
    
          if ((flags & 1) && check(fd, srcReadLow, srcReadHigh, mask)) {
            fd < 32 ? (dstReadLow = dstReadLow | mask) : (dstReadHigh = dstReadHigh | mask);
            total++;
          }
          if ((flags & 4) && check(fd, srcWriteLow, srcWriteHigh, mask)) {
            fd < 32 ? (dstWriteLow = dstWriteLow | mask) : (dstWriteHigh = dstWriteHigh | mask);
            total++;
          }
          if ((flags & 2) && check(fd, srcExceptLow, srcExceptHigh, mask)) {
            fd < 32 ? (dstExceptLow = dstExceptLow | mask) : (dstExceptHigh = dstExceptHigh | mask);
            total++;
          }
        }
    
        if (readfds) {
          HEAP32[((readfds)>>2)]=dstReadLow;
          HEAP32[(((readfds)+(4))>>2)]=dstReadHigh;
        }
        if (writefds) {
          HEAP32[((writefds)>>2)]=dstWriteLow;
          HEAP32[(((writefds)+(4))>>2)]=dstWriteHigh;
        }
        if (exceptfds) {
          HEAP32[((exceptfds)>>2)]=dstExceptLow;
          HEAP32[(((exceptfds)+(4))>>2)]=dstExceptHigh;
        }
        
        return total;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall144(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // msync
        var addr = SYSCALLS.get(), len = SYSCALLS.get(), flags = SYSCALLS.get();
        var info = SYSCALLS.mappings[addr];
        if (!info) return 0;
        SYSCALLS.doMsync(addr, FS.getStream(info.fd), len, info.flags);
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall145(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // readv
        var stream = SYSCALLS.getStreamFromFD(), iov = SYSCALLS.get(), iovcnt = SYSCALLS.get();
        return SYSCALLS.doReadv(stream, iov, iovcnt);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall146(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // writev
        var stream = SYSCALLS.getStreamFromFD(), iov = SYSCALLS.get(), iovcnt = SYSCALLS.get();
        return SYSCALLS.doWritev(stream, iov, iovcnt);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall15(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // chmod
        var path = SYSCALLS.getStr(), mode = SYSCALLS.get();
        FS.chmod(path, mode);
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall168(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // poll
        var fds = SYSCALLS.get(), nfds = SYSCALLS.get(), timeout = SYSCALLS.get();
        var nonzero = 0;
        for (var i = 0; i < nfds; i++) {
          var pollfd = fds + 8 * i;
          var fd = HEAP32[((pollfd)>>2)];
          var events = HEAP16[(((pollfd)+(4))>>1)];
          var mask = 32;
          var stream = FS.getStream(fd);
          if (stream) {
            mask = SYSCALLS.DEFAULT_POLLMASK;
            if (stream.stream_ops.poll) {
              mask = stream.stream_ops.poll(stream);
            }
          }
          mask &= events | 8 | 16;
          if (mask) nonzero++;
          HEAP16[(((pollfd)+(6))>>1)]=mask;
        }
        return nonzero;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall183(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // getcwd
        var buf = SYSCALLS.get(), size = SYSCALLS.get();
        if (size === 0) return -22;
        var cwd = FS.cwd();
        var cwdLengthInBytes = lengthBytesUTF8(cwd);
        if (size < cwdLengthInBytes + 1) return -34;
        stringToUTF8(cwd, buf, size);
        return buf;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    
    
    
    function _memset(ptr, value, num) {
        ptr = ptr|0; value = value|0; num = num|0;
        var end = 0, aligned_end = 0, block_aligned_end = 0, value4 = 0;
        end = (ptr + num)|0;
    
        value = value & 0xff;
        if ((num|0) >= 67 /* 64 bytes for an unrolled loop + 3 bytes for unaligned head*/) {
          while ((ptr&3) != 0) {
            HEAP8[((ptr)>>0)]=value;
            ptr = (ptr+1)|0;
          }
    
          aligned_end = (end & -4)|0;
          value4 = value | (value << 8) | (value << 16) | (value << 24);
    
          block_aligned_end = (aligned_end - 64)|0;
    
          while((ptr|0) <= (block_aligned_end|0)) {
            HEAP32[((ptr)>>2)]=value4;
            HEAP32[(((ptr)+(4))>>2)]=value4;
            HEAP32[(((ptr)+(8))>>2)]=value4;
            HEAP32[(((ptr)+(12))>>2)]=value4;
            HEAP32[(((ptr)+(16))>>2)]=value4;
            HEAP32[(((ptr)+(20))>>2)]=value4;
            HEAP32[(((ptr)+(24))>>2)]=value4;
            HEAP32[(((ptr)+(28))>>2)]=value4;
            HEAP32[(((ptr)+(32))>>2)]=value4;
            HEAP32[(((ptr)+(36))>>2)]=value4;
            HEAP32[(((ptr)+(40))>>2)]=value4;
            HEAP32[(((ptr)+(44))>>2)]=value4;
            HEAP32[(((ptr)+(48))>>2)]=value4;
            HEAP32[(((ptr)+(52))>>2)]=value4;
            HEAP32[(((ptr)+(56))>>2)]=value4;
            HEAP32[(((ptr)+(60))>>2)]=value4;
            ptr = (ptr + 64)|0;
          }
    
          while ((ptr|0) < (aligned_end|0) ) {
            HEAP32[((ptr)>>2)]=value4;
            ptr = (ptr+4)|0;
          }
        }
        // The remaining bytes.
        while ((ptr|0) < (end|0)) {
          HEAP8[((ptr)>>0)]=value;
          ptr = (ptr+1)|0;
        }
        return (end-num)|0;
      }function __emscripten_syscall_mmap2(addr, len, prot, flags, fd, off) {
        off <<= 12; // undo pgoffset
        var ptr;
        var allocated = false;
    
        // addr argument must be page aligned if MAP_FIXED flag is set.
        if ((flags & 16) !== 0 && (addr % PAGE_SIZE) !== 0) {
          return -22;
        }
    
        // MAP_ANONYMOUS (aka MAP_ANON) isn't actually defined by POSIX spec,
        // but it is widely used way to allocate memory pages on Linux, BSD and Mac.
        // In this case fd argument is ignored.
        if ((flags & 32) !== 0) {
          ptr = _memalign(PAGE_SIZE, len);
          if (!ptr) return -12;
          _memset(ptr, 0, len);
          allocated = true;
        } else {
          var info = FS.getStream(fd);
          if (!info) return -9;
          var res = FS.mmap(info, HEAPU8, addr, len, off, prot, flags);
          ptr = res.ptr;
          allocated = res.allocated;
        }
        SYSCALLS.mappings[ptr] = { malloc: ptr, len: len, allocated: allocated, fd: fd, flags: flags };
        return ptr;
      }function ___syscall192(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // mmap2
        var addr = SYSCALLS.get(), len = SYSCALLS.get(), prot = SYSCALLS.get(), flags = SYSCALLS.get(), fd = SYSCALLS.get(), off = SYSCALLS.get()
        return __emscripten_syscall_mmap2(addr, len, prot, flags, fd, off);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall194(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // ftruncate64
        var fd = SYSCALLS.get(), zero = SYSCALLS.getZero(), length = SYSCALLS.get64();
        FS.ftruncate(fd, length);
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall195(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // SYS_stat64
        var path = SYSCALLS.getStr(), buf = SYSCALLS.get();
        return SYSCALLS.doStat(FS.stat, path, buf);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall196(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // SYS_lstat64
        var path = SYSCALLS.getStr(), buf = SYSCALLS.get();
        return SYSCALLS.doStat(FS.lstat, path, buf);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall197(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // SYS_fstat64
        var stream = SYSCALLS.getStreamFromFD(), buf = SYSCALLS.get();
        return SYSCALLS.doStat(FS.stat, stream.path, buf);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    
    function ___syscall202(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // getgid32
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }function ___syscall199(a0,a1
    /*``*/) {
    return ___syscall202(a0,a1);
    }
  
    
    var PROCINFO={ppid:1,pid:42,sid:42,pgid:42};function ___syscall20(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // getpid
        return PROCINFO.pid;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall201(a0,a1
    /*``*/) {
    return ___syscall202(a0,a1);
    }
  
  
    
    function ___syscall211(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // getresgid32
        var ruid = SYSCALLS.get(), euid = SYSCALLS.get(), suid = SYSCALLS.get();
        HEAP32[((ruid)>>2)]=0;
        HEAP32[((euid)>>2)]=0;
        HEAP32[((suid)>>2)]=0;
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }function ___syscall209(a0,a1
    /*``*/) {
    return ___syscall211(a0,a1);
    }
  
    function ___syscall220(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // SYS_getdents64
        var stream = SYSCALLS.getStreamFromFD(), dirp = SYSCALLS.get(), count = SYSCALLS.get();
        if (!stream.getdents) {
          stream.getdents = FS.readdir(stream.path);
        }
    
        var struct_size = 280;
        var pos = 0;
        var off = FS.llseek(stream, 0, 1);
    
        var idx = Math.floor(off / struct_size);
    
        while (idx < stream.getdents.length && pos + struct_size <= count) {
          var id;
          var type;
          var name = stream.getdents[idx];
          if (name[0] === '.') {
            id = 1;
            type = 4; // DT_DIR
          } else {
            var child = FS.lookupNode(stream.node, name);
            id = child.id;
            type = FS.isChrdev(child.mode) ? 2 :  // DT_CHR, character device.
                   FS.isDir(child.mode) ? 4 :     // DT_DIR, directory.
                   FS.isLink(child.mode) ? 10 :   // DT_LNK, symbolic link.
                   8;                             // DT_REG, regular file.
          }
          (tempI64 = [id>>>0,(tempDouble=id,(+(Math_abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math_min((+(Math_floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[((dirp + pos)>>2)]=tempI64[0],HEAP32[(((dirp + pos)+(4))>>2)]=tempI64[1]);
          (tempI64 = [(idx + 1) * struct_size>>>0,(tempDouble=(idx + 1) * struct_size,(+(Math_abs(tempDouble))) >= 1.0 ? (tempDouble > 0.0 ? ((Math_min((+(Math_floor((tempDouble)/4294967296.0))), 4294967295.0))|0)>>>0 : (~~((+(Math_ceil((tempDouble - +(((~~(tempDouble)))>>>0))/4294967296.0)))))>>>0) : 0)],HEAP32[(((dirp + pos)+(8))>>2)]=tempI64[0],HEAP32[(((dirp + pos)+(12))>>2)]=tempI64[1]);
          HEAP16[(((dirp + pos)+(16))>>1)]=280;
          HEAP8[(((dirp + pos)+(18))>>0)]=type;
          stringToUTF8(name, dirp + pos + 19, 256);
          pos += struct_size;
          idx += 1;
        }
        FS.llseek(stream, idx * struct_size, 0);
        return pos;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall221(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // fcntl64
        var stream = SYSCALLS.getStreamFromFD(), cmd = SYSCALLS.get();
        switch (cmd) {
          case 0: {
            var arg = SYSCALLS.get();
            if (arg < 0) {
              return -22;
            }
            var newStream;
            newStream = FS.open(stream.path, stream.flags, 0, arg);
            return newStream.fd;
          }
          case 1:
          case 2:
            return 0;  // FD_CLOEXEC makes no sense for a single process.
          case 3:
            return stream.flags;
          case 4: {
            var arg = SYSCALLS.get();
            stream.flags |= arg;
            return 0;
          }
          case 12:
          /* case 12: Currently in musl F_GETLK64 has same value as F_GETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ {
            
            var arg = SYSCALLS.get();
            var offset = 0;
            // We're always unlocked.
            HEAP16[(((arg)+(offset))>>1)]=2;
            return 0;
          }
          case 13:
          case 14:
          /* case 13: Currently in musl F_SETLK64 has same value as F_SETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */
          /* case 14: Currently in musl F_SETLKW64 has same value as F_SETLKW, so omitted to avoid duplicate case blocks. If that changes, uncomment this */
            
            
            return 0; // Pretend that the locking is successful.
          case 16:
          case 8:
            return -22; // These are for sockets. We don't have them fully implemented yet.
          case 9:
            // 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.
            ___setErrNo(22);
            return -1;
          default: {
            return -22;
          }
        }
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall268(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // statfs64
        var path = SYSCALLS.getStr(), size = SYSCALLS.get(), buf = SYSCALLS.get();
        assert(size === 64);
        // NOTE: None of the constants here are true. We're just returning safe and
        //       sane values.
        HEAP32[(((buf)+(4))>>2)]=4096;
        HEAP32[(((buf)+(40))>>2)]=4096;
        HEAP32[(((buf)+(8))>>2)]=1000000;
        HEAP32[(((buf)+(12))>>2)]=500000;
        HEAP32[(((buf)+(16))>>2)]=500000;
        HEAP32[(((buf)+(20))>>2)]=FS.nextInode;
        HEAP32[(((buf)+(24))>>2)]=1000000;
        HEAP32[(((buf)+(28))>>2)]=42;
        HEAP32[(((buf)+(44))>>2)]=2;  // ST_NOSUID
        HEAP32[(((buf)+(36))>>2)]=255;
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall272(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // fadvise64_64
        return 0; // your advice is important to us (but we can't use it)
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall3(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // read
        var stream = SYSCALLS.getStreamFromFD(), buf = SYSCALLS.get(), count = SYSCALLS.get();
        return FS.read(stream, HEAP8,buf, count);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall320(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // utimensat
        var dirfd = SYSCALLS.get(), path = SYSCALLS.getStr(), times = SYSCALLS.get(), flags = SYSCALLS.get();
        assert(flags === 0);
        path = SYSCALLS.calculateAt(dirfd, path);
        var seconds = HEAP32[((times)>>2)];
        var nanoseconds = HEAP32[(((times)+(4))>>2)];
        var atime = (seconds*1000) + (nanoseconds/(1000*1000));
        times += 8;
        seconds = HEAP32[((times)>>2)];
        nanoseconds = HEAP32[(((times)+(4))>>2)];
        var mtime = (seconds*1000) + (nanoseconds/(1000*1000));
        FS.utime(path, atime, mtime);
        return 0;  
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall33(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // access
        var path = SYSCALLS.getStr(), amode = SYSCALLS.get();
        return SYSCALLS.doAccess(path, amode);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall38(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // rename
        var old_path = SYSCALLS.getStr(), new_path = SYSCALLS.getStr();
        FS.rename(old_path, new_path);
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall39(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // mkdir
        var path = SYSCALLS.getStr(), mode = SYSCALLS.get();
        return SYSCALLS.doMkdir(path, mode);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall4(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // write
        var stream = SYSCALLS.getStreamFromFD(), buf = SYSCALLS.get(), count = SYSCALLS.get();
        return FS.write(stream, HEAP8,buf, count);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall40(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // rmdir
        var path = SYSCALLS.getStr();
        FS.rmdir(path);
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall41(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // dup
        var old = SYSCALLS.getStreamFromFD();
        return FS.open(old.path, old.flags, 0).fd;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    
    var PIPEFS={BUCKET_BUFFER_SIZE:8192,mount:function (mount) {
          // Do not pollute the real root directory or its child nodes with pipes
          // Looks like it is OK to create another pseudo-root node not linked to the FS.root hierarchy this way
          return FS.createNode(null, '/', 16384 | 511 /* 0777 */, 0);
        },createPipe:function () {
          var pipe = {
            buckets: []
          };
    
          pipe.buckets.push({
            buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
            offset: 0,
            roffset: 0
          });
    
          var rName = PIPEFS.nextname();
          var wName = PIPEFS.nextname();
          var rNode = FS.createNode(PIPEFS.root, rName, 4096, 0);
          var wNode = FS.createNode(PIPEFS.root, wName, 4096, 0);
    
          rNode.pipe = pipe;
          wNode.pipe = pipe;
    
          var readableStream = FS.createStream({
            path: rName,
            node: rNode,
            flags: FS.modeStringToFlags('r'),
            seekable: false,
            stream_ops: PIPEFS.stream_ops
          });
          rNode.stream = readableStream;
    
          var writableStream = FS.createStream({
            path: wName,
            node: wNode,
            flags: FS.modeStringToFlags('w'),
            seekable: false,
            stream_ops: PIPEFS.stream_ops
          });
          wNode.stream = writableStream;
    
          return {
            readable_fd: readableStream.fd,
            writable_fd: writableStream.fd
          };
        },stream_ops:{poll:function (stream) {
            var pipe = stream.node.pipe;
    
            if ((stream.flags & 2097155) === 1) {
              return (256 | 4);
            } else {
              if (pipe.buckets.length > 0) {
                for (var i = 0; i < pipe.buckets.length; i++) {
                  var bucket = pipe.buckets[i];
                  if (bucket.offset - bucket.roffset > 0) {
                    return (64 | 1);
                  }
                }
              }
            }
    
            return 0;
          },ioctl:function (stream, request, varargs) {
            return ERRNO_CODES.EINVAL;
          },fsync:function (stream) {
            return ERRNO_CODES.EINVAL;
          },read:function (stream, buffer, offset, length, position /* ignored */) {
            var pipe = stream.node.pipe;
            var currentLength = 0;
    
            for (var i = 0; i < pipe.buckets.length; i++) {
              var bucket = pipe.buckets[i];
              currentLength += bucket.offset - bucket.roffset;
            }
    
            assert(buffer instanceof ArrayBuffer || ArrayBuffer.isView(buffer));
            var data = buffer.subarray(offset, offset + length);
    
            if (length <= 0) {
              return 0;
            }
            if (currentLength == 0) {
              // Behave as if the read end is always non-blocking
              throw new FS.ErrnoError(ERRNO_CODES.EAGAIN);
            }
            var toRead = Math.min(currentLength, length);
    
            var totalRead = toRead;
            var toRemove = 0;
    
            for (var i = 0; i < pipe.buckets.length; i++) {
              var currBucket = pipe.buckets[i];
              var bucketSize = currBucket.offset - currBucket.roffset;
    
              if (toRead <= bucketSize) {
                var tmpSlice = currBucket.buffer.subarray(currBucket.roffset, currBucket.offset);
                if (toRead < bucketSize) {
                  tmpSlice = tmpSlice.subarray(0, toRead);
                  currBucket.roffset += toRead;
                } else {
                  toRemove++;
                }
                data.set(tmpSlice);
                break;
              } else {
                var tmpSlice = currBucket.buffer.subarray(currBucket.roffset, currBucket.offset);
                data.set(tmpSlice);
                data = data.subarray(tmpSlice.byteLength);
                toRead -= tmpSlice.byteLength;
                toRemove++;
              }
            }
    
            if (toRemove && toRemove == pipe.buckets.length) {
              // Do not generate excessive garbage in use cases such as
              // write several bytes, read everything, write several bytes, read everything...
              toRemove--;
              pipe.buckets[toRemove].offset = 0;
              pipe.buckets[toRemove].roffset = 0;
            }
    
            pipe.buckets.splice(0, toRemove);
    
            return totalRead;
          },write:function (stream, buffer, offset, length, position /* ignored */) {
            var pipe = stream.node.pipe;
    
            assert(buffer instanceof ArrayBuffer || ArrayBuffer.isView(buffer));
            var data = buffer.subarray(offset, offset + length);
    
            var dataLen = data.byteLength;
            if (dataLen <= 0) {
              return 0;
            }
    
            var currBucket = null;
    
            if (pipe.buckets.length == 0) {
              currBucket = {
                buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
                offset: 0,
                roffset: 0
              };
              pipe.buckets.push(currBucket);
            } else {
              currBucket = pipe.buckets[pipe.buckets.length - 1];
            }
    
            assert(currBucket.offset <= PIPEFS.BUCKET_BUFFER_SIZE);
    
            var freeBytesInCurrBuffer = PIPEFS.BUCKET_BUFFER_SIZE - currBucket.offset;
            if (freeBytesInCurrBuffer >= dataLen) {
              currBucket.buffer.set(data, currBucket.offset);
              currBucket.offset += dataLen;
              return dataLen;
            } else if (freeBytesInCurrBuffer > 0) {
              currBucket.buffer.set(data.subarray(0, freeBytesInCurrBuffer), currBucket.offset);
              currBucket.offset += freeBytesInCurrBuffer;
              data = data.subarray(freeBytesInCurrBuffer, data.byteLength);
            }
    
            var numBuckets = (data.byteLength / PIPEFS.BUCKET_BUFFER_SIZE) | 0;
            var remElements = data.byteLength % PIPEFS.BUCKET_BUFFER_SIZE;
    
            for (var i = 0; i < numBuckets; i++) {
              var newBucket = {
                buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
                offset: PIPEFS.BUCKET_BUFFER_SIZE,
                roffset: 0
              };
              pipe.buckets.push(newBucket);
              newBucket.buffer.set(data.subarray(0, PIPEFS.BUCKET_BUFFER_SIZE));
              data = data.subarray(PIPEFS.BUCKET_BUFFER_SIZE, data.byteLength);
            }
    
            if (remElements > 0) {
              var newBucket = {
                buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE),
                offset: data.byteLength,
                roffset: 0
              };
              pipe.buckets.push(newBucket);
              newBucket.buffer.set(data);
            }
    
            return dataLen;
          },close:function (stream) {
            var pipe = stream.node.pipe;
            pipe.buckets = null;
          }},nextname:function () {
          if (!PIPEFS.nextname.current) {
            PIPEFS.nextname.current = 0;
          }
          return 'pipe[' + (PIPEFS.nextname.current++) + ']';
        }};function ___syscall42(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // pipe
        var fdPtr = SYSCALLS.get();
    
        if (fdPtr == 0) {
          throw new FS.ErrnoError(14);
        }
    
        var res = PIPEFS.createPipe();
    
        HEAP32[((fdPtr)>>2)]=res.readable_fd;
        HEAP32[(((fdPtr)+(4))>>2)]=res.writable_fd;
    
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall5(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // open
        var pathname = SYSCALLS.getStr(), flags = SYSCALLS.get(), mode = SYSCALLS.get() // optional TODO
        var stream = FS.open(pathname, flags, mode);
        return stream.fd;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall54(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // ioctl
        var stream = SYSCALLS.getStreamFromFD(), op = SYSCALLS.get();
        switch (op) {
          case 21509:
          case 21505: {
            if (!stream.tty) return -25;
            return 0;
          }
          case 21510:
          case 21511:
          case 21512:
          case 21506:
          case 21507:
          case 21508: {
            if (!stream.tty) return -25;
            return 0; // no-op, not actually adjusting terminal settings
          }
          case 21519: {
            if (!stream.tty) return -25;
            var argp = SYSCALLS.get();
            HEAP32[((argp)>>2)]=0;
            return 0;
          }
          case 21520: {
            if (!stream.tty) return -25;
            return -22; // not supported
          }
          case 21531: {
            var argp = SYSCALLS.get();
            return FS.ioctl(stream, op, argp);
          }
          case 21523: {
            // TODO: in theory we should write to the winsize struct that gets
            // passed in, but for now musl doesn't read anything on it
            if (!stream.tty) return -25;
            return 0;
          }
          case 21524: {
            // TODO: technically, this ioctl call should change the window size.
            // but, since emscripten doesn't have any concept of a terminal window
            // yet, we'll just silently throw it away as we do TIOCGWINSZ
            if (!stream.tty) return -25;
            return 0;
          }
          default: abort('bad ioctl syscall ' + op);
        }
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall6(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // close
        var stream = SYSCALLS.getStreamFromFD();
        FS.close(stream);
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall63(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // dup2
        var old = SYSCALLS.getStreamFromFD(), suggestFD = SYSCALLS.get();
        if (old.fd === suggestFD) return suggestFD;
        return SYSCALLS.doDup(old.path, old.flags, suggestFD);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall77(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // getrusage
        var who = SYSCALLS.get(), usage = SYSCALLS.get();
        _memset(usage, 0, 136);
        HEAP32[((usage)>>2)]=1; // fake some values
        HEAP32[(((usage)+(4))>>2)]=2;
        HEAP32[(((usage)+(8))>>2)]=3;
        HEAP32[(((usage)+(12))>>2)]=4;
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall85(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // readlink
        var path = SYSCALLS.getStr(), buf = SYSCALLS.get(), bufsize = SYSCALLS.get();
        return SYSCALLS.doReadlink(path, buf, bufsize);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall9(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // link
        var oldpath = SYSCALLS.get(), newpath = SYSCALLS.get();
        return -31; // no hardlinks for us
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    
    function __emscripten_syscall_munmap(addr, len) {
        if (addr == -1 || len == 0) {
          return -22;
        }
        // TODO: support unmmap'ing parts of allocations
        var info = SYSCALLS.mappings[addr];
        if (!info) return 0;
        if (len === info.len) {
          var stream = FS.getStream(info.fd);
          SYSCALLS.doMsync(addr, stream, len, info.flags)
          FS.munmap(stream);
          SYSCALLS.mappings[addr] = null;
          if (info.allocated) {
            _free(info.malloc);
          }
        }
        return 0;
      }function ___syscall91(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // munmap
        var addr = SYSCALLS.get(), len = SYSCALLS.get();
        return __emscripten_syscall_munmap(addr, len);
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall94(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // fchmod
        var fd = SYSCALLS.get(), mode = SYSCALLS.get();
        FS.fchmod(fd, mode);
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall96(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // getpriority
        return 0;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___syscall97(which, varargs) {SYSCALLS.varargs = varargs;
    try {
     // setpriority
        return -1;
      } catch (e) {
      if (typeof FS === 'undefined' || !(e instanceof FS.ErrnoError)) abort(e);
      return -e.errno;
    }
    }
  
    function ___unlock() {}
  
    
    function _exit(status) {
        // void _exit(int status);
        // http://pubs.opengroup.org/onlinepubs/000095399/functions/exit.html
        exit(status);
      }function __exit(a0
    /*``*/) {
    return _exit(a0);
    }
  
    function _abort() {
        Module['abort']();
      }
  
    function _atexit(func, arg) {
        warnOnce('atexit() called, but EXIT_RUNTIME is not set, so atexits() will not be called. set EXIT_RUNTIME to 1 (see the FAQ)');
        __ATEXIT__.unshift({ func: func, arg: arg });
      }
  
    
    function _emscripten_get_now_res() { // return resolution of get_now, in nanoseconds
        if (ENVIRONMENT_IS_NODE) {
          return 1; // nanoseconds
        } else
        if (typeof dateNow !== 'undefined') {
          return 1000; // microseconds (1/1000 of a millisecond)
        } else
        if (typeof performance === 'object' && performance && typeof performance['now'] === 'function') {
          return 1000; // microseconds (1/1000 of a millisecond)
        } else {
          return 1000*1000; // milliseconds
        }
      }function _clock_getres(clk_id, res) {
        // int clock_getres(clockid_t clk_id, struct timespec *res);
        var nsec;
        if (clk_id === 0) {
          nsec = 1000 * 1000; // educated guess that it's milliseconds
        } else if (clk_id === 1 && _emscripten_get_now_is_monotonic()) {
          nsec = _emscripten_get_now_res();
        } else {
          ___setErrNo(22);
          return -1;
        }
        HEAP32[((res)>>2)]=(nsec/1000000000)|0;
        HEAP32[(((res)+(4))>>2)]=nsec // resolution is nanoseconds
        return 0;
      }
  
  
    function _emscripten_get_heap_size() {
        return HEAP8.length;
      }
  
    function _emscripten_memcpy_big(dest, src, num) {
        HEAPU8.set(HEAPU8.subarray(src, src+num), dest);
      }
  
    
    function _execl(/* ... */) {
        // int execl(const char *path, const char *arg0, ... /*, (char *)0 */);
        // http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html
        // We don't support executing external code.
        ___setErrNo(8);
        return -1;
      }function _execve() {
    return _execl.apply(null, arguments)
    }
  
  
    var _fabs=Math_abs;
  
    var _fabsf=Math_abs;
  
    var _floor=Math_floor;
  
    function _fork() {
        // pid_t fork(void);
        // http://pubs.opengroup.org/onlinepubs/000095399/functions/fork.html
        // We don't support multiple processes.
        ___setErrNo(11);
        return -1;
      }
  
    function _getTempRet0() {
        return (getTempRet0() | 0);
      }
  
    function _getaddrinfo(node, service, hint, out) {
        // Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL
        // hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we
        // really should provide a linked list of suitable addrinfo values.
        var addrs = [];
        var canon = null;
        var addr = 0;
        var port = 0;
        var flags = 0;
        var family = 0;
        var type = 0;
        var proto = 0;
        var ai, last;
    
        function allocaddrinfo(family, type, proto, canon, addr, port) {
          var sa, salen, ai;
          var res;
    
          salen = family === 10 ?
            28 :
            16;
          addr = family === 10 ?
            __inet_ntop6_raw(addr) :
            __inet_ntop4_raw(addr);
          sa = _malloc(salen);
          res = __write_sockaddr(sa, family, addr, port);
          assert(!res.errno);
    
          ai = _malloc(32);
          HEAP32[(((ai)+(4))>>2)]=family;
          HEAP32[(((ai)+(8))>>2)]=type;
          HEAP32[(((ai)+(12))>>2)]=proto;
          HEAP32[(((ai)+(24))>>2)]=canon;
          HEAP32[(((ai)+(20))>>2)]=sa;
          if (family === 10) {
            HEAP32[(((ai)+(16))>>2)]=28;
          } else {
            HEAP32[(((ai)+(16))>>2)]=16;
          }
          HEAP32[(((ai)+(28))>>2)]=0;
    
          return ai;
        }
    
        if (hint) {
          flags = HEAP32[((hint)>>2)];
          family = HEAP32[(((hint)+(4))>>2)];
          type = HEAP32[(((hint)+(8))>>2)];
          proto = HEAP32[(((hint)+(12))>>2)];
        }
        if (type && !proto) {
          proto = type === 2 ? 17 : 6;
        }
        if (!type && proto) {
          type = proto === 17 ? 2 : 1;
        }
    
        // If type or proto are set to zero in hints we should really be returning multiple addrinfo values, but for
        // now default to a TCP STREAM socket so we can at least return a sensible addrinfo given NULL hints.
        if (proto === 0) {
          proto = 6;
        }
        if (type === 0) {
          type = 1;
        }
    
        if (!node && !service) {
          return -2;
        }
        if (flags & ~(1|2|4|
            1024|8|16|32)) {
          return -1;
        }
        if (hint !== 0 && (HEAP32[((hint)>>2)] & 2) && !node) {
          return -1;
        }
        if (flags & 32) {
          // TODO
          return -2;
        }
        if (type !== 0 && type !== 1 && type !== 2) {
          return -7;
        }
        if (family !== 0 && family !== 2 && family !== 10) {
          return -6;
        }
    
        if (service) {
          service = UTF8ToString(service);
          port = parseInt(service, 10);
    
          if (isNaN(port)) {
            if (flags & 1024) {
              return -2;
            }
            // TODO support resolving well-known service names from:
            // http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt
            return -8;
          }
        }
    
        if (!node) {
          if (family === 0) {
            family = 2;
          }
          if ((flags & 1) === 0) {
            if (family === 2) {
              addr = _htonl(2130706433);
            } else {
              addr = [0, 0, 0, 1];
            }
          }
          ai = allocaddrinfo(family, type, proto, null, addr, port);
          HEAP32[((out)>>2)]=ai;
          return 0;
        }
    
        //
        // try as a numeric address
        //
        node = UTF8ToString(node);
        addr = __inet_pton4_raw(node);
        if (addr !== null) {
          // incoming node is a valid ipv4 address
          if (family === 0 || family === 2) {
            family = 2;
          }
          else if (family === 10 && (flags & 8)) {
            addr = [0, 0, _htonl(0xffff), addr];
            family = 10;
          } else {
            return -2;
          }
        } else {
          addr = __inet_pton6_raw(node);
          if (addr !== null) {
            // incoming node is a valid ipv6 address
            if (family === 0 || family === 10) {
              family = 10;
            } else {
              return -2;
            }
          }
        }
        if (addr != null) {
          ai = allocaddrinfo(family, type, proto, node, addr, port);
          HEAP32[((out)>>2)]=ai;
          return 0;
        }
        if (flags & 4) {
          return -2;
        }
    
        //
        // try as a hostname
        //
        // resolve the hostname to a temporary fake address
        node = DNS.lookup_name(node);
        addr = __inet_pton4_raw(node);
        if (family === 0) {
          family = 2;
        } else if (family === 10) {
          addr = [0, 0, _htonl(0xffff), addr];
        }
        ai = allocaddrinfo(family, type, proto, null, addr, port);
        HEAP32[((out)>>2)]=ai;
        return 0;
      }
  
    function _getenv(name) {
        // char *getenv(const char *name);
        // http://pubs.opengroup.org/onlinepubs/009695399/functions/getenv.html
        if (name === 0) return 0;
        name = UTF8ToString(name);
        if (!ENV.hasOwnProperty(name)) return 0;
    
        if (_getenv.ret) _free(_getenv.ret);
        _getenv.ret = allocateUTF8(ENV[name]);
        return _getenv.ret;
      }
  
    function _getnameinfo(sa, salen, node, nodelen, serv, servlen, flags) {
        var info = __read_sockaddr(sa, salen);
        if (info.errno) {
          return -6;
        }
        var port = info.port;
        var addr = info.addr;
    
        var overflowed = false;
    
        if (node && nodelen) {
          var lookup;
          if ((flags & 1) || !(lookup = DNS.lookup_addr(addr))) {
            if (flags & 8) {
              return -2;
            }
          } else {
            addr = lookup;
          }
          var numBytesWrittenExclNull = stringToUTF8(addr, node, nodelen);
    
          if (numBytesWrittenExclNull+1 >= nodelen) {
            overflowed = true;
          }
        }
    
        if (serv && servlen) {
          port = '' + port;
          var numBytesWrittenExclNull = stringToUTF8(port, serv, servlen);
    
          if (numBytesWrittenExclNull+1 >= servlen) {
            overflowed = true;
          }
        }
    
        if (overflowed) {
          // Note: even when we overflow, getnameinfo() is specced to write out the truncated results.
          return -12;
        }
    
        return 0;
      }
  
    
    
    var Protocols={list:[],map:{}};function _setprotoent(stayopen) {
        // void setprotoent(int stayopen);
    
        // Allocate and populate a protoent structure given a name, protocol number and array of aliases
        function allocprotoent(name, proto, aliases) {
          // write name into buffer
          var nameBuf = _malloc(name.length + 1);
          writeAsciiToMemory(name, nameBuf);
    
          // write aliases into buffer
          var j = 0;
          var length = aliases.length;
          var aliasListBuf = _malloc((length + 1) * 4); // Use length + 1 so we have space for the terminating NULL ptr.
    
          for (var i = 0; i < length; i++, j += 4) {
            var alias = aliases[i];
            var aliasBuf = _malloc(alias.length + 1);
            writeAsciiToMemory(alias, aliasBuf);
            HEAP32[(((aliasListBuf)+(j))>>2)]=aliasBuf;
          }
          HEAP32[(((aliasListBuf)+(j))>>2)]=0; // Terminating NULL pointer.
    
          // generate protoent
          var pe = _malloc(12);
          HEAP32[((pe)>>2)]=nameBuf;
          HEAP32[(((pe)+(4))>>2)]=aliasListBuf;
          HEAP32[(((pe)+(8))>>2)]=proto;
          return pe;
        };
    
        // Populate the protocol 'database'. The entries are limited to tcp and udp, though it is fairly trivial
        // to add extra entries from /etc/protocols if desired - though not sure if that'd actually be useful.
        var list = Protocols.list;
        var map  = Protocols.map;
        if (list.length === 0) {
            var entry = allocprotoent('tcp', 6, ['TCP']);
            list.push(entry);
            map['tcp'] = map['6'] = entry;
            entry = allocprotoent('udp', 17, ['UDP']);
            list.push(entry);
            map['udp'] = map['17'] = entry;
        }
    
        _setprotoent.index = 0;
      }function _getprotobyname(name) {
        // struct protoent *getprotobyname(const char *);
        name = UTF8ToString(name);
        _setprotoent(true);
        var result = Protocols.map[name];
        return result;
      }
  
    function _getpwuid(uid) {
        return 0; // NULL
      }
  
    function _gettimeofday(ptr) {
        var now = Date.now();
        HEAP32[((ptr)>>2)]=(now/1000)|0; // seconds
        HEAP32[(((ptr)+(4))>>2)]=((now % 1000)*1000)|0; // microseconds
        return 0;
      }
  
    
    var ___tm_timezone=(stringToUTF8("GMT", 736512, 4), 736512);function _gmtime_r(time, tmPtr) {
        var date = new Date(HEAP32[((time)>>2)]*1000);
        HEAP32[((tmPtr)>>2)]=date.getUTCSeconds();
        HEAP32[(((tmPtr)+(4))>>2)]=date.getUTCMinutes();
        HEAP32[(((tmPtr)+(8))>>2)]=date.getUTCHours();
        HEAP32[(((tmPtr)+(12))>>2)]=date.getUTCDate();
        HEAP32[(((tmPtr)+(16))>>2)]=date.getUTCMonth();
        HEAP32[(((tmPtr)+(20))>>2)]=date.getUTCFullYear()-1900;
        HEAP32[(((tmPtr)+(24))>>2)]=date.getUTCDay();
        HEAP32[(((tmPtr)+(36))>>2)]=0;
        HEAP32[(((tmPtr)+(32))>>2)]=0;
        var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0);
        var yday = ((date.getTime() - start) / (1000 * 60 * 60 * 24))|0;
        HEAP32[(((tmPtr)+(28))>>2)]=yday;
        HEAP32[(((tmPtr)+(40))>>2)]=___tm_timezone;
    
        return tmPtr;
      }
  
    function _kill(pid, sig) {
        // http://pubs.opengroup.org/onlinepubs/000095399/functions/kill.html
        // Makes no sense in a single-process environment.
    	  // Should kill itself somtimes depending on `pid`
        err('Calling stub instead of kill()');
        ___setErrNo(ERRNO_CODES.EPERM);
        return -1;
      }
  
    function _llvm_eh_typeid_for(type) {
        return type;
      }
  
    
    function _tzset() {
        // TODO: Use (malleable) environment variables instead of system settings.
        if (_tzset.called) return;
        _tzset.called = true;
    
        // timezone is specified as seconds west of UTC ("The external variable
        // `timezone` shall be set to the difference, in seconds, between
        // Coordinated Universal Time (UTC) and local standard time."), the same
        // as returned by getTimezoneOffset().
        // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html
        HEAP32[((__get_timezone())>>2)]=(new Date()).getTimezoneOffset() * 60;
    
        var winter = new Date(2000, 0, 1);
        var summer = new Date(2000, 6, 1);
        HEAP32[((__get_daylight())>>2)]=Number(winter.getTimezoneOffset() != summer.getTimezoneOffset());
    
        function extractZone(date) {
          var match = date.toTimeString().match(/\(([A-Za-z ]+)\)$/);
          return match ? match[1] : "GMT";
        };
        var winterName = extractZone(winter);
        var summerName = extractZone(summer);
        var winterNamePtr = allocate(intArrayFromString(winterName), 'i8', ALLOC_NORMAL);
        var summerNamePtr = allocate(intArrayFromString(summerName), 'i8', ALLOC_NORMAL);
        if (summer.getTimezoneOffset() < winter.getTimezoneOffset()) {
          // Northern hemisphere
          HEAP32[((__get_tzname())>>2)]=winterNamePtr;
          HEAP32[(((__get_tzname())+(4))>>2)]=summerNamePtr;
        } else {
          HEAP32[((__get_tzname())>>2)]=summerNamePtr;
          HEAP32[(((__get_tzname())+(4))>>2)]=winterNamePtr;
        }
      }function _localtime_r(time, tmPtr) {
        _tzset();
        var date = new Date(HEAP32[((time)>>2)]*1000);
        HEAP32[((tmPtr)>>2)]=date.getSeconds();
        HEAP32[(((tmPtr)+(4))>>2)]=date.getMinutes();
        HEAP32[(((tmPtr)+(8))>>2)]=date.getHours();
        HEAP32[(((tmPtr)+(12))>>2)]=date.getDate();
        HEAP32[(((tmPtr)+(16))>>2)]=date.getMonth();
        HEAP32[(((tmPtr)+(20))>>2)]=date.getFullYear()-1900;
        HEAP32[(((tmPtr)+(24))>>2)]=date.getDay();
    
        var start = new Date(date.getFullYear(), 0, 1);
        var yday = ((date.getTime() - start.getTime()) / (1000 * 60 * 60 * 24))|0;
        HEAP32[(((tmPtr)+(28))>>2)]=yday;
        HEAP32[(((tmPtr)+(36))>>2)]=-(date.getTimezoneOffset() * 60);
    
        // Attention: DST is in December in South, and some regions don't have DST at all.
        var summerOffset = new Date(2000, 6, 1).getTimezoneOffset();
        var winterOffset = start.getTimezoneOffset();
        var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset, summerOffset))|0;
        HEAP32[(((tmPtr)+(32))>>2)]=dst;
    
        var zonePtr = HEAP32[(((__get_tzname())+(dst ? 4 : 0))>>2)];
        HEAP32[(((tmPtr)+(40))>>2)]=zonePtr;
    
        return tmPtr;
      }
  
    function _memcpy(dest, src, num) {
        dest = dest|0; src = src|0; num = num|0;
        var ret = 0;
        var aligned_dest_end = 0;
        var block_aligned_dest_end = 0;
        var dest_end = 0;
        // Test against a benchmarked cutoff limit for when HEAPU8.set() becomes faster to use.
        if ((num|0) >= 8192) {
          _emscripten_memcpy_big(dest|0, src|0, num|0)|0;
          return dest|0;
        }
    
        ret = dest|0;
        dest_end = (dest + num)|0;
        if ((dest&3) == (src&3)) {
          // The initial unaligned < 4-byte front.
          while (dest & 3) {
            if ((num|0) == 0) return ret|0;
            HEAP8[((dest)>>0)]=((HEAP8[((src)>>0)])|0);
            dest = (dest+1)|0;
            src = (src+1)|0;
            num = (num-1)|0;
          }
          aligned_dest_end = (dest_end & -4)|0;
          block_aligned_dest_end = (aligned_dest_end - 64)|0;
          while ((dest|0) <= (block_aligned_dest_end|0) ) {
            HEAP32[((dest)>>2)]=((HEAP32[((src)>>2)])|0);
            HEAP32[(((dest)+(4))>>2)]=((HEAP32[(((src)+(4))>>2)])|0);
            HEAP32[(((dest)+(8))>>2)]=((HEAP32[(((src)+(8))>>2)])|0);
            HEAP32[(((dest)+(12))>>2)]=((HEAP32[(((src)+(12))>>2)])|0);
            HEAP32[(((dest)+(16))>>2)]=((HEAP32[(((src)+(16))>>2)])|0);
            HEAP32[(((dest)+(20))>>2)]=((HEAP32[(((src)+(20))>>2)])|0);
            HEAP32[(((dest)+(24))>>2)]=((HEAP32[(((src)+(24))>>2)])|0);
            HEAP32[(((dest)+(28))>>2)]=((HEAP32[(((src)+(28))>>2)])|0);
            HEAP32[(((dest)+(32))>>2)]=((HEAP32[(((src)+(32))>>2)])|0);
            HEAP32[(((dest)+(36))>>2)]=((HEAP32[(((src)+(36))>>2)])|0);
            HEAP32[(((dest)+(40))>>2)]=((HEAP32[(((src)+(40))>>2)])|0);
            HEAP32[(((dest)+(44))>>2)]=((HEAP32[(((src)+(44))>>2)])|0);
            HEAP32[(((dest)+(48))>>2)]=((HEAP32[(((src)+(48))>>2)])|0);
            HEAP32[(((dest)+(52))>>2)]=((HEAP32[(((src)+(52))>>2)])|0);
            HEAP32[(((dest)+(56))>>2)]=((HEAP32[(((src)+(56))>>2)])|0);
            HEAP32[(((dest)+(60))>>2)]=((HEAP32[(((src)+(60))>>2)])|0);
            dest = (dest+64)|0;
            src = (src+64)|0;
          }
          while ((dest|0) < (aligned_dest_end|0) ) {
            HEAP32[((dest)>>2)]=((HEAP32[((src)>>2)])|0);
            dest = (dest+4)|0;
            src = (src+4)|0;
          }
        } else {
          // In the unaligned copy case, unroll a bit as well.
          aligned_dest_end = (dest_end - 4)|0;
          while ((dest|0) < (aligned_dest_end|0) ) {
            HEAP8[((dest)>>0)]=((HEAP8[((src)>>0)])|0);
            HEAP8[(((dest)+(1))>>0)]=((HEAP8[(((src)+(1))>>0)])|0);
            HEAP8[(((dest)+(2))>>0)]=((HEAP8[(((src)+(2))>>0)])|0);
            HEAP8[(((dest)+(3))>>0)]=((HEAP8[(((src)+(3))>>0)])|0);
            dest = (dest+4)|0;
            src = (src+4)|0;
          }
        }
        // The remaining unaligned < 4 byte tail.
        while ((dest|0) < (dest_end|0)) {
          HEAP8[((dest)>>0)]=((HEAP8[((src)>>0)])|0);
          dest = (dest+1)|0;
          src = (src+1)|0;
        }
        return ret|0;
      }
  
  
    
    var MONO={pump_count:0,timeout_queue:[],mono_wasm_runtime_is_ready:false,pump_message:function () {
    			if (!this.mono_background_exec)
    				this.mono_background_exec = Module.cwrap ("mono_background_exec", 'void', [ ]);
    			while (MONO.timeout_queue.length > 0) {
    				--MONO.pump_count;
    				MONO.timeout_queue.shift()();
    			}
    			while (MONO.pump_count > 0) {
    				--MONO.pump_count;
    				this.mono_background_exec ();
    			}
    		},mono_wasm_get_call_stack:function () {
    			if (!this.mono_wasm_current_bp_id)
    				this.mono_wasm_current_bp_id = Module.cwrap ("mono_wasm_current_bp_id", 'number', [ ]);
    			if (!this.mono_wasm_enum_frames)
    				this.mono_wasm_enum_frames = Module.cwrap ("mono_wasm_enum_frames", 'void', [ ]);
    
    			var bp_id = this.mono_wasm_current_bp_id ();
    			this.active_frames = [];
    			this.mono_wasm_enum_frames ();
    
    			var the_frames = this.active_frames;
    			this.active_frames = [];
    			return {
    				"breakpoint_id": bp_id,
    				"frames": the_frames,
    			};
    		},mono_wasm_get_variables:function (scope, var_list) {
    			if (!this.mono_wasm_get_var_info)
    				this.mono_wasm_get_var_info = Module.cwrap ("mono_wasm_get_var_info", 'void', [ 'number', 'number', 'number']);
    
    			this.var_info = [];
    			var numBytes = var_list.length * Int32Array.BYTES_PER_ELEMENT;
    			var ptr = Module._malloc(numBytes);
    			var heapBytes = new Int32Array(Module.HEAP32.buffer, ptr, numBytes);
    			for (let i=0; i<var_list.length; i++) {
    				heapBytes[i] = var_list[i]
    			}
    			this.mono_wasm_get_var_info (scope, heapBytes.byteOffset, var_list.length);
    			Module._free(heapBytes.byteOffset);
    			var res = this.var_info;
    			this.var_info = []
    
    			return res;
    		},mono_wasm_get_object_properties:function (objId) {
    			if (!this.mono_wasm_get_object_properties_info)
    				this.mono_wasm_get_object_properties_info = Module.cwrap ("mono_wasm_get_object_properties", 'void', [ 'number' ]);
    
    			this.var_info = [];
    			console.log (">> mono_wasm_get_object_properties " + objId);
    			this.mono_wasm_get_object_properties_info (objId);
    
    			var res = this.var_info;
    			this.var_info = []
    
    			return res;
    		},mono_wasm_get_array_values:function (objId) {
    			if (!this.mono_wasm_get_array_values_info)
    				this.mono_wasm_get_array_values_info = Module.cwrap ("mono_wasm_get_array_values", 'void', [ 'number' ]);
    
    			this.var_info = [];
    			console.log (">> mono_wasm_get_array_values " + objId);
    			this.mono_wasm_get_array_values_info (objId);
    
    			var res = this.var_info;
    			this.var_info = []
    
    			return res;
    		},mono_wasm_start_single_stepping:function (kind) {
    			console.log (">> mono_wasm_start_single_stepping " + kind);
    			if (!this.mono_wasm_setup_single_step)
    				this.mono_wasm_setup_single_step = Module.cwrap ("mono_wasm_setup_single_step", 'void', [ 'number']);
    
    			this.mono_wasm_setup_single_step (kind);
    		},mono_wasm_runtime_ready:function () {
    			console.log (">>mono_wasm_runtime_ready");
    			this.mono_wasm_runtime_is_ready = true;
    			debugger;
    		},mono_wasm_set_breakpoint:function (assembly, method_token, il_offset) {
    			if (!this.mono_wasm_set_bp)
    				this.mono_wasm_set_bp = Module.cwrap ('mono_wasm_set_breakpoint', 'number', ['string', 'number', 'number']);
    
    			return this.mono_wasm_set_bp (assembly, method_token, il_offset)
    		},mono_wasm_remove_breakpoint:function (breakpoint_id) {
    			if (!this.mono_wasm_del_bp)
    				this.mono_wasm_del_bp = Module.cwrap ('mono_wasm_remove_breakpoint', 'number', ['number']);
    
    			return this.mono_wasm_del_bp (breakpoint_id);
    		},mono_wasm_setenv:function (name, value) {
    			if (!this.wasm_setenv)
    				this.wasm_setenv = Module.cwrap ('mono_wasm_setenv', 'void', ['string', 'string']);
    			this.wasm_setenv (name, value);
    		},mono_wasm_set_runtime_options:function (options) {
    			if (!this.wasm_parse_runtime_options)
    				this.wasm_parse_runtime_options = Module.cwrap ('mono_wasm_parse_runtime_options', 'void', ['number', 'number']);
    			var argv = Module._malloc (options.length * 4);
    			var wasm_strdup = Module.cwrap ('mono_wasm_strdup', 'number', ['string']);
    			aindex = 0;
    			for (var i = 0; i < options.length; ++i) {
    				Module.setValue (argv + (aindex * 4), wasm_strdup (options [i]), "i32");
    				aindex += 1;
    			}
    			this.wasm_parse_runtime_options (options.length, argv);
    		},mono_wasm_init_aot_profiler:function (options) {
    			if (options == null)
    				options = {}
    			if (!('write_at' in options))
    				options.write_at = 'WebAssembly.Runtime::StopProfile';
    			if (!('send_to' in options))
    				options.send_to = 'WebAssembly.Runtime::DumpAotProfileData';
    			var arg = "aot:write-at-method=" + options.write_at + ",send-to-method=" + options.send_to;
    			Module.ccall ('mono_wasm_load_profiler_aot', 'void', ['string'], [arg]);
    		},mono_load_runtime_and_bcl:function (vfs_prefix, deploy_prefix, enable_debugging, file_list, loaded_cb, fetch_file_cb) {
    			var pending = file_list.length;
    			var loaded_files = [];
    			var mono_wasm_add_assembly = Module.cwrap ('mono_wasm_add_assembly', null, ['string', 'number', 'number']);
    
    			if (!fetch_file_cb) {
    				if (ENVIRONMENT_IS_NODE) {
    					var fs = require('fs');
    					fetch_file_cb = function (asset) {
    						console.log("Loading... " + asset);
    						var binary = fs.readFileSync (asset);
    						var resolve_func2 = function(resolve, reject) {
    							resolve(new Uint8Array (binary));
    						};
    
    						var resolve_func1 = function(resolve, reject) {
    							var response = {
    								ok: true,
    								url: asset,
    								arrayBuffer: function() {
    									return new Promise(resolve_func2);
    								}
    							};
    							resolve(response);
    						};
    
    						return new Promise(resolve_func1);
    					};
    				} else {
    					fetch_file_cb = function (asset) {
    						return fetch (asset, { credentials: 'same-origin' });
    					}
    				}
    			}
    
    			file_list.forEach (function(file_name) {
    				
    				var fetch_promise = fetch_file_cb (locateFile(deploy_prefix + "/" + file_name));
    
    				fetch_promise.then (function (response) {
    					if (!response.ok)
    						throw "failed to load '" + file_name + "'";
    					loaded_files.push (response.url);
    					return response ['arrayBuffer'] ();
    				}).then (function (blob) {
    					var asm = new Uint8Array (blob);
    					var memory = Module._malloc(asm.length);
    					var heapBytes = new Uint8Array(Module.HEAPU8.buffer, memory, asm.length);
    					heapBytes.set (asm);
    					mono_wasm_add_assembly (file_name, memory, asm.length);
    
    					console.log ("Loaded: " + file_name);
    					--pending;
    					if (pending == 0) {
    						MONO.loaded_files = loaded_files;
    						var load_runtime = Module.cwrap ('mono_wasm_load_runtime', null, ['string', 'number']);
    
    						console.log ("initializing mono runtime");
    						if (ENVIRONMENT_IS_SHELL) {
    							try {
    								load_runtime (vfs_prefix, enable_debugging);
    							} catch (ex) {
    								print ("load_runtime () failed: " + ex);
    								var err = new Error();
    								print ("Stacktrace: \n");
    								print (err.stack);
    
    								var wasm_exit = Module.cwrap ('mono_wasm_exit', 'void', ['number']);
    								wasm_exit (1);
    							}
    						} else {
    							load_runtime (vfs_prefix, enable_debugging);
    						}
    						MONO.mono_wasm_runtime_ready ();
    						loaded_cb ();
    					}
    				});
    			});
    		},mono_wasm_get_loaded_files:function () {
    			console.log(">>>mono_wasm_get_loaded_files");
    			return this.loaded_files;
    		},mono_wasm_clear_all_breakpoints:function () {
    			if (this.mono_clear_bps)
    				this.mono_clear_bps = Module.cwrap ('mono_wasm_clear_all_breakpoints', 'void', [ ]);
    			this.mono_clear_bps ();
    		}};function _mono_set_timeout(timeout, id) {
    		if (!this.mono_set_timeout_exec)
    			this.mono_set_timeout_exec = Module.cwrap ("mono_set_timeout_exec", 'void', [ 'number' ]);
    		if (ENVIRONMENT_IS_WEB) {
    			window.setTimeout (function () {
    				this.mono_set_timeout_exec (id);
    			}, timeout);
    		} else if (ENVIRONMENT_IS_WORKER) {
    			self.setTimeout (function () {
    				this.mono_set_timeout_exec (id);
    			}, timeout);
    		} else {
    			++MONO.pump_count;
    			MONO.timeout_queue.push(function() {
    				this.mono_set_timeout_exec (id);
    			})
    		}
    	}
  
    function _mono_wasm_add_array_item(position) {
    		MONO.var_info.push({
    			name: "[" + position + "]",
    		});
    	}
  
    function _mono_wasm_add_array_var(className, objectId) {
    		if (objectId == 0) {
    			MONO.var_info.push({
    				value: {
    					type: "array",
    					className: Module.UTF8ToString (className),
    					description: Module.UTF8ToString (className),
    					subtype: "null"
    				}
    			});
    		} else {
    			MONO.var_info.push({
    				value: {
    					type: "array",
    					className: Module.UTF8ToString (className),
    					description: Module.UTF8ToString (className),
    					objectId: "dotnet:array:"+ objectId,
    				}
    			});
    		}
    	}
  
    function _mono_wasm_add_bool_var(var_value) {
    		MONO.var_info.push({
    			value: {
    				type: "boolean",
    				value: var_value != 0,
    			}
    		});
    	}
  
    function _mono_wasm_add_frame(il, method, name) {
    		MONO.active_frames.push( {
    			il_pos: il,
    			method_token: method,
    			assembly_name: Module.UTF8ToString (name)
    		});
    	}
  
    function _mono_wasm_add_number_var(var_value) {
    		MONO.var_info.push({
    			value: {
    				type: "number",
    				value: var_value,
    			}
    		});
    	}
  
    function _mono_wasm_add_obj_var(className, objectId) {
    		if (objectId == 0) {
    			MONO.var_info.push({
    				value: {
    					type: "object",
    					className: Module.UTF8ToString (className),
    					description: Module.UTF8ToString (className),
    					subtype: "null"
    				}
    			});
    		} else {
    			MONO.var_info.push({
    				value: {
    					type: "object",
    					className: Module.UTF8ToString (className),
    					description: Module.UTF8ToString (className),
    					objectId: "dotnet:object:"+ objectId,
    				}
    			});
    		}
    	}
  
    function _mono_wasm_add_properties_var(name) {
    		MONO.var_info.push({
    			name: Module.UTF8ToString (name),
    		});
    	}
  
    function _mono_wasm_add_string_var(var_value) {
    		if (var_value == 0) {
    			MONO.var_info.push({
    				value: {
    					type: "object",
    					subtype: "null"
    				}
    			});
    		} else {
    			MONO.var_info.push({
    				value: {
    					type: "string",
    					value: Module.UTF8ToString (var_value),
    				}
    			});
    		}
    	}
  
    
    var BINDING={BINDING_ASM:"[WebAssembly.Bindings]WebAssembly.Runtime",mono_wasm_object_registry:[],mono_wasm_ref_counter:0,mono_wasm_free_list:[],mono_wasm_marshal_enum_as_int:false,mono_bindings_init:function (binding_asm) {
    			this.BINDING_ASM = binding_asm;
    		},export_functions:function (module) {
    			module ["mono_bindings_init"] = BINDING.mono_bindings_init.bind(BINDING);
    			module ["mono_method_invoke"] = BINDING.call_method.bind(BINDING);
    			module ["mono_method_get_call_signature"] = BINDING.mono_method_get_call_signature.bind(BINDING);
    			module ["mono_method_resolve"] = BINDING.resolve_method_fqn.bind(BINDING);
    			module ["mono_bind_static_method"] = BINDING.bind_static_method.bind(BINDING);
    			module ["mono_call_static_method"] = BINDING.call_static_method.bind(BINDING);
    		},bindings_lazy_init:function () {
    			if (this.init)
    				return;
    		
    			this.assembly_load = Module.cwrap ('mono_wasm_assembly_load', 'number', ['string']);
    			this.find_class = Module.cwrap ('mono_wasm_assembly_find_class', 'number', ['number', 'string', 'string']);
    			this.find_method = Module.cwrap ('mono_wasm_assembly_find_method', 'number', ['number', 'string', 'number']);
    			this.invoke_method = Module.cwrap ('mono_wasm_invoke_method', 'number', ['number', 'number', 'number', 'number']);
    			this.mono_string_get_utf8 = Module.cwrap ('mono_wasm_string_get_utf8', 'number', ['number']);
    			this.js_string_to_mono_string = Module.cwrap ('mono_wasm_string_from_js', 'number', ['string']);
    			this.mono_get_obj_type = Module.cwrap ('mono_wasm_get_obj_type', 'number', ['number']);
    			this.mono_unbox_int = Module.cwrap ('mono_unbox_int', 'number', ['number']);
    			this.mono_unbox_float = Module.cwrap ('mono_wasm_unbox_float', 'number', ['number']);
    			this.mono_array_length = Module.cwrap ('mono_wasm_array_length', 'number', ['number']);
    			this.mono_array_get = Module.cwrap ('mono_wasm_array_get', 'number', ['number', 'number']);
    			this.mono_obj_array_new = Module.cwrap ('mono_wasm_obj_array_new', 'number', ['number']);
    			this.mono_obj_array_set = Module.cwrap ('mono_wasm_obj_array_set', 'void', ['number', 'number', 'number']);
    			this.mono_unbox_enum = Module.cwrap ('mono_wasm_unbox_enum', 'number', ['number']);
    
    			// receives a byteoffset into allocated Heap with a size.
    			this.mono_typed_array_new = Module.cwrap ('mono_wasm_typed_array_new', 'number', ['number','number','number','number']);
    
    			var binding_fqn_asm = this.BINDING_ASM.substring(this.BINDING_ASM.indexOf ("[") + 1, this.BINDING_ASM.indexOf ("]")).trim();
    			var binding_fqn_class = this.BINDING_ASM.substring (this.BINDING_ASM.indexOf ("]") + 1).trim();
    			
    			this.binding_module = this.assembly_load (binding_fqn_asm);
    			if (!this.binding_module)
    				throw "Can't find bindings module assembly: " + binding_fqn_asm;
    
    			if (binding_fqn_class !== null && typeof binding_fqn_class !== "undefined")
    			{
    				var namespace = "WebAssembly";
    				var classname = binding_fqn_class.length > 0 ? binding_fqn_class : "Runtime";
    				if (binding_fqn_class.indexOf(".") != -1) {
    					var idx = binding_fqn_class.lastIndexOf(".");
    					namespace = binding_fqn_class.substring (0, idx);
    					classname = binding_fqn_class.substring (idx + 1);
    				}
    			}
    
    			var wasm_runtime_class = this.find_class (this.binding_module, namespace, classname)
    			if (!wasm_runtime_class)
    				throw "Can't find " + binding_fqn_class + " class";
    
    			var get_method = function(method_name) {
    				var res = BINDING.find_method (wasm_runtime_class, method_name, -1)
    				if (!res)
    					throw "Can't find method " + namespace + "." + classname + ":" + method_name;
    				return res;
    			}
    			this.bind_js_obj = get_method ("BindJSObject");
    			this.bind_core_clr_obj = get_method ("BindCoreCLRObject");
    			this.bind_existing_obj = get_method ("BindExistingObject");
    			this.unbind_js_obj = get_method ("UnBindJSObject");
    			this.unbind_js_obj_and_free = get_method ("UnBindJSObjectAndFree");			
    			this.unbind_raw_obj_and_free = get_method ("UnBindRawJSObjectAndFree");			
    			this.get_js_id = get_method ("GetJSObjectId");
    			this.get_raw_mono_obj = get_method ("GetMonoObject");
    
    			this.box_js_int = get_method ("BoxInt");
    			this.box_js_double = get_method ("BoxDouble");
    			this.box_js_bool = get_method ("BoxBool");
    			this.is_simple_array = get_method ("IsSimpleArray");
    			this.get_core_type = get_method ("GetCoreType");
    			this.setup_js_cont = get_method ("SetupJSContinuation");
    
    			this.create_tcs = get_method ("CreateTaskSource");
    			this.set_tcs_result = get_method ("SetTaskSourceResult");
    			this.set_tcs_failure = get_method ("SetTaskSourceFailure");
    			this.tcs_get_task_and_bind = get_method ("GetTaskAndBind");
    			this.get_call_sig = get_method ("GetCallSignature");
    
    			this.object_to_string = get_method ("ObjectToString");
    			this.get_date_value = get_method ("GetDateValue");
    			this.create_date_time = get_method ("CreateDateTime");
    
    			this.object_to_enum = get_method ("ObjectToEnum");
    			this.init = true;
    		},get_js_obj:function (js_handle) {
    			if (js_handle > 0)
    				return this.mono_wasm_require_handle(js_handle);
    			return null;
    		},conv_string:function (mono_obj) {
    			if (mono_obj == 0)
    				return null;
    			var raw = this.mono_string_get_utf8 (mono_obj);
    			var res = Module.UTF8ToString (raw);
    			Module._free (raw);
    
    			return res;
    		},is_nested_array:function (ele) {
    			return this.call_method (this.is_simple_array, null, "mi", [ ele ]);
    		},mono_array_to_js_array:function (mono_array) {
    			if (mono_array == 0)
    				return null;
    
    			var res = [];
    			var len = this.mono_array_length (mono_array);
    			for (var i = 0; i < len; ++i)
    			{
    				var ele = this.mono_array_get (mono_array, i);
    				if (this.is_nested_array(ele))
    					res.push(this.mono_array_to_js_array(ele));
    				else
    					res.push (this.unbox_mono_obj (ele));
    			}
    
    			return res;
    		},js_array_to_mono_array:function (js_array) {
    			var mono_array = this.mono_obj_array_new (js_array.length);
    			for (var i = 0; i < js_array.length; ++i) {
    				this.mono_obj_array_set (mono_array, i, this.js_to_mono_obj (js_array [i]));
    			}
    			return mono_array;
    		},unbox_mono_obj:function (mono_obj) {
    			if (mono_obj == 0)
    				return undefined;
    			var type = this.mono_get_obj_type (mono_obj);
    			//See MARSHAL_TYPE_ defines in driver.c
    			switch (type) {
    			case 1: // int
    				return this.mono_unbox_int (mono_obj);
    			case 2: // float
    				return this.mono_unbox_float (mono_obj);
    			case 3: //string
    				return this.conv_string (mono_obj);
    			case 4: //vts
    				throw new Error ("no idea on how to unbox value types");
    			case 5: { // delegate
    				var obj = this.extract_js_obj (mono_obj);
    				return function () {
    					return BINDING.invoke_delegate (obj, arguments);
    				};
    			}
    			case 6: {// Task
    
    				if (typeof Promise === "undefined" || typeof Promise.resolve === "undefined")
    					throw new Error ("Promises are not supported thus C# Tasks can not work in this context.");
    
    				var obj = this.extract_js_obj (mono_obj);
    				var cont_obj = null;
    				var promise = new Promise (function (resolve, reject) {
    					cont_obj = {
    						resolve: resolve,
    						reject: reject
    					};
    				});
    
    				this.call_method (this.setup_js_cont, null, "mo", [ mono_obj, cont_obj ]);
    				obj.__mono_js_cont__ = cont_obj.__mono_gchandle__;
    				cont_obj.__mono_js_task__ = obj.__mono_gchandle__;
    				return promise;
    			}
    
    			case 7: // ref type
    				return this.extract_js_obj (mono_obj);
    
    			case 8: // bool
    				return this.mono_unbox_int (mono_obj) != 0;
    
    			case 9: // enum
    
    				if(this.mono_wasm_marshal_enum_as_int)
    				{
    					return this.mono_unbox_enum (mono_obj);
    				}
    				else
    				{
    					enumValue = this.call_method(this.object_to_string, null, "m", [ mono_obj ]);
    				}
    
    				return enumValue;
    
    
    			case 11: 
    			case 12: 
    			case 13: 
    			case 14: 
    			case 15: 
    			case 16: 
    			case 17: 
    			case 18:
    			{
    				throw new Error ("Marshalling of primitive arrays are not supported.  Use the corresponding TypedArray instead.");
    			}
    			case 20: // clr .NET DateTime
    				var dateValue = this.call_method(this.get_date_value, null, "md", [ mono_obj ]);
    				return new Date(dateValue);
    			case 21: // clr .NET DateTimeOffset
    				var dateoffsetValue = this.call_method(this.object_to_string, null, "m", [ mono_obj ]);
    				return dateoffsetValue;
    			default:
    				throw new Error ("no idea on how to unbox object kind " + type);
    			}
    		},create_task_completion_source:function () {
    			return this.call_method (this.create_tcs, null, "i", [ -1 ]);
    		},set_task_result:function (tcs, result) {
    			tcs.is_mono_tcs_result_set = true;
    			this.call_method (this.set_tcs_result, null, "oo", [ tcs, result ]);
    			if (tcs.is_mono_tcs_task_bound)
    				this.free_task_completion_source(tcs);
    		},set_task_failure:function (tcs, reason) {
    			tcs.is_mono_tcs_result_set = true;
    			this.call_method (this.set_tcs_failure, null, "os", [ tcs, reason.toString () ]);
    			if (tcs.is_mono_tcs_task_bound)
    				this.free_task_completion_source(tcs);
    		},js_typedarray_to_heap:function (typedArray){
    			var numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;
    			var ptr = Module._malloc(numBytes);
    			var heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, numBytes);
    			heapBytes.set(new Uint8Array(typedArray.buffer, typedArray.byteOffset, numBytes));
    			return heapBytes;
    		},js_to_mono_obj:function (js_obj) {
    	  		this.bindings_lazy_init ();
    
    			if (js_obj == null || js_obj == undefined)
    				return 0;
    			if (typeof js_obj === 'number') {
    				if (parseInt(js_obj) == js_obj)
    					return this.call_method (this.box_js_int, null, "im", [ js_obj ]);
    				return this.call_method (this.box_js_double, null, "dm", [ js_obj ]);
    			}
    			if (typeof js_obj === 'string')
    				return this.js_string_to_mono_string (js_obj);
    
    			if (typeof js_obj === 'boolean')
    				return this.call_method (this.box_js_bool, null, "im", [ js_obj ]);
    
    			if (Promise.resolve(js_obj) === js_obj) {
    				var the_task = this.try_extract_mono_obj (js_obj);
    				if (the_task)
    					return the_task;
    				var tcs = this.create_task_completion_source ();
    
    				js_obj.then (function (result) {
    					BINDING.set_task_result (tcs, result);
    				}, function (reason) {
    					BINDING.set_task_failure (tcs, reason);
    				})
    
    				return this.get_task_and_bind (tcs, js_obj);
    			}
    
    			if (js_obj.constructor.name === "Date")
    				// We may need to take into account the TimeZone Offset
    				return this.call_method(this.create_date_time, null, "dm", [ js_obj.getTime() ]);
    
    			return this.extract_mono_obj (js_obj);
    		},js_typed_array_to_array:function (js_obj) {
    
    			// JavaScript typed arrays are array-like objects and provide a mechanism for accessing 
    			// raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays 
    			// split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
    			//  is an object representing a chunk of data; it has no format to speak of, and offers no 
    			// mechanism for accessing its contents. In order to access the memory contained in a buffer, 
    			// you need to use a view. A view provides a context — that is, a data type, starting offset, 
    			// and number of elements — that turns the data into an actual typed array.
    			// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
    			if (!!(js_obj.buffer instanceof ArrayBuffer && js_obj.BYTES_PER_ELEMENT)) 
    			{
    				var arrayType = 0;	
    				if (js_obj instanceof Int8Array)
    					arrayType = 11;
    				if (js_obj instanceof Uint8Array)
    					arrayType = 12;
    				if (js_obj instanceof Uint8ClampedArray)
    					arrayType = 12;
    				if (js_obj instanceof Int16Array)
    					arrayType = 13;
    				if (js_obj instanceof Uint16Array)
    					arrayType = 14;
    				if (js_obj instanceof Int32Array)
    					arrayType = 15;
    				if (js_obj instanceof Uint32Array)
    					arrayType = 16;
    				if (js_obj instanceof Float32Array)
    					arrayType = 17;
    				if (js_obj instanceof Float64Array)
    					arrayType = 18;
    
    				var heapBytes = this.js_typedarray_to_heap(js_obj);
    				var bufferArray = this.mono_typed_array_new(heapBytes.byteOffset, js_obj.length, js_obj.BYTES_PER_ELEMENT, arrayType);
    				Module._free(heapBytes.byteOffset);
    				return bufferArray;
    			}
    			else {
    				throw new Error("Object '" + js_obj + "' is not a typed array");
    			} 
    
    
    		},typedarray_copy_to:function (typed_array, pinned_array, begin, end, bytes_per_element) {
    
    			// JavaScript typed arrays are array-like objects and provide a mechanism for accessing 
    			// raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays 
    			// split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
    			//  is an object representing a chunk of data; it has no format to speak of, and offers no 
    			// mechanism for accessing its contents. In order to access the memory contained in a buffer, 
    			// you need to use a view. A view provides a context — that is, a data type, starting offset, 
    			// and number of elements — that turns the data into an actual typed array.
    			// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
    			if (!!(typed_array.buffer instanceof ArrayBuffer && typed_array.BYTES_PER_ELEMENT)) 
    			{
    				// Some sanity checks of what is being asked of us
    				// lets play it safe and throw an error here instead of assuming to much.
    				// Better safe than sorry later
    				if (bytes_per_element !== typed_array.BYTES_PER_ELEMENT)
    					throw new Error("Inconsistent element sizes: TypedArray.BYTES_PER_ELEMENT '" + typed_array.BYTES_PER_ELEMENT + "' sizeof managed element: '" + bytes_per_element + "'");
    
    				// how much space we have to work with
    				var num_of_bytes = (end - begin) * bytes_per_element;
    				// how much typed buffer space are we talking about
    				var view_bytes = typed_array.length * typed_array.BYTES_PER_ELEMENT;
    				// only use what is needed.
    				if (num_of_bytes > view_bytes)
    					num_of_bytes = view_bytes;
    
    				// offset index into the view
    				var offset = begin * bytes_per_element;
    
    				// Create a view over the heap pointed to by the pinned array address
    				var heapBytes = new Uint8Array(Module.HEAPU8.buffer, pinned_array + offset, num_of_bytes);
    				// Copy the bytes of the typed array to the heap.
    				heapBytes.set(new Uint8Array(typed_array.buffer, typed_array.byteOffset, num_of_bytes));
    
    				return num_of_bytes;
    			}
    			else {
    				throw new Error("Object '" + typed_array + "' is not a typed array");
    			} 
    
    		},typedarray_copy_from:function (typed_array, pinned_array, begin, end, bytes_per_element) {
    
    			// JavaScript typed arrays are array-like objects and provide a mechanism for accessing 
    			// raw binary data. (...) To achieve maximum flexibility and efficiency, JavaScript typed arrays 
    			// split the implementation into buffers and views. A buffer (implemented by the ArrayBuffer object)
    			//  is an object representing a chunk of data; it has no format to speak of, and offers no 
    			// mechanism for accessing its contents. In order to access the memory contained in a buffer, 
    			// you need to use a view. A view provides a context — that is, a data type, starting offset, 
    			// and number of elements — that turns the data into an actual typed array.
    			// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
    			if (!!(typed_array.buffer instanceof ArrayBuffer && typed_array.BYTES_PER_ELEMENT)) 
    			{
    				// Some sanity checks of what is being asked of us
    				// lets play it safe and throw an error here instead of assuming to much.
    				// Better safe than sorry later
    				if (bytes_per_element !== typed_array.BYTES_PER_ELEMENT)
    					throw new Error("Inconsistent element sizes: TypedArray.BYTES_PER_ELEMENT '" + typed_array.BYTES_PER_ELEMENT + "' sizeof managed element: '" + bytes_per_element + "'");
    
    				// how much space we have to work with
    				var num_of_bytes = (end - begin) * bytes_per_element;
    				// how much typed buffer space are we talking about
    				var view_bytes = typed_array.length * typed_array.BYTES_PER_ELEMENT;
    				// only use what is needed.
    				if (num_of_bytes > view_bytes)
    					num_of_bytes = view_bytes;
    
    				// Create a new view for mapping
    				var typedarrayBytes = new Uint8Array(typed_array.buffer, 0, num_of_bytes);
    				// offset index into the view
    				var offset = begin * bytes_per_element;
    				// Set view bytes to value from HEAPU8
    				typedarrayBytes.set(Module.HEAPU8.subarray(pinned_array + offset, pinned_array + offset + num_of_bytes));
    				return num_of_bytes;
    			}
    			else {
    				throw new Error("Object '" + typed_array + "' is not a typed array");
    			} 
    
    		},typed_array_from:function (pinned_array, begin, end, bytes_per_element, type) {
    
    			// typed array
    			var newTypedArray = 0;
    
    			switch (type)
    			{
    				case 5: 
    					newTypedArray = new Int8Array(end - begin);
    					break;
    				case 6: 
    					newTypedArray = new Uint8Array(end - begin);
    					break;
    				case 7: 
    					newTypedArray = new Int16Array(end - begin);
    					break;
    				case 8: 
    					newTypedArray = new Uint16Array(end - begin);
    					break;
    				case 9: 
    					newTypedArray = new Int32Array(end - begin);
    					break;
    				case 10: 
    					newTypedArray = new Uint32Array(end - begin);
    					break;
    				case 13: 
    					newTypedArray = new Float32Array(end - begin);
    					break;
    				case 14:
    					newTypedArray = new Float64Array(end - begin);
    					break;
    				case 15:  // This is a special case because the typed array is also byte[]
    					newTypedArray = new Uint8ClampedArray(end - begin);
    					break;
    			}
    
    			this.typedarray_copy_from(newTypedArray, pinned_array, begin, end, bytes_per_element);
    			return newTypedArray;
    		},js_to_mono_enum:function (method, parmIdx, js_obj) {
    			this.bindings_lazy_init ();
        
    			if (js_obj === null || typeof js_obj === "undefined")
    				return 0;
    
    			var monoObj = this.js_to_mono_obj(js_obj);
    			// Check enum contract
    			var monoEnum = this.call_method(this.object_to_enum, null, "iimm", [ method, parmIdx, monoObj ])
    			// return the unboxed enum value.
    			return this.mono_unbox_enum(monoEnum);
    		},wasm_binding_obj_new:function (js_obj_id, type)
    		{
    			return this.call_method (this.bind_js_obj, null, "io", [js_obj_id, type]);
    		},wasm_bind_existing:function (mono_obj, js_id)
    		{
    			return this.call_method (this.bind_existing_obj, null, "mi", [mono_obj, js_id]);
    		},wasm_bind_core_clr_obj:function (js_id, gc_handle)
    		{
    			return this.call_method (this.bind_core_clr_obj, null, "ii", [js_id, gc_handle]);
    		},wasm_unbind_js_obj:function (js_obj_id)
    		{
    			this.call_method (this.unbind_js_obj, null, "i", [js_obj_id]);
    		},wasm_unbind_js_obj_and_free:function (js_obj_id)
    		{
    			this.call_method (this.unbind_js_obj_and_free, null, "i", [js_obj_id]);
    		},wasm_get_js_id:function (mono_obj)
    		{
    			return this.call_method (this.get_js_id, null, "m", [mono_obj]);
    		},wasm_get_raw_obj:function (gchandle)
    		{
    			return this.call_method (this.get_raw_mono_obj, null, "im", [gchandle]);
    		},try_extract_mono_obj:function (js_obj) {
    			if (js_obj === null || typeof js_obj === "undefined" || typeof js_obj.__mono_gchandle__ === "undefined")
    				return 0;
    			return this.wasm_get_raw_obj (js_obj.__mono_gchandle__);
    		},mono_method_get_call_signature:function (method) {
    			this.bindings_lazy_init ();
    
    			return this.call_method (this.get_call_sig, null, "i", [ method ]);
    		},get_task_and_bind:function (tcs, js_obj) {
    			var gc_handle = this.mono_wasm_free_list.length ? this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++;
    			var task_gchandle = this.call_method (this.tcs_get_task_and_bind, null, "oi", [ tcs, gc_handle + 1 ]);
    			js_obj.__mono_gchandle__ = task_gchandle;
    			this.mono_wasm_object_registry[gc_handle] = js_obj;
    			this.free_task_completion_source(tcs);
    			tcs.is_mono_tcs_task_bound = true;
    			js_obj.__mono_bound_tcs__ = tcs.__mono_gchandle__;
    			tcs.__mono_bound_task__ = js_obj.__mono_gchandle__;
    			return this.wasm_get_raw_obj (js_obj.__mono_gchandle__);
    		},free_task_completion_source:function (tcs) {
    			if (tcs.is_mono_tcs_result_set)
    			{
    				this.call_method (this.unbind_raw_obj_and_free, null, "ii", [ tcs.__mono_gchandle__ ]);
    			}
    			if (tcs.__mono_bound_task__)
    			{
    				this.call_method (this.unbind_raw_obj_and_free, null, "ii", [ tcs.__mono_bound_task__ ]);
    			}
    		},extract_mono_obj:function (js_obj) {
    
    			if (js_obj === null || typeof js_obj === "undefined")
    				return 0;
    
    			if (!js_obj.is_mono_bridged_obj) {
    				var gc_handle = this.mono_wasm_register_obj(js_obj);
    				return this.wasm_get_raw_obj (gc_handle);
    			}
    
    
    			return this.wasm_get_raw_obj (js_obj.__mono_gchandle__);
    		},extract_js_obj:function (mono_obj) {
    			if (mono_obj == 0)
    				return null;
    
    			var js_id = this.wasm_get_js_id (mono_obj);
    			if (js_id > 0)
    				return this.mono_wasm_require_handle(js_id);
    
    			var gcHandle = this.mono_wasm_free_list.length ? this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++;
    			var js_obj = {
    				__mono_gchandle__: this.wasm_bind_existing(mono_obj, gcHandle + 1),
    				is_mono_bridged_obj: true
    			};
    
    			this.mono_wasm_object_registry[gcHandle] = js_obj;
    			return js_obj;
    		},call_method:function (method, this_arg, args_marshal, args) {
    			this.bindings_lazy_init ();
    
    			var extra_args_mem = 0;
    			for (var i = 0; i < args.length; ++i) {
    				//long/double memory must be 8 bytes aligned and I'm being lazy here
    				if (args_marshal[i] == 'i' || args_marshal[i] == 'f' || args_marshal[i] == 'l' || args_marshal[i] == 'd' || args_marshal[i] == 'j' || args_marshal[i] == 'k')
    					extra_args_mem += 8;
    			}
    
    			var extra_args_mem = extra_args_mem ? Module._malloc (extra_args_mem) : 0;
    			var extra_arg_idx = 0;
    			var args_mem = Module._malloc (args.length * 4);
    			var eh_throw = Module._malloc (4);
    			for (var i = 0; i < args.length; ++i) {
    				if (args_marshal[i] == 's') {
    					Module.setValue (args_mem + i * 4, this.js_string_to_mono_string (args [i]), "i32");
    				} else if (args_marshal[i] == 'm') {
    					Module.setValue (args_mem + i * 4, args [i], "i32");
    				} else if (args_marshal[i] == 'o') {
    					Module.setValue (args_mem + i * 4, this.js_to_mono_obj (args [i]), "i32");
    				} else if (args_marshal[i] == 'j'  || args_marshal[i] == 'k') {
    					var enumVal = this.js_to_mono_enum(method, i, args[i]);
    		
    					var extra_cell = extra_args_mem + extra_arg_idx;
    					extra_arg_idx += 8;
    
    					if (args_marshal[i] == 'j')
    						Module.setValue (extra_cell, enumVal, "i32");
    					else if (args_marshal[i] == 'k')
    						Module.setValue (extra_cell, enumVal, "i64");
    
    					Module.setValue (args_mem + i * 4, extra_cell, "i32");
    				} else if (args_marshal[i] == 'i' || args_marshal[i] == 'f' || args_marshal[i] == 'l' || args_marshal[i] == 'd') {
    					var extra_cell = extra_args_mem + extra_arg_idx;
    					extra_arg_idx += 8;
    
    					if (args_marshal[i] == 'i')
    						Module.setValue (extra_cell, args [i], "i32");
    					else if (args_marshal[i] == 'l')
    						Module.setValue (extra_cell, args [i], "i64");
    					else if (args_marshal[i] == 'f')
    						Module.setValue (extra_cell, args [i], "float");
    					else
    						Module.setValue (extra_cell, args [i], "double");
    
    					Module.setValue (args_mem + i * 4, extra_cell, "i32");
    				}
    			}
    			Module.setValue (eh_throw, 0, "i32");
    
    			var res = this.invoke_method (method, this_arg, args_mem, eh_throw);
    
    			var eh_res = Module.getValue (eh_throw, "i32");
    
    			if (extra_args_mem)
    				Module._free (extra_args_mem);
    			Module._free (args_mem);
    			Module._free (eh_throw);
    
    			if (eh_res != 0) {
    				var msg = this.conv_string (res);
    				throw new Error (msg); //the convention is that invoke_method ToString () any outgoing exception
    			}
    
    			if (args_marshal !== null && typeof args_marshal !== "undefined") 
    			{
    				if (args_marshal.length >= args.length && args_marshal [args.length] === "m")
    					return res;
    			}
    
    			return this.unbox_mono_obj (res);
    		},invoke_delegate:function (delegate_obj, js_args) {
    			this.bindings_lazy_init ();
    
    			if (!this.delegate_dynamic_invoke) {
    				if (!this.corlib)
    					this.corlib = this.assembly_load ("mscorlib");
    				if (!this.delegate_class)
    					this.delegate_class = this.find_class (this.corlib, "System", "Delegate");
    				if (!this.delegate_class)
    				{
    					throw new Error("System.Delegate class can not be resolved.");
    				}
    				this.delegate_dynamic_invoke = this.find_method (this.delegate_class, "DynamicInvoke", -1);
    			}
    			var mono_args = this.js_array_to_mono_array (js_args);
    			if (!this.delegate_dynamic_invoke)
    				throw new Error("System.Delegate.DynamicInvoke method can not be resolved.");
    			// Note: the single 'm' passed here is causing problems with AOT.  Changed to "mo" again.  
    			// This may need more analysis if causes problems again.
    			return this.call_method (this.delegate_dynamic_invoke, this.extract_mono_obj (delegate_obj), "mo", [ mono_args ]);
    		},resolve_method_fqn:function (fqn) {
    			var assembly = fqn.substring(fqn.indexOf ("[") + 1, fqn.indexOf ("]")).trim();
    			fqn = fqn.substring (fqn.indexOf ("]") + 1).trim();
    
    			var methodname = fqn.substring(fqn.indexOf (":") + 1);
    			fqn = fqn.substring (0, fqn.indexOf (":")).trim ();
    
    			var namespace = "";
    			var classname = fqn;
    			if (fqn.indexOf(".") != -1) {
    				var idx = fqn.lastIndexOf(".");
    				namespace = fqn.substring (0, idx);
    				classname = fqn.substring (idx + 1);
    			}
    
    			var asm = this.assembly_load (assembly);
    			if (!asm)
    				throw new Error ("Could not find assembly: " + assembly);
    
    			var klass = this.find_class(asm, namespace, classname);
    			if (!klass)
    				throw new Error ("Could not find class: " + namespace + ":" +classname);
    
    			var method = this.find_method (klass, methodname, -1);
    			if (!method)
    				throw new Error ("Could not find method: " + methodname);
    			return method;
    		},call_static_method:function (fqn, args, signature) {
    			this.bindings_lazy_init ();
    
    			var method = this.resolve_method_fqn (fqn);
    
    			if (typeof signature === "undefined")
    				signature = Module.mono_method_get_call_signature (method);
    
    			return this.call_method (method, null, signature, args);
    		},bind_static_method:function (fqn, signature) {
    			this.bindings_lazy_init ();
    
    			var method = this.resolve_method_fqn (fqn);
    
    			if (typeof signature === "undefined")
    				signature = Module.mono_method_get_call_signature (method);
    
    			return function() {
    				return BINDING.call_method (method, null, signature, arguments);
    			};
    		},wasm_get_core_type:function (obj)
    		{
    			return this.call_method (this.get_core_type, null, "so", [ "WebAssembly.Core."+obj.constructor.name ]);
    		},get_wasm_type:function (obj) {
    			var coreType = obj[Symbol.for("wasm type")];
    			if (typeof coreType === "undefined") {
    				switch (obj.constructor.name) {
    					case "Array":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Array.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "ArrayBuffer":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							ArrayBuffer.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "Int8Array":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Int8Array.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "Uint8Array":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Uint8Array.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "Uint8ClampedArray":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Uint8ClampedArray.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "Int16Array":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Int16Array.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "Uint16Array":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Uint16Array.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "Int32Array":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Int32Array.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "Uint32Array":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Uint32Array.prototype[Symbol.for("wasm type")] = coreType
    						}
    						return coreType;
    					case "Float32Array":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Float32Array.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "Float64Array":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Float64Array.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "Function":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							Function.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "SharedArrayBuffer":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							SharedArrayBuffer.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    					case "DataView":
    						coreType = this.wasm_get_core_type(obj);
    						if (typeof coreType !== "undefined") {
    							DataView.prototype[Symbol.for("wasm type")] = coreType
    						}
    						break;
    				}
    		  	}
    			return coreType;
    		},mono_wasm_register_obj:function (obj) {
    
    			var gc_handle = undefined;
    			if (obj !== null && typeof obj !== "undefined") 
    			{
    				gc_handle = obj.__mono_gchandle__;
    
    				if (typeof gc_handle === "undefined") {
    					var handle = this.mono_wasm_free_list.length ?
    								this.mono_wasm_free_list.pop() : this.mono_wasm_ref_counter++;
    					obj.__mono_jshandle__ = handle;
    					// Obtain the JS -> C# type mapping.
    					var wasm_type = this.get_wasm_type(obj);
    					gc_handle = obj.__mono_gchandle__ = this.wasm_binding_obj_new(handle + 1, wasm_type);
    					this.mono_wasm_object_registry[handle] = obj;
    						
    				}
    			}
    			return gc_handle;
    		},mono_wasm_require_handle:function (handle) {
    			if (handle > 0)
    				return this.mono_wasm_object_registry[handle - 1];
    			return null;
    		},mono_wasm_unregister_obj:function (js_id) {
    			var obj = this.mono_wasm_object_registry[js_id - 1];
    			if (typeof obj  !== "undefined" && obj !== null) {
    				// if this is the global object then do not
    				// unregister it.
    				if (typeof ___mono_wasm_global___ !== "undefined" && ___mono_wasm_global___ === obj)
    					return obj;
    
    				var gc_handle = obj.__mono_gchandle__;
    				if (typeof gc_handle  !== "undefined") {
    					this.wasm_unbind_js_obj_and_free(js_id);
    
    					obj.__mono_gchandle__ = undefined;
    					obj.__mono_jshandle__ = undefined;
    
    					this.mono_wasm_object_registry[js_id - 1] = undefined;
    					this.mono_wasm_free_list.push(js_id - 1);
    				}
    			}
    			return obj;
    		},mono_wasm_free_handle:function (handle) {
    			this.mono_wasm_unregister_obj(handle);
    		},mono_wasm_free_raw_object:function (js_id) {
    			var obj = this.mono_wasm_object_registry[js_id - 1];
    			if (typeof obj  !== "undefined" && obj !== null) {
    				// if this is the global object then do not
    				// unregister it.
    				if (typeof ___mono_wasm_global___ !== "undefined" && ___mono_wasm_global___ === obj)
    					return obj;
    
    				var gc_handle = obj.__mono_gchandle__;
    				if (typeof gc_handle  !== "undefined") {
    
    					obj.__mono_gchandle__ = undefined;
    					obj.__mono_jshandle__ = undefined;
    
    					this.mono_wasm_object_registry[js_id - 1] = undefined;
    					this.mono_wasm_free_list.push(js_id - 1);
    				}
    			}
    			return obj;
    		},mono_wasm_get_global:function () {
    			function testGlobal(obj) {
    				obj['___mono_wasm_global___'] = obj;
    				var success = typeof ___mono_wasm_global___ === 'object' && obj['___mono_wasm_global___'] === obj;
    				if (!success) {
    					delete obj['___mono_wasm_global___'];
    				}
    				return success;
    			}
    			if (typeof ___mono_wasm_global___ === 'object') {
    				return ___mono_wasm_global___;
    			}
    			if (typeof global === 'object' && testGlobal(global)) {
    				___mono_wasm_global___ = global;
    			} else if (typeof window === 'object' && testGlobal(window)) {
    				___mono_wasm_global___ = window;
    			} else if (testGlobal((function(){return Function;})()('return this')())) {
    
    				___mono_wasm_global___ = (function(){return Function;})()('return this')();
    
    			}
    			if (typeof ___mono_wasm_global___ === 'object') {
    				return ___mono_wasm_global___;
    			}
    			throw Error('unable to get mono wasm global object.');
    		}};function _mono_wasm_bind_core_object(js_handle, gc_handle, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var requireObject = BINDING.mono_wasm_require_handle (js_handle);
    		if (!requireObject) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		BINDING.wasm_bind_core_clr_obj(js_handle, gc_handle );
    		requireObject.__mono_gchandle__ = gc_handle;
    		return gc_handle;
    	}
  
    function _mono_wasm_bind_host_object(js_handle, gc_handle, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var requireObject = BINDING.mono_wasm_require_handle (js_handle);
    		if (!requireObject) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		BINDING.wasm_bind_core_clr_obj(js_handle, gc_handle );
    		requireObject.__mono_gchandle__ = gc_handle;
    		return gc_handle;
    	}
  
    function _mono_wasm_fire_bp() {
    		console.log ("mono_wasm_fire_bp");
    		debugger;
    	}
  
    function _mono_wasm_get_by_index(js_handle, property_index, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var obj = BINDING.mono_wasm_require_handle (js_handle);
    		if (!obj) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		try {
    			var m = obj [property_index];
    			return BINDING.js_to_mono_obj (m);
    		} catch (e) {
    			var res = e.toString ();
    			setValue (is_exception, 1, "i32");
    			if (res === null || typeof res === "undefined")
    				res = "unknown exception";
    			return BINDING.js_string_to_mono_string (res);
    		}
    	}
  
    function _mono_wasm_get_global_object(global_name, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var js_name = BINDING.conv_string (global_name);
    
    		var globalObj = undefined;
    
    		if (!js_name) {
    			globalObj = BINDING.mono_wasm_get_global();
    		}
    		else {
    			globalObj = BINDING.mono_wasm_get_global()[js_name];
    		}
    
    		if (globalObj === null || typeof globalObj === undefined) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Global object '" + js_name + "' not found.");
    		}
    
    		return BINDING.js_to_mono_obj (globalObj);
    	}
  
    function _mono_wasm_get_object_property(js_handle, property_name, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var obj = BINDING.mono_wasm_require_handle (js_handle);
    		if (!obj) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		var js_name = BINDING.conv_string (property_name);
    		if (!js_name) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid property name object '" + js_name + "'");
    		}
    
    		var res;
    		try {
    			var m = obj [js_name];
    			if (m === Object(m) && obj.__is_mono_proxied__)
    				m.__is_mono_proxied__ = true;
    				
    			return BINDING.js_to_mono_obj (m);
    		} catch (e) {
    			var res = e.toString ();
    			setValue (is_exception, 1, "i32");
    			if (res === null || typeof res === "undefined")
    				res = "unknown exception";
    			return BINDING.js_string_to_mono_string (res);
    		}
    	}
  
    
    var DOTNET={_dotnet_get_global:function () {
    			function testGlobal(obj) {
    				obj['___dotnet_global___'] = obj;
    				var success = typeof ___dotnet_global___ === 'object' && obj['___dotnet_global___'] === obj;
    				if (!success) {
    					delete obj['___dotnet_global___'];
    				}
    				return success;
    			}
    			if (typeof ___dotnet_global___ === 'object') {
    				return ___dotnet_global___;
    			}
    			if (typeof global === 'object' && testGlobal(global)) {
    				___dotnet_global___ = global;
    			} else if (typeof window === 'object' && testGlobal(window)) {
    				___dotnet_global___ = window;
    			}
    			if (typeof ___dotnet_global___ === 'object') {
    				return ___dotnet_global___;
    			}
    			throw Error('unable to get DotNet global object.');
    		},conv_string:function (mono_obj) {
    			if (mono_obj == 0)
    				return null;
    
    			if (!this.mono_string_get_utf8)
    				this.mono_string_get_utf8 = Module.cwrap ('mono_wasm_string_get_utf8', 'number', ['number']);
    
    			var raw = this.mono_string_get_utf8 (mono_obj);
    			var res = Module.UTF8ToString (raw);
    			Module._free (raw);
    
    			return res;
    		}};function _mono_wasm_invoke_js_marshalled(exceptionMessage, asyncHandleLongPtr, functionName, argsJson) {
    
    		var mono_string = DOTNET._dotnet_get_global()._mono_string_cached
    			|| (DOTNET._dotnet_get_global()._mono_string_cached = Module.cwrap('mono_wasm_string_from_js', 'number', ['string']));
    	
    		try {
    			// Passing a .NET long into JS via Emscripten is tricky. The method here is to pass
    			// as pointer to the long, then combine two reads from the HEAPU32 array.
    			// Even though JS numbers can't represent the full range of a .NET long, it's OK
    			// because we'll never exceed Number.MAX_SAFE_INTEGER (2^53 - 1) in this case.
    			//var u32Index = $1 >> 2;
    			var u32Index = asyncHandleLongPtr >> 2;
    			var asyncHandleJsNumber = Module.HEAPU32[u32Index + 1]*4294967296 + Module.HEAPU32[u32Index];
    
    			// var funcNameJsString = UTF8ToString (functionName);
    			// var argsJsonJsString = argsJson && UTF8ToString (argsJson);
    			var funcNameJsString = DOTNET.conv_string(functionName);
    			var argsJsonJsString = argsJson && DOTNET.conv_string (argsJson);
    
    			var dotNetExports = DOTNET._dotnet_get_global().DotNet;
    			if (!dotNetExports) {
    				throw new Error('The Microsoft.JSInterop.js library is not loaded.');
    			}
    
    			if (asyncHandleJsNumber) {
    				dotNetExports.jsCallDispatcher.beginInvokeJSFromDotNet(asyncHandleJsNumber, funcNameJsString, argsJsonJsString);
    				return 0;
    			} else {
    				var resultJson = dotNetExports.jsCallDispatcher.invokeJSFromDotNet(funcNameJsString, argsJsonJsString);
    				return resultJson === null ? 0 : mono_string(resultJson);
    			}
    		} catch (ex) {
    			var exceptionJsString = ex.message + '\n' + ex.stack;
    			var exceptionSystemString = mono_string(exceptionJsString);
    			setValue (exceptionMessage, exceptionSystemString, 'i32'); // *exceptionMessage = exceptionSystemString;
    			return 0;
    		}
    	}
  
    function _mono_wasm_invoke_js_unmarshalled(exceptionMessage, funcName, arg0, arg1, arg2)	{
    		try {
    			// Get the function you're trying to invoke
    			var funcNameJsString = DOTNET.conv_string(funcName);
    			var dotNetExports = DOTNET._dotnet_get_global().DotNet;
    			if (!dotNetExports) {
    				throw new Error('The Microsoft.JSInterop.js library is not loaded.');
    			}
    			var funcInstance = dotNetExports.jsCallDispatcher.findJSFunction(funcNameJsString);
    
    			return funcInstance.call(null, arg0, arg1, arg2);
    		} catch (ex) {
    			var exceptionJsString = ex.message + '\n' + ex.stack;
    			var mono_string = Module.cwrap('mono_wasm_string_from_js', 'number', ['string']); // TODO: Cache
    			var exceptionSystemString = mono_string(exceptionJsString);
    			setValue (exceptionMessage, exceptionSystemString, 'i32'); // *exceptionMessage = exceptionSystemString;
    			return 0;
    		}
    	}
  
    function _mono_wasm_invoke_js_with_args(js_handle, method_name, args, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var obj = BINDING.get_js_obj (js_handle);
    		if (!obj) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		var js_name = BINDING.conv_string (method_name);
    		if (!js_name) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid method name object '" + method_name + "'");
    		}
    
    		var js_args = BINDING.mono_array_to_js_array(args);
    
    		var res;
    		try {
    			var m = obj [js_name];
    			if (typeof m === "undefined")
    				throw new Error("Method: '" + js_name + "' not found for: '" + Object.prototype.toString.call(obj) + "'");
    			var res = m.apply (obj, js_args);
    			return BINDING.js_to_mono_obj (res);
    		} catch (e) {
    			var res = e.toString ();
    			setValue (is_exception, 1, "i32");
    			if (res === null || res === undefined)
    				res = "unknown exception";
    			return BINDING.js_string_to_mono_string (res);
    		}
    	}
  
    function _mono_wasm_new(core_name, args, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var js_name = BINDING.conv_string (core_name);
    
    		if (!js_name) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Core object '" + js_name + "' not found.");
    		}
    
    		var coreObj = BINDING.mono_wasm_get_global()[js_name];
    
    		if (coreObj === null || typeof coreObj === undefined) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Global object '" + js_name + "' not found.");
    		}
    
    		var js_args = BINDING.mono_array_to_js_array(args);
    		
    		try {
    			
    			// This is all experimental !!!!!!
    			var allocator = function(constructor, js_args) {
    				// Not sure if we should be checking for anything here
    				var argsList = new Array();
    				argsList[0] = constructor;
    				if (js_args)
    					argsList = argsList.concat(js_args);
    				var obj = new (constructor.bind.apply(constructor, argsList ));
    				return obj;
    			};
    	
    			var res = allocator(coreObj, js_args);
    			var gc_handle = BINDING.mono_wasm_free_list.length ? BINDING.mono_wasm_free_list.pop() : BINDING.mono_wasm_ref_counter++;
    			BINDING.mono_wasm_object_registry[gc_handle] = res;
    			return BINDING.js_to_mono_obj (gc_handle + 1);
    		} catch (e) {
    			var res = e.toString ();
    			setValue (is_exception, 1, "i32");
    			if (res === null || res === undefined)
    				res = "Error allocating object.";
    			return BINDING.js_string_to_mono_string (res);
    		}	
    
    	}
  
    function _mono_wasm_new_object(object_handle_or_function, args, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		if (!object_handle_or_function) {
    			return BINDING.js_to_mono_obj ({});
    		}
    		else {
    
    			var requireObject;
    			if (typeof object_handle_or_function === 'function')
    				requireObject = object_handle_or_function;
    			else
    				requireObject = BINDING.mono_wasm_require_handle (object_handle_or_function);
    
    			if (!requireObject) {
    				setValue (is_exception, 1, "i32");
    				return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + object_handle_or_function + "'");
    			}
    
    			var js_args = BINDING.mono_array_to_js_array(args);
    			
    			try {
    				
    				// This is all experimental !!!!!!
    				var allocator = function(constructor, js_args) {
    					// Not sure if we should be checking for anything here
    					var argsList = new Array();
    					argsList[0] = constructor;
    					if (js_args)
    						argsList = argsList.concat(js_args);
    					var obj = new (constructor.bind.apply(constructor, argsList ));
    					return obj;
    				};
    		
    				var res = allocator(requireObject, js_args);
    				return BINDING.extract_mono_obj (res);
    			} catch (e) {
    				var res = e.toString ();
    				setValue (is_exception, 1, "i32");
    				if (res === null || res === undefined)
    					res = "Error allocating object.";
    				return BINDING.js_string_to_mono_string (res);
    			}	
    		}
    
    	}
  
    function _mono_wasm_release_handle(js_handle, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		BINDING.mono_wasm_free_handle(js_handle);
    	}
  
    function _mono_wasm_release_object(js_handle, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		BINDING.mono_wasm_free_raw_object(js_handle);
    	}
  
    function _mono_wasm_set_by_index(js_handle, property_index, value, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var obj = BINDING.mono_wasm_require_handle (js_handle);
    		if (!obj) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		var js_value = BINDING.unbox_mono_obj(value);
    
    		try {
    			obj [property_index] = js_value;
    			return true;
    		} catch (e) {
    			var res = e.toString ();
    			setValue (is_exception, 1, "i32");
    			if (res === null || typeof res === "undefined")
    				res = "unknown exception";
    			return BINDING.js_string_to_mono_string (res);
    		}
    	}
  
    function _mono_wasm_set_object_property(js_handle, property_name, value, createIfNotExist, hasOwnProperty, is_exception) {
    
    		BINDING.bindings_lazy_init ();
    
    		var requireObject = BINDING.mono_wasm_require_handle (js_handle);
    		if (!requireObject) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		var property = BINDING.conv_string (property_name);
    		if (!property) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid property name object '" + property_name + "'");
    		}
    
            var result = false;
    
    		var js_value = BINDING.unbox_mono_obj(value);
    
            if (createIfNotExist) {
                requireObject[property] = js_value;
                result = true;
            }
            else {
    			result = false;
    			if (!createIfNotExist)
    			{
    				if (!requireObject.hasOwnProperty(property))
    					return false;
    			}
                if (hasOwnProperty === true) {
                    if (requireObject.hasOwnProperty(property)) {
                        requireObject[property] = js_value;
                        result = true;
                    }
                }
                else {
                    requireObject[property] = js_value;
                    result = true;
                }
            
            }
            return BINDING.call_method (BINDING.box_js_bool, null, "im", [ result ]);
    	}
  
    function _mono_wasm_typed_array_copy_from(js_handle, pinned_array, begin, end, bytes_per_element, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var requireObject = BINDING.mono_wasm_require_handle (js_handle);
    		if (!requireObject) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		var res = BINDING.typedarray_copy_from(requireObject, pinned_array, begin, end, bytes_per_element);
    		return BINDING.js_to_mono_obj (res)
    	}
  
    function _mono_wasm_typed_array_copy_to(js_handle, pinned_array, begin, end, bytes_per_element, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var requireObject = BINDING.mono_wasm_require_handle (js_handle);
    		if (!requireObject) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		var res = BINDING.typedarray_copy_to(requireObject, pinned_array, begin, end, bytes_per_element);
    		return BINDING.js_to_mono_obj (res)
    	}
  
    function _mono_wasm_typed_array_from(pinned_array, begin, end, bytes_per_element, type, is_exception) {
    		BINDING.bindings_lazy_init ();
    		var res = BINDING.typed_array_from(pinned_array, begin, end, bytes_per_element, type);
    		return BINDING.js_to_mono_obj (res)
    	}
  
    function _mono_wasm_typed_array_to_array(js_handle, is_exception) {
    		BINDING.bindings_lazy_init ();
    
    		var requireObject = BINDING.mono_wasm_require_handle (js_handle);
    		if (!requireObject) {
    			setValue (is_exception, 1, "i32");
    			return BINDING.js_string_to_mono_string ("Invalid JS object handle '" + js_handle + "'");
    		}
    
    		return BINDING.js_typed_array_to_array(requireObject);
    	}
  
    
    function _usleep(useconds) {
        // int usleep(useconds_t useconds);
        // http://pubs.opengroup.org/onlinepubs/000095399/functions/usleep.html
        // We're single-threaded, so use a busy loop. Super-ugly.
        var msec = useconds / 1000;
        if ((ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && self['performance'] && self['performance']['now']) {
          var start = self['performance']['now']();
          while (self['performance']['now']() - start < msec) {
            // Do nothing.
          }
        } else {
          var start = Date.now();
          while (Date.now() - start < msec) {
            // Do nothing.
          }
        }
        return 0;
      }
    Module["_usleep"] = _usleep;function _nanosleep(rqtp, rmtp) {
        // int nanosleep(const struct timespec  *rqtp, struct timespec *rmtp);
        if (rqtp === 0) {
          ___setErrNo(22);
          return -1;
        }
        var seconds = HEAP32[((rqtp)>>2)];
        var nanoseconds = HEAP32[(((rqtp)+(4))>>2)];
        if (nanoseconds < 0 || nanoseconds > 999999999 || seconds < 0) {
          ___setErrNo(22);
          return -1;
        }
        if (rmtp !== 0) {
          HEAP32[((rmtp)>>2)]=0;
          HEAP32[(((rmtp)+(4))>>2)]=0;
        }
        return _usleep((seconds * 1e6) + (nanoseconds / 1000));
      }
  
    function _pthread_cleanup_pop() {
        assert(_pthread_cleanup_push.level == __ATEXIT__.length, 'cannot pop if something else added meanwhile!');
        __ATEXIT__.pop();
        _pthread_cleanup_push.level = __ATEXIT__.length;
      }
  
    function _pthread_cleanup_push(routine, arg) {
        __ATEXIT__.push(function() { dynCall_vi(routine, arg) })
        _pthread_cleanup_push.level = __ATEXIT__.length;
      }
  
    function _pthread_cond_broadcast(x) {
        x = x | 0;
        return 0;
      }
  
    function _pthread_cond_destroy() { return 0; }
  
    function _pthread_cond_init() { return 0; }
  
    function _pthread_cond_signal() { return 0; }
  
    function _pthread_cond_timedwait() { return 0; }
  
    function _pthread_cond_wait() { return 0; }
  
    function _pthread_mutexattr_destroy() {}
  
    function _pthread_mutexattr_init() {}
  
    function _pthread_mutexattr_setprotocol() {}
  
    function _pthread_mutexattr_settype() {}
  
    function _pthread_setcancelstate() { return 0; }
  
    
    
    function abortOnCannotGrowMemory(requestedSize) {
        abort('Cannot enlarge memory arrays to size ' + requestedSize + ' bytes (OOM). Either (1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value ' + HEAP8.length + ', (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 ');
      }
    
    function emscripten_realloc_buffer(size) {
        var PAGE_MULTIPLE = 65536;
        size = alignUp(size, PAGE_MULTIPLE); // round up to wasm page size
        var oldSize = buffer.byteLength;
        // native wasm support
        // note that this is *not* threadsafe. multiple threads can call .grow(), and each
        // presents a delta, so in theory we may over-allocate here (e.g. if two threads
        // ask to grow from 256MB to 512MB, we get 2 requests to add +256MB, and may end
        // up growing to 768MB (even though we may have been able to make do with 512MB).
        // TODO: consider decreasing the step sizes in emscripten_resize_heap
        try {
          var result = wasmMemory.grow((size - oldSize) / 65536); // .grow() takes a delta compared to the previous size
          if (result !== (-1 | 0)) {
            // success in native wasm memory growth, get the buffer from the memory
            buffer = wasmMemory.buffer;
            return true;
          } else {
            return false;
          }
        } catch(e) {
          console.error('emscripten_realloc_buffer: Attempted to grow from ' + oldSize  + ' bytes to ' + size + ' bytes, but got error: ' + e);
          return false;
        }
      }function _emscripten_resize_heap(requestedSize) {
        var oldSize = _emscripten_get_heap_size();
        // With pthreads, races can happen (another thread might increase the size in between), so return a failure, and let the caller retry.
        assert(requestedSize > oldSize);
    
    
        var PAGE_MULTIPLE = 65536;
        var LIMIT = 2147483648 - PAGE_MULTIPLE; // We can do one page short of 2GB as theoretical maximum.
    
        if (requestedSize > LIMIT) {
          err('Cannot enlarge memory, asked to go up to ' + requestedSize + ' bytes, but the limit is ' + LIMIT + ' bytes!');
          return false;
        }
    
        var MIN_TOTAL_MEMORY = 16777216;
        var newSize = Math.max(oldSize, MIN_TOTAL_MEMORY); // So the loop below will not be infinite, and minimum asm.js memory size is 16MB.
    
        // TODO: see realloc_buffer - for PTHREADS we may want to decrease these jumps
        while (newSize < requestedSize) { // Keep incrementing the heap size as long as it's less than what is requested.
          if (newSize <= 536870912) {
            newSize = alignUp(2 * newSize, PAGE_MULTIPLE); // Simple heuristic: double until 1GB...
          } else {
            // ..., but after that, add smaller increments towards 2GB, which we cannot reach
            newSize = Math.min(alignUp((3 * newSize + 2147483648) / 4, PAGE_MULTIPLE), LIMIT);
          }
    
          if (newSize === oldSize) {
            warnOnce('Cannot ask for more memory since we reached the practical limit in browsers (which is just below 2GB), so the request would have failed. Requesting only ' + HEAP8.length);
          }
        }
    
    
        var start = Date.now();
    
        if (!emscripten_realloc_buffer(newSize)) {
          err('Failed to grow the heap from ' + oldSize + ' bytes to ' + newSize + ' bytes, not enough memory!');
          return false;
        }
    
        updateGlobalBufferViews();
    
    
    
        return true;
      }function _sbrk(increment) {
        increment = increment|0;
        var oldDynamicTop = 0;
        var oldDynamicTopOnChange = 0;
        var newDynamicTop = 0;
        var totalMemory = 0;
        totalMemory = _emscripten_get_heap_size()|0;
    
          oldDynamicTop = HEAP32[DYNAMICTOP_PTR>>2]|0;
          newDynamicTop = oldDynamicTop + increment | 0;
    
          if (((increment|0) > 0 & (newDynamicTop|0) < (oldDynamicTop|0)) // Detect and fail if we would wrap around signed 32-bit int.
            | (newDynamicTop|0) < 0) { // Also underflow, sbrk() should be able to be used to subtract.
            abortOnCannotGrowMemory(newDynamicTop|0)|0;
            ___setErrNo(12);
            return -1;
          }
    
          if ((newDynamicTop|0) > (totalMemory|0)) {
            if (_emscripten_resize_heap(newDynamicTop|0)|0) {
              // We resized the heap. Start another loop iteration if we need to.
            } else {
              // We failed to resize the heap.
              ___setErrNo(12);
              return -1;
            }
          }
    
          HEAP32[DYNAMICTOP_PTR>>2] = newDynamicTop|0;
    
        return oldDynamicTop|0;
      }
  
    function _schedule_background_exec() {
    		++MONO.pump_count;
    		if (ENVIRONMENT_IS_WEB) {
    			window.setTimeout (MONO.pump_message, 0);
    		} else if (ENVIRONMENT_IS_WORKER) {
    			self.setTimeout (MONO.pump_message, 0);
    		}
    	}
  
    function _sem_destroy() {}
  
    function _sem_init() {}
  
    function _sem_post() {}
  
    function _sem_trywait() {}
  
    function _sem_wait() {}
  
    function _setTempRet0($i) {
        setTempRet0(($i) | 0);
      }
  
    function _setenv(envname, envval, overwrite) {
        // int setenv(const char *envname, const char *envval, int overwrite);
        // http://pubs.opengroup.org/onlinepubs/009695399/functions/setenv.html
        if (envname === 0) {
          ___setErrNo(22);
          return -1;
        }
        var name = UTF8ToString(envname);
        var val = UTF8ToString(envval);
        if (name === '' || name.indexOf('=') !== -1) {
          ___setErrNo(22);
          return -1;
        }
        if (ENV.hasOwnProperty(name) && !overwrite) return 0;
        ENV[name] = val;
        ___buildEnvironment(__get_environ());
        return 0;
      }
  
    function _sigaction(signum, act, oldact) {
        //int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
        err('Calling stub instead of sigaction()');
        return 0;
      }
  
    function _sigemptyset(set) {
        HEAP32[((set)>>2)]=0;
        return 0;
      }
  
    var _sqrt=Math_sqrt;
  
    var _sqrtf=Math_sqrt;
  
    
    function __isLeapYear(year) {
          return year%4 === 0 && (year%100 !== 0 || year%400 === 0);
      }
    
    function __arraySum(array, index) {
        var sum = 0;
        for (var i = 0; i <= index; sum += array[i++]);
        return sum;
      }
    
    
    var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];
    
    var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date, days) {
        var newDate = new Date(date.getTime());
        while(days > 0) {
          var leap = __isLeapYear(newDate.getFullYear());
          var currentMonth = newDate.getMonth();
          var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth];
    
          if (days > daysInCurrentMonth-newDate.getDate()) {
            // we spill over to next month
            days -= (daysInCurrentMonth-newDate.getDate()+1);
            newDate.setDate(1);
            if (currentMonth < 11) {
              newDate.setMonth(currentMonth+1)
            } else {
              newDate.setMonth(0);
              newDate.setFullYear(newDate.getFullYear()+1);
            }
          } else {
            // we stay in current month
            newDate.setDate(newDate.getDate()+days);
            return newDate;
          }
        }
    
        return newDate;
      }function _strftime(s, maxsize, format, tm) {
        // size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
        // http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html
    
        var tm_zone = HEAP32[(((tm)+(40))>>2)];
    
        var date = {
          tm_sec: HEAP32[((tm)>>2)],
          tm_min: HEAP32[(((tm)+(4))>>2)],
          tm_hour: HEAP32[(((tm)+(8))>>2)],
          tm_mday: HEAP32[(((tm)+(12))>>2)],
          tm_mon: HEAP32[(((tm)+(16))>>2)],
          tm_year: HEAP32[(((tm)+(20))>>2)],
          tm_wday: HEAP32[(((tm)+(24))>>2)],
          tm_yday: HEAP32[(((tm)+(28))>>2)],
          tm_isdst: HEAP32[(((tm)+(32))>>2)],
          tm_gmtoff: HEAP32[(((tm)+(36))>>2)],
          tm_zone: tm_zone ? UTF8ToString(tm_zone) : ''
        };
    
        var pattern = UTF8ToString(format);
    
        // expand format
        var EXPANSION_RULES_1 = {
          '%c': '%a %b %d %H:%M:%S %Y',     // Replaced by the locale's appropriate date and time representation - e.g., Mon Aug  3 14:02:01 2013
          '%D': '%m/%d/%y',                 // Equivalent to %m / %d / %y
          '%F': '%Y-%m-%d',                 // Equivalent to %Y - %m - %d
          '%h': '%b',                       // Equivalent to %b
          '%r': '%I:%M:%S %p',              // Replaced by the time in a.m. and p.m. notation
          '%R': '%H:%M',                    // Replaced by the time in 24-hour notation
          '%T': '%H:%M:%S',                 // Replaced by the time
          '%x': '%m/%d/%y',                 // Replaced by the locale's appropriate date representation
          '%X': '%H:%M:%S',                 // Replaced by the locale's appropriate time representation
          // Modified Conversion Specifiers
          '%Ec': '%c',                      // Replaced by the locale's alternative appropriate date and time representation.
          '%EC': '%C',                      // Replaced by the name of the base year (period) in the locale's alternative representation.
          '%Ex': '%m/%d/%y',                // Replaced by the locale's alternative date representation.
          '%EX': '%H:%M:%S',                // Replaced by the locale's alternative time representation.
          '%Ey': '%y',                      // Replaced by the offset from %EC (year only) in the locale's alternative representation.
          '%EY': '%Y',                      // Replaced by the full alternative year representation.
          '%Od': '%d',                      // Replaced by the day of the month, using the locale's alternative numeric symbols, filled as needed with leading zeros if there is any alternative symbol for zero; otherwise, with leading <space> characters.
          '%Oe': '%e',                      // Replaced by the day of the month, using the locale's alternative numeric symbols, filled as needed with leading <space> characters.
          '%OH': '%H',                      // Replaced by the hour (24-hour clock) using the locale's alternative numeric symbols.
          '%OI': '%I',                      // Replaced by the hour (12-hour clock) using the locale's alternative numeric symbols.
          '%Om': '%m',                      // Replaced by the month using the locale's alternative numeric symbols.
          '%OM': '%M',                      // Replaced by the minutes using the locale's alternative numeric symbols.
          '%OS': '%S',                      // Replaced by the seconds using the locale's alternative numeric symbols.
          '%Ou': '%u',                      // Replaced by the weekday as a number in the locale's alternative representation (Monday=1).
          '%OU': '%U',                      // Replaced by the week number of the year (Sunday as the first day of the week, rules corresponding to %U ) using the locale's alternative numeric symbols.
          '%OV': '%V',                      // Replaced by the week number of the year (Monday as the first day of the week, rules corresponding to %V ) using the locale's alternative numeric symbols.
          '%Ow': '%w',                      // Replaced by the number of the weekday (Sunday=0) using the locale's alternative numeric symbols.
          '%OW': '%W',                      // Replaced by the week number of the year (Monday as the first day of the week) using the locale's alternative numeric symbols.
          '%Oy': '%y',                      // Replaced by the year (offset from %C ) using the locale's alternative numeric symbols.
        };
        for (var rule in EXPANSION_RULES_1) {
          pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_1[rule]);
        }
    
        var WEEKDAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
        var MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    
        function leadingSomething(value, digits, character) {
          var str = typeof value === 'number' ? value.toString() : (value || '');
          while (str.length < digits) {
            str = character[0]+str;
          }
          return str;
        };
    
        function leadingNulls(value, digits) {
          return leadingSomething(value, digits, '0');
        };
    
        function compareByDay(date1, date2) {
          function sgn(value) {
            return value < 0 ? -1 : (value > 0 ? 1 : 0);
          };
    
          var compare;
          if ((compare = sgn(date1.getFullYear()-date2.getFullYear())) === 0) {
            if ((compare = sgn(date1.getMonth()-date2.getMonth())) === 0) {
              compare = sgn(date1.getDate()-date2.getDate());
            }
          }
          return compare;
        };
    
        function getFirstWeekStartDate(janFourth) {
            switch (janFourth.getDay()) {
              case 0: // Sunday
                return new Date(janFourth.getFullYear()-1, 11, 29);
              case 1: // Monday
                return janFourth;
              case 2: // Tuesday
                return new Date(janFourth.getFullYear(), 0, 3);
              case 3: // Wednesday
                return new Date(janFourth.getFullYear(), 0, 2);
              case 4: // Thursday
                return new Date(janFourth.getFullYear(), 0, 1);
              case 5: // Friday
                return new Date(janFourth.getFullYear()-1, 11, 31);
              case 6: // Saturday
                return new Date(janFourth.getFullYear()-1, 11, 30);
            }
        };
    
        function getWeekBasedYear(date) {
            var thisDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
    
            var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4);
            var janFourthNextYear = new Date(thisDate.getFullYear()+1, 0, 4);
    
            var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
            var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
    
            if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {
              // this date is after the start of the first week of this year
              if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {
                return thisDate.getFullYear()+1;
              } else {
                return thisDate.getFullYear();
              }
            } else {
              return thisDate.getFullYear()-1;
            }
        };
    
        var EXPANSION_RULES_2 = {
          '%a': function(date) {
            return WEEKDAYS[date.tm_wday].substring(0,3);
          },
          '%A': function(date) {
            return WEEKDAYS[date.tm_wday];
          },
          '%b': function(date) {
            return MONTHS[date.tm_mon].substring(0,3);
          },
          '%B': function(date) {
            return MONTHS[date.tm_mon];
          },
          '%C': function(date) {
            var year = date.tm_year+1900;
            return leadingNulls((year/100)|0,2);
          },
          '%d': function(date) {
            return leadingNulls(date.tm_mday, 2);
          },
          '%e': function(date) {
            return leadingSomething(date.tm_mday, 2, ' ');
          },
          '%g': function(date) {
            // %g, %G, and %V give values according to the ISO 8601:2000 standard week-based year.
            // In this system, weeks begin on a Monday and week 1 of the year is the week that includes
            // January 4th, which is also the week that includes the first Thursday of the year, and
            // is also the first week that contains at least four days in the year.
            // If the first Monday of January is the 2nd, 3rd, or 4th, the preceding days are part of
            // the last week of the preceding year; thus, for Saturday 2nd January 1999,
            // %G is replaced by 1998 and %V is replaced by 53. If December 29th, 30th,
            // or 31st is a Monday, it and any following days are part of week 1 of the following year.
            // Thus, for Tuesday 30th December 1997, %G is replaced by 1998 and %V is replaced by 01.
    
            return getWeekBasedYear(date).toString().substring(2);
          },
          '%G': function(date) {
            return getWeekBasedYear(date);
          },
          '%H': function(date) {
            return leadingNulls(date.tm_hour, 2);
          },
          '%I': function(date) {
            var twelveHour = date.tm_hour;
            if (twelveHour == 0) twelveHour = 12;
            else if (twelveHour > 12) twelveHour -= 12;
            return leadingNulls(twelveHour, 2);
          },
          '%j': function(date) {
            // Day of the year (001-366)
            return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date.tm_mon-1), 3);
          },
          '%m': function(date) {
            return leadingNulls(date.tm_mon+1, 2);
          },
          '%M': function(date) {
            return leadingNulls(date.tm_min, 2);
          },
          '%n': function() {
            return '\n';
          },
          '%p': function(date) {
            if (date.tm_hour >= 0 && date.tm_hour < 12) {
              return 'AM';
            } else {
              return 'PM';
            }
          },
          '%S': function(date) {
            return leadingNulls(date.tm_sec, 2);
          },
          '%t': function() {
            return '\t';
          },
          '%u': function(date) {
            return date.tm_wday || 7;
          },
          '%U': function(date) {
            // Replaced by the week number of the year as a decimal number [00,53].
            // The first Sunday of January is the first day of week 1;
            // days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
            var janFirst = new Date(date.tm_year+1900, 0, 1);
            var firstSunday = janFirst.getDay() === 0 ? janFirst : __addDays(janFirst, 7-janFirst.getDay());
            var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
    
            // is target date after the first Sunday?
            if (compareByDay(firstSunday, endDate) < 0) {
              // calculate difference in days between first Sunday and endDate
              var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
              var firstSundayUntilEndJanuary = 31-firstSunday.getDate();
              var days = firstSundayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
              return leadingNulls(Math.ceil(days/7), 2);
            }
    
            return compareByDay(firstSunday, janFirst) === 0 ? '01': '00';
          },
          '%V': function(date) {
            // Replaced by the week number of the year (Monday as the first day of the week)
            // as a decimal number [01,53]. If the week containing 1 January has four
            // or more days in the new year, then it is considered week 1.
            // Otherwise, it is the last week of the previous year, and the next week is week 1.
            // Both January 4th and the first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
            var janFourthThisYear = new Date(date.tm_year+1900, 0, 4);
            var janFourthNextYear = new Date(date.tm_year+1901, 0, 4);
    
            var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear);
            var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear);
    
            var endDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday);
    
            if (compareByDay(endDate, firstWeekStartThisYear) < 0) {
              // if given date is before this years first week, then it belongs to the 53rd week of last year
              return '53';
            }
    
            if (compareByDay(firstWeekStartNextYear, endDate) <= 0) {
              // if given date is after next years first week, then it belongs to the 01th week of next year
              return '01';
            }
    
            // given date is in between CW 01..53 of this calendar year
            var daysDifference;
            if (firstWeekStartThisYear.getFullYear() < date.tm_year+1900) {
              // first CW of this year starts last year
              daysDifference = date.tm_yday+32-firstWeekStartThisYear.getDate()
            } else {
              // first CW of this year starts this year
              daysDifference = date.tm_yday+1-firstWeekStartThisYear.getDate();
            }
            return leadingNulls(Math.ceil(daysDifference/7), 2);
          },
          '%w': function(date) {
            return date.tm_wday;
          },
          '%W': function(date) {
            // Replaced by the week number of the year as a decimal number [00,53].
            // The first Monday of January is the first day of week 1;
            // days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
            var janFirst = new Date(date.tm_year, 0, 1);
            var firstMonday = janFirst.getDay() === 1 ? janFirst : __addDays(janFirst, janFirst.getDay() === 0 ? 1 : 7-janFirst.getDay()+1);
            var endDate = new Date(date.tm_year+1900, date.tm_mon, date.tm_mday);
    
            // is target date after the first Monday?
            if (compareByDay(firstMonday, endDate) < 0) {
              var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth()-1)-31;
              var firstMondayUntilEndJanuary = 31-firstMonday.getDate();
              var days = firstMondayUntilEndJanuary+februaryFirstUntilEndMonth+endDate.getDate();
              return leadingNulls(Math.ceil(days/7), 2);
            }
            return compareByDay(firstMonday, janFirst) === 0 ? '01': '00';
          },
          '%y': function(date) {
            // Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year]
            return (date.tm_year+1900).toString().substring(2);
          },
          '%Y': function(date) {
            // Replaced by the year as a decimal number (for example, 1997). [ tm_year]
            return date.tm_year+1900;
          },
          '%z': function(date) {
            // Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ).
            // For example, "-0430" means 4 hours 30 minutes behind UTC (west of Greenwich).
            var off = date.tm_gmtoff;
            var ahead = off >= 0;
            off = Math.abs(off) / 60;
            // convert from minutes into hhmm format (which means 60 minutes = 100 units)
            off = (off / 60)*100 + (off % 60);
            return (ahead ? '+' : '-') + String("0000" + off).slice(-4);
          },
          '%Z': function(date) {
            return date.tm_zone;
          },
          '%%': function() {
            return '%';
          }
        };
        for (var rule in EXPANSION_RULES_2) {
          if (pattern.indexOf(rule) >= 0) {
            pattern = pattern.replace(new RegExp(rule, 'g'), EXPANSION_RULES_2[rule](date));
          }
        }
    
        var bytes = intArrayFromString(pattern, false);
        if (bytes.length > maxsize) {
          return 0;
        }
    
        writeArrayToMemory(bytes, s);
        return bytes.length-1;
      }
  
    function _sysconf(name) {
        // long sysconf(int name);
        // http://pubs.opengroup.org/onlinepubs/009695399/functions/sysconf.html
        switch(name) {
          case 30: return PAGE_SIZE;
          case 85:
            var maxHeapSize = 2*1024*1024*1024 - 65536;
            return maxHeapSize / PAGE_SIZE;
          case 132:
          case 133:
          case 12:
          case 137:
          case 138:
          case 15:
          case 235:
          case 16:
          case 17:
          case 18:
          case 19:
          case 20:
          case 149:
          case 13:
          case 10:
          case 236:
          case 153:
          case 9:
          case 21:
          case 22:
          case 159:
          case 154:
          case 14:
          case 77:
          case 78:
          case 139:
          case 80:
          case 81:
          case 82:
          case 68:
          case 67:
          case 164:
          case 11:
          case 29:
          case 47:
          case 48:
          case 95:
          case 52:
          case 51:
          case 46:
            return 200809;
          case 79:
            return 0;
          case 27:
          case 246:
          case 127:
          case 128:
          case 23:
          case 24:
          case 160:
          case 161:
          case 181:
          case 182:
          case 242:
          case 183:
          case 184:
          case 243:
          case 244:
          case 245:
          case 165:
          case 178:
          case 179:
          case 49:
          case 50:
          case 168:
          case 169:
          case 175:
          case 170:
          case 171:
          case 172:
          case 97:
          case 76:
          case 32:
          case 173:
          case 35:
            return -1;
          case 176:
          case 177:
          case 7:
          case 155:
          case 8:
          case 157:
          case 125:
          case 126:
          case 92:
          case 93:
          case 129:
          case 130:
          case 131:
          case 94:
          case 91:
            return 1;
          case 74:
          case 60:
          case 69:
          case 70:
          case 4:
            return 1024;
          case 31:
          case 42:
          case 72:
            return 32;
          case 87:
          case 26:
          case 33:
            return 2147483647;
          case 34:
          case 1:
            return 47839;
          case 38:
          case 36:
            return 99;
          case 43:
          case 37:
            return 2048;
          case 0: return 2097152;
          case 3: return 65536;
          case 28: return 32768;
          case 44: return 32767;
          case 75: return 16384;
          case 39: return 1000;
          case 89: return 700;
          case 71: return 256;
          case 40: return 255;
          case 2: return 100;
          case 180: return 64;
          case 25: return 20;
          case 5: return 16;
          case 6: return 6;
          case 73: return 4;
          case 84: {
            if (typeof navigator === 'object') return navigator['hardwareConcurrency'] || 1;
            return 1;
          }
        }
        ___setErrNo(22);
        return -1;
      }
  
    function _time(ptr) {
        var ret = (Date.now()/1000)|0;
        if (ptr) {
          HEAP32[((ptr)>>2)]=ret;
        }
        return ret;
      }
  
    function _unsetenv(name) {
        // int unsetenv(const char *name);
        // http://pubs.opengroup.org/onlinepubs/009695399/functions/unsetenv.html
        if (name === 0) {
          ___setErrNo(22);
          return -1;
        }
        name = UTF8ToString(name);
        if (name === '' || name.indexOf('=') !== -1) {
          ___setErrNo(22);
          return -1;
        }
        if (ENV.hasOwnProperty(name)) {
          delete ENV[name];
          ___buildEnvironment(__get_environ());
        }
        return 0;
      }
  
    function _utime(path, times) {
        // int utime(const char *path, const struct utimbuf *times);
        // http://pubs.opengroup.org/onlinepubs/009695399/basedefs/utime.h.html
        var time;
        if (times) {
          // NOTE: We don't keep track of access timestamps.
          var offset = 4;
          time = HEAP32[(((times)+(offset))>>2)];
          time *= 1000;
        } else {
          time = Date.now();
        }
        path = UTF8ToString(path);
        try {
          FS.utime(path, time, time);
          return 0;
        } catch (e) {
          FS.handleFSError(e);
          return -1;
        }
      }
  
    function _utimes(path, times) {
        var time;
        if (times) {
          var offset = 8 + 0;
          time = HEAP32[(((times)+(offset))>>2)] * 1000;
          offset = 8 + 4;
          time += HEAP32[(((times)+(offset))>>2)] / 1000;
        } else {
          time = Date.now();
        }
        path = UTF8ToString(path);
        try {
          FS.utime(path, time, time);
          return 0;
        } catch (e) {
          FS.handleFSError(e);
          return -1;
        }
      }
  
    
    function _wait(stat_loc) {
        // pid_t wait(int *stat_loc);
        // http://pubs.opengroup.org/onlinepubs/009695399/functions/wait.html
        // Makes no sense in a single-process environment.
        ___setErrNo(10);
        return -1;
      }function _waitpid() {
    return _wait.apply(null, arguments)
    }
  if (ENVIRONMENT_IS_NODE) {
      _emscripten_get_now = function _emscripten_get_now_actual() {
        var t = process['hrtime']();
        return t[0] * 1e3 + t[1] / 1e6;
      };
    } else if (typeof dateNow !== 'undefined') {
      _emscripten_get_now = dateNow;
    } else if (typeof performance === 'object' && performance && typeof performance['now'] === 'function') {
      _emscripten_get_now = function() { return performance['now'](); };
    } else {
      _emscripten_get_now = Date.now;
    };
  FS.staticInit();Module["FS_createPath"] = FS.createPath;Module["FS_createDataFile"] = FS.createDataFile;;
  if (ENVIRONMENT_HAS_NODE) { var fs = require("fs"); var NODEJS_PATH = require("path"); NODEFS.staticInit(); };
  Module["pump_message"] = MONO.pump_message;
  BINDING.export_functions (Module);;
  var ASSERTIONS = true;
  
  // Copyright 2017 The Emscripten Authors.  All rights reserved.
  // Emscripten is available under two separate licenses, the MIT license and the
  // University of Illinois/NCSA Open Source License.  Both these licenses can be
  // found in the LICENSE file.
  
  /** @type {function(string, boolean=, number=)} */
  function intArrayFromString(stringy, dontAddNull, length) {
    var len = length > 0 ? length : lengthBytesUTF8(stringy)+1;
    var u8array = new Array(len);
    var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length);
    if (dontAddNull) u8array.length = numBytesWritten;
    return u8array;
  }
  
  function intArrayToString(array) {
    var ret = [];
    for (var i = 0; i < array.length; i++) {
      var chr = array[i];
      if (chr > 0xFF) {
        if (ASSERTIONS) {
          assert(false, 'Character code ' + chr + ' (' + String.fromCharCode(chr) + ')  at offset ' + i + ' not in 0x00-0xFF.');
        }
        chr &= 0xFF;
      }
      ret.push(String.fromCharCode(chr));
    }
    return ret.join('');
  }
  
  
  // ASM_LIBRARY EXTERN PRIMITIVES: Int8Array,Int32Array
  
  var asmGlobalArg = {};
  var asmLibraryArg = { "DYNAMICTOP_PTR": DYNAMICTOP_PTR, "__assert_fail": ___assert_fail, "__buildEnvironment": ___buildEnvironment, "__clock_gettime": ___clock_gettime, "__cxa_allocate_exception": ___cxa_allocate_exception, "__cxa_begin_catch": ___cxa_begin_catch, "__cxa_end_catch": ___cxa_end_catch, "__cxa_find_matching_catch": ___cxa_find_matching_catch, "__cxa_find_matching_catch_3": ___cxa_find_matching_catch_3, "__cxa_free_exception": ___cxa_free_exception, "__cxa_throw": ___cxa_throw, "__cxa_uncaught_exception": ___cxa_uncaught_exception, "__exception_addRef": ___exception_addRef, "__exception_deAdjust": ___exception_deAdjust, "__exception_decRef": ___exception_decRef, "__lock": ___lock, "__map_file": ___map_file, "__resumeException": ___resumeException, "__setErrNo": ___setErrNo, "__syscall10": ___syscall10, "__syscall102": ___syscall102, "__syscall118": ___syscall118, "__syscall12": ___syscall12, "__syscall122": ___syscall122, "__syscall140": ___syscall140, "__syscall142": ___syscall142, "__syscall144": ___syscall144, "__syscall145": ___syscall145, "__syscall146": ___syscall146, "__syscall15": ___syscall15, "__syscall168": ___syscall168, "__syscall183": ___syscall183, "__syscall192": ___syscall192, "__syscall194": ___syscall194, "__syscall195": ___syscall195, "__syscall196": ___syscall196, "__syscall197": ___syscall197, "__syscall199": ___syscall199, "__syscall20": ___syscall20, "__syscall201": ___syscall201, "__syscall202": ___syscall202, "__syscall209": ___syscall209, "__syscall211": ___syscall211, "__syscall220": ___syscall220, "__syscall221": ___syscall221, "__syscall268": ___syscall268, "__syscall272": ___syscall272, "__syscall3": ___syscall3, "__syscall320": ___syscall320, "__syscall33": ___syscall33, "__syscall38": ___syscall38, "__syscall39": ___syscall39, "__syscall4": ___syscall4, "__syscall40": ___syscall40, "__syscall41": ___syscall41, "__syscall42": ___syscall42, "__syscall5": ___syscall5, "__syscall54": ___syscall54, "__syscall6": ___syscall6, "__syscall63": ___syscall63, "__syscall77": ___syscall77, "__syscall85": ___syscall85, "__syscall9": ___syscall9, "__syscall91": ___syscall91, "__syscall94": ___syscall94, "__syscall96": ___syscall96, "__syscall97": ___syscall97, "__unlock": ___unlock, "_addDays": __addDays, "_arraySum": __arraySum, "_emscripten_syscall_mmap2": __emscripten_syscall_mmap2, "_emscripten_syscall_munmap": __emscripten_syscall_munmap, "_exit": __exit, "_inet_ntop4_raw": __inet_ntop4_raw, "_inet_ntop6_raw": __inet_ntop6_raw, "_inet_pton4_raw": __inet_pton4_raw, "_inet_pton6_raw": __inet_pton6_raw, "_isLeapYear": __isLeapYear, "_read_sockaddr": __read_sockaddr, "_write_sockaddr": __write_sockaddr, "abort": _abort, "abortOnCannotGrowMemory": abortOnCannotGrowMemory, "atexit": _atexit, "clock_getres": _clock_getres, "clock_gettime": _clock_gettime, "emscripten_asm_const_iii": _emscripten_asm_const_iii, "emscripten_get_heap_size": _emscripten_get_heap_size, "emscripten_get_now": _emscripten_get_now, "emscripten_get_now_is_monotonic": _emscripten_get_now_is_monotonic, "emscripten_get_now_res": _emscripten_get_now_res, "emscripten_memcpy_big": _emscripten_memcpy_big, "emscripten_realloc_buffer": emscripten_realloc_buffer, "emscripten_resize_heap": _emscripten_resize_heap, "execl": _execl, "execve": _execve, "exit": _exit, "fabs": _fabs, "fabsf": _fabsf, "floor": _floor, "fork": _fork, "getTempRet0": _getTempRet0, "getaddrinfo": _getaddrinfo, "getenv": _getenv, "getnameinfo": _getnameinfo, "getprotobyname": _getprotobyname, "getpwuid": _getpwuid, "gettimeofday": _gettimeofday, "gmtime_r": _gmtime_r, "invoke_vi": invoke_vi, "kill": _kill, "llvm_eh_typeid_for": _llvm_eh_typeid_for, "localtime_r": _localtime_r, "memcpy": _memcpy, "memset": _memset, "mono_set_timeout": _mono_set_timeout, "mono_wasm_add_array_item": _mono_wasm_add_array_item, "mono_wasm_add_array_var": _mono_wasm_add_array_var, "mono_wasm_add_bool_var": _mono_wasm_add_bool_var, "mono_wasm_add_frame": _mono_wasm_add_frame, "mono_wasm_add_number_var": _mono_wasm_add_number_var, "mono_wasm_add_obj_var": _mono_wasm_add_obj_var, "mono_wasm_add_properties_var": _mono_wasm_add_properties_var, "mono_wasm_add_string_var": _mono_wasm_add_string_var, "mono_wasm_bind_core_object": _mono_wasm_bind_core_object, "mono_wasm_bind_host_object": _mono_wasm_bind_host_object, "mono_wasm_fire_bp": _mono_wasm_fire_bp, "mono_wasm_get_by_index": _mono_wasm_get_by_index, "mono_wasm_get_global_object": _mono_wasm_get_global_object, "mono_wasm_get_object_property": _mono_wasm_get_object_property, "mono_wasm_invoke_js_marshalled": _mono_wasm_invoke_js_marshalled, "mono_wasm_invoke_js_unmarshalled": _mono_wasm_invoke_js_unmarshalled, "mono_wasm_invoke_js_with_args": _mono_wasm_invoke_js_with_args, "mono_wasm_new": _mono_wasm_new, "mono_wasm_new_object": _mono_wasm_new_object, "mono_wasm_release_handle": _mono_wasm_release_handle, "mono_wasm_release_object": _mono_wasm_release_object, "mono_wasm_set_by_index": _mono_wasm_set_by_index, "mono_wasm_set_object_property": _mono_wasm_set_object_property, "mono_wasm_typed_array_copy_from": _mono_wasm_typed_array_copy_from, "mono_wasm_typed_array_copy_to": _mono_wasm_typed_array_copy_to, "mono_wasm_typed_array_from": _mono_wasm_typed_array_from, "mono_wasm_typed_array_to_array": _mono_wasm_typed_array_to_array, "nanosleep": _nanosleep, "pthread_cleanup_pop": _pthread_cleanup_pop, "pthread_cleanup_push": _pthread_cleanup_push, "pthread_cond_broadcast": _pthread_cond_broadcast, "pthread_cond_destroy": _pthread_cond_destroy, "pthread_cond_init": _pthread_cond_init, "pthread_cond_signal": _pthread_cond_signal, "pthread_cond_timedwait": _pthread_cond_timedwait, "pthread_cond_wait": _pthread_cond_wait, "pthread_mutexattr_destroy": _pthread_mutexattr_destroy, "pthread_mutexattr_init": _pthread_mutexattr_init, "pthread_mutexattr_setprotocol": _pthread_mutexattr_setprotocol, "pthread_mutexattr_settype": _pthread_mutexattr_settype, "pthread_setcancelstate": _pthread_setcancelstate, "sbrk": _sbrk, "schedule_background_exec": _schedule_background_exec, "sem_destroy": _sem_destroy, "sem_init": _sem_init, "sem_post": _sem_post, "sem_trywait": _sem_trywait, "sem_wait": _sem_wait, "setTempRet0": _setTempRet0, "setenv": _setenv, "setprotoent": _setprotoent, "sigaction": _sigaction, "sigemptyset": _sigemptyset, "sqrt": _sqrt, "sqrtf": _sqrtf, "strftime": _strftime, "sysconf": _sysconf, "time": _time, "tzset": _tzset, "unsetenv": _unsetenv, "usleep": _usleep, "utime": _utime, "utimes": _utimes, "wait": _wait, "waitpid": _waitpid };
  var asm = Module['asm'](asmGlobalArg, asmLibraryArg, buffer);
  var real____wasm_call_ctors = asm["__wasm_call_ctors"];
  asm["__wasm_call_ctors"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real____wasm_call_ctors.apply(null, arguments);
  };
  
  var real__mono_wasm_add_assembly = asm["mono_wasm_add_assembly"];
  asm["mono_wasm_add_assembly"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_add_assembly.apply(null, arguments);
  };
  
  var real__malloc = asm["malloc"];
  asm["malloc"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__malloc.apply(null, arguments);
  };
  
  var real__mono_wasm_setenv = asm["mono_wasm_setenv"];
  asm["mono_wasm_setenv"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_setenv.apply(null, arguments);
  };
  
  var real__free = asm["free"];
  asm["free"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__free.apply(null, arguments);
  };
  
  var real__mono_wasm_load_runtime = asm["mono_wasm_load_runtime"];
  asm["mono_wasm_load_runtime"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_load_runtime.apply(null, arguments);
  };
  
  var real__mono_wasm_assembly_load = asm["mono_wasm_assembly_load"];
  asm["mono_wasm_assembly_load"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_assembly_load.apply(null, arguments);
  };
  
  var real__mono_wasm_assembly_find_class = asm["mono_wasm_assembly_find_class"];
  asm["mono_wasm_assembly_find_class"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_assembly_find_class.apply(null, arguments);
  };
  
  var real__mono_wasm_assembly_find_method = asm["mono_wasm_assembly_find_method"];
  asm["mono_wasm_assembly_find_method"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_assembly_find_method.apply(null, arguments);
  };
  
  var real__mono_wasm_invoke_method = asm["mono_wasm_invoke_method"];
  asm["mono_wasm_invoke_method"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_invoke_method.apply(null, arguments);
  };
  
  var real__mono_wasm_assembly_get_entry_point = asm["mono_wasm_assembly_get_entry_point"];
  asm["mono_wasm_assembly_get_entry_point"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_assembly_get_entry_point.apply(null, arguments);
  };
  
  var real__mono_wasm_string_get_utf8 = asm["mono_wasm_string_get_utf8"];
  asm["mono_wasm_string_get_utf8"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_string_get_utf8.apply(null, arguments);
  };
  
  var real__mono_wasm_string_from_js = asm["mono_wasm_string_from_js"];
  asm["mono_wasm_string_from_js"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_string_from_js.apply(null, arguments);
  };
  
  var real__mono_wasm_get_obj_type = asm["mono_wasm_get_obj_type"];
  asm["mono_wasm_get_obj_type"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_get_obj_type.apply(null, arguments);
  };
  
  var real__mono_unbox_int = asm["mono_unbox_int"];
  asm["mono_unbox_int"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_unbox_int.apply(null, arguments);
  };
  
  var real__mono_wasm_unbox_float = asm["mono_wasm_unbox_float"];
  asm["mono_wasm_unbox_float"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_unbox_float.apply(null, arguments);
  };
  
  var real__mono_wasm_array_length = asm["mono_wasm_array_length"];
  asm["mono_wasm_array_length"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_array_length.apply(null, arguments);
  };
  
  var real__mono_wasm_array_get = asm["mono_wasm_array_get"];
  asm["mono_wasm_array_get"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_array_get.apply(null, arguments);
  };
  
  var real__mono_wasm_obj_array_new = asm["mono_wasm_obj_array_new"];
  asm["mono_wasm_obj_array_new"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_obj_array_new.apply(null, arguments);
  };
  
  var real__mono_wasm_obj_array_set = asm["mono_wasm_obj_array_set"];
  asm["mono_wasm_obj_array_set"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_obj_array_set.apply(null, arguments);
  };
  
  var real__mono_wasm_string_array_new = asm["mono_wasm_string_array_new"];
  asm["mono_wasm_string_array_new"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_string_array_new.apply(null, arguments);
  };
  
  var real__mono_wasm_exec_regression = asm["mono_wasm_exec_regression"];
  asm["mono_wasm_exec_regression"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_exec_regression.apply(null, arguments);
  };
  
  var real__mono_wasm_exit = asm["mono_wasm_exit"];
  asm["mono_wasm_exit"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_exit.apply(null, arguments);
  };
  
  var real__mono_wasm_set_main_args = asm["mono_wasm_set_main_args"];
  asm["mono_wasm_set_main_args"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_set_main_args.apply(null, arguments);
  };
  
  var real__mono_wasm_strdup = asm["mono_wasm_strdup"];
  asm["mono_wasm_strdup"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_strdup.apply(null, arguments);
  };
  
  var real__mono_wasm_parse_runtime_options = asm["mono_wasm_parse_runtime_options"];
  asm["mono_wasm_parse_runtime_options"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_parse_runtime_options.apply(null, arguments);
  };
  
  var real__mono_wasm_enable_on_demand_gc = asm["mono_wasm_enable_on_demand_gc"];
  asm["mono_wasm_enable_on_demand_gc"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_enable_on_demand_gc.apply(null, arguments);
  };
  
  var real__mono_wasm_typed_array_new = asm["mono_wasm_typed_array_new"];
  asm["mono_wasm_typed_array_new"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_typed_array_new.apply(null, arguments);
  };
  
  var real__mono_wasm_unbox_enum = asm["mono_wasm_unbox_enum"];
  asm["mono_wasm_unbox_enum"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_unbox_enum.apply(null, arguments);
  };
  
  var real____errno_location = asm["__errno_location"];
  asm["__errno_location"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real____errno_location.apply(null, arguments);
  };
  
  var real__fflush = asm["fflush"];
  asm["fflush"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__fflush.apply(null, arguments);
  };
  
  var real__mono_print_method_from_ip = asm["mono_print_method_from_ip"];
  asm["mono_print_method_from_ip"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_print_method_from_ip.apply(null, arguments);
  };
  
  var real__putchar = asm["putchar"];
  asm["putchar"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__putchar.apply(null, arguments);
  };
  
  var real__mono_wasm_setup_single_step = asm["mono_wasm_setup_single_step"];
  asm["mono_wasm_setup_single_step"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_setup_single_step.apply(null, arguments);
  };
  
  var real__mono_wasm_clear_all_breakpoints = asm["mono_wasm_clear_all_breakpoints"];
  asm["mono_wasm_clear_all_breakpoints"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_clear_all_breakpoints.apply(null, arguments);
  };
  
  var real__mono_wasm_set_breakpoint = asm["mono_wasm_set_breakpoint"];
  asm["mono_wasm_set_breakpoint"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_set_breakpoint.apply(null, arguments);
  };
  
  var real__mono_wasm_remove_breakpoint = asm["mono_wasm_remove_breakpoint"];
  asm["mono_wasm_remove_breakpoint"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_remove_breakpoint.apply(null, arguments);
  };
  
  var real__mono_wasm_current_bp_id = asm["mono_wasm_current_bp_id"];
  asm["mono_wasm_current_bp_id"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_current_bp_id.apply(null, arguments);
  };
  
  var real__mono_wasm_enum_frames = asm["mono_wasm_enum_frames"];
  asm["mono_wasm_enum_frames"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_enum_frames.apply(null, arguments);
  };
  
  var real__mono_wasm_get_var_info = asm["mono_wasm_get_var_info"];
  asm["mono_wasm_get_var_info"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_get_var_info.apply(null, arguments);
  };
  
  var real__mono_wasm_get_object_properties = asm["mono_wasm_get_object_properties"];
  asm["mono_wasm_get_object_properties"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_get_object_properties.apply(null, arguments);
  };
  
  var real__mono_wasm_get_array_values = asm["mono_wasm_get_array_values"];
  asm["mono_wasm_get_array_values"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_wasm_get_array_values.apply(null, arguments);
  };
  
  var real__mono_set_timeout_exec = asm["mono_set_timeout_exec"];
  asm["mono_set_timeout_exec"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_set_timeout_exec.apply(null, arguments);
  };
  
  var real__htonl = asm["htonl"];
  asm["htonl"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__htonl.apply(null, arguments);
  };
  
  var real__htons = asm["htons"];
  asm["htons"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__htons.apply(null, arguments);
  };
  
  var real__ntohs = asm["ntohs"];
  asm["ntohs"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__ntohs.apply(null, arguments);
  };
  
  var real__mono_background_exec = asm["mono_background_exec"];
  asm["mono_background_exec"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__mono_background_exec.apply(null, arguments);
  };
  
  var real___ZSt18uncaught_exceptionv = asm["_ZSt18uncaught_exceptionv"];
  asm["_ZSt18uncaught_exceptionv"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real___ZSt18uncaught_exceptionv.apply(null, arguments);
  };
  
  var real____cxa_can_catch = asm["__cxa_can_catch"];
  asm["__cxa_can_catch"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real____cxa_can_catch.apply(null, arguments);
  };
  
  var real____cxa_is_pointer_type = asm["__cxa_is_pointer_type"];
  asm["__cxa_is_pointer_type"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real____cxa_is_pointer_type.apply(null, arguments);
  };
  
  var real___get_tzname = asm["_get_tzname"];
  asm["_get_tzname"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real___get_tzname.apply(null, arguments);
  };
  
  var real___get_daylight = asm["_get_daylight"];
  asm["_get_daylight"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real___get_daylight.apply(null, arguments);
  };
  
  var real___get_timezone = asm["_get_timezone"];
  asm["_get_timezone"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real___get_timezone.apply(null, arguments);
  };
  
  var real___get_environ = asm["_get_environ"];
  asm["_get_environ"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real___get_environ.apply(null, arguments);
  };
  
  var real__memalign = asm["memalign"];
  asm["memalign"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__memalign.apply(null, arguments);
  };
  
  var real__emscripten_builtin_free = asm["emscripten_builtin_free"];
  asm["emscripten_builtin_free"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__emscripten_builtin_free.apply(null, arguments);
  };
  
  var real__emscripten_builtin_memalign = asm["emscripten_builtin_memalign"];
  asm["emscripten_builtin_memalign"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__emscripten_builtin_memalign.apply(null, arguments);
  };
  
  var real__setThrew = asm["setThrew"];
  asm["setThrew"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real__setThrew.apply(null, arguments);
  };
  
  var real_dynCall_vi = asm["dynCall_vi"];
  asm["dynCall_vi"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_vi.apply(null, arguments);
  };
  
  var real_stackSave = asm["stackSave"];
  asm["stackSave"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_stackSave.apply(null, arguments);
  };
  
  var real_stackAlloc = asm["stackAlloc"];
  asm["stackAlloc"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_stackAlloc.apply(null, arguments);
  };
  
  var real_stackRestore = asm["stackRestore"];
  asm["stackRestore"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_stackRestore.apply(null, arguments);
  };
  
  var real___growWasmMemory = asm["__growWasmMemory"];
  asm["__growWasmMemory"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real___growWasmMemory.apply(null, arguments);
  };
  
  var real_dynCall_iii = asm["dynCall_iii"];
  asm["dynCall_iii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iii.apply(null, arguments);
  };
  
  var real_dynCall_iiiii = asm["dynCall_iiiii"];
  asm["dynCall_iiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iiiii.apply(null, arguments);
  };
  
  var real_dynCall_iiiiii = asm["dynCall_iiiiii"];
  asm["dynCall_iiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iiiiii.apply(null, arguments);
  };
  
  var real_dynCall_viiiii = asm["dynCall_viiiii"];
  asm["dynCall_viiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viiiii.apply(null, arguments);
  };
  
  var real_dynCall_ii = asm["dynCall_ii"];
  asm["dynCall_ii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_ii.apply(null, arguments);
  };
  
  var real_dynCall_iiii = asm["dynCall_iiii"];
  asm["dynCall_iiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iiii.apply(null, arguments);
  };
  
  var real_dynCall_vii = asm["dynCall_vii"];
  asm["dynCall_vii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_vii.apply(null, arguments);
  };
  
  var real_dynCall_i = asm["dynCall_i"];
  asm["dynCall_i"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_i.apply(null, arguments);
  };
  
  var real_dynCall_iiiiiii = asm["dynCall_iiiiiii"];
  asm["dynCall_iiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_v = asm["dynCall_v"];
  asm["dynCall_v"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_v.apply(null, arguments);
  };
  
  var real_dynCall_viiii = asm["dynCall_viiii"];
  asm["dynCall_viiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viiii.apply(null, arguments);
  };
  
  var real_dynCall_viii = asm["dynCall_viii"];
  asm["dynCall_viii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viii.apply(null, arguments);
  };
  
  var real_dynCall_viiiiii = asm["dynCall_viiiiii"];
  asm["dynCall_viiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viiiiii.apply(null, arguments);
  };
  
  var real_dynCall_viiiiiii = asm["dynCall_viiiiiii"];
  asm["dynCall_viiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_viiiiiiii = asm["dynCall_viiiiiiii"];
  asm["dynCall_viiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viiiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_viiiiiiiii = asm["dynCall_viiiiiiiii"];
  asm["dynCall_viiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viiiiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_viiiiiiiiii = asm["dynCall_viiiiiiiiii"];
  asm["dynCall_viiiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viiiiiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_viiiiiiiiiii = asm["dynCall_viiiiiiiiiii"];
  asm["dynCall_viiiiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viiiiiiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_idiii = asm["dynCall_idiii"];
  asm["dynCall_idiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_idiii.apply(null, arguments);
  };
  
  var real_dynCall_vijji = asm["dynCall_vijji"];
  asm["dynCall_vijji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_vijji.apply(null, arguments);
  };
  
  var real_dynCall_jiii = asm["dynCall_jiii"];
  asm["dynCall_jiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_jiii.apply(null, arguments);
  };
  
  var real_dynCall_j = asm["dynCall_j"];
  asm["dynCall_j"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_j.apply(null, arguments);
  };
  
  var real_dynCall_iiiiiiiiii = asm["dynCall_iiiiiiiiii"];
  asm["dynCall_iiiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iiiiiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_jiij = asm["dynCall_jiij"];
  asm["dynCall_jiij"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_jiij.apply(null, arguments);
  };
  
  var real_dynCall_iiiiiiii = asm["dynCall_iiiiiiii"];
  asm["dynCall_iiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iiiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_iiji = asm["dynCall_iiji"];
  asm["dynCall_iiji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iiji.apply(null, arguments);
  };
  
  var real_dynCall_ji = asm["dynCall_ji"];
  asm["dynCall_ji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_ji.apply(null, arguments);
  };
  
  var real_dynCall_vj = asm["dynCall_vj"];
  asm["dynCall_vj"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_vj.apply(null, arguments);
  };
  
  var real_dynCall_iijiiiii = asm["dynCall_iijiiiii"];
  asm["dynCall_iijiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iijiiiii.apply(null, arguments);
  };
  
  var real_dynCall_iiiiiiiiiii = asm["dynCall_iiiiiiiiiii"];
  asm["dynCall_iiiiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iiiiiiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_iiiiiiiii = asm["dynCall_iiiiiiiii"];
  asm["dynCall_iiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iiiiiiiii.apply(null, arguments);
  };
  
  var real_dynCall_jii = asm["dynCall_jii"];
  asm["dynCall_jii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_jii.apply(null, arguments);
  };
  
  var real_dynCall_jijii = asm["dynCall_jijii"];
  asm["dynCall_jijii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_jijii.apply(null, arguments);
  };
  
  var real_dynCall_iijjji = asm["dynCall_iijjji"];
  asm["dynCall_iijjji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iijjji.apply(null, arguments);
  };
  
  var real_dynCall_dd = asm["dynCall_dd"];
  asm["dynCall_dd"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_dd.apply(null, arguments);
  };
  
  var real_dynCall_ff = asm["dynCall_ff"];
  asm["dynCall_ff"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_ff.apply(null, arguments);
  };
  
  var real_dynCall_ddd = asm["dynCall_ddd"];
  asm["dynCall_ddd"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_ddd.apply(null, arguments);
  };
  
  var real_dynCall_ddi = asm["dynCall_ddi"];
  asm["dynCall_ddi"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_ddi.apply(null, arguments);
  };
  
  var real_dynCall_fff = asm["dynCall_fff"];
  asm["dynCall_fff"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_fff.apply(null, arguments);
  };
  
  var real_dynCall_ffi = asm["dynCall_ffi"];
  asm["dynCall_ffi"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_ffi.apply(null, arguments);
  };
  
  var real_dynCall_viidiii = asm["dynCall_viidiii"];
  asm["dynCall_viidiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_viidiii.apply(null, arguments);
  };
  
  var real_dynCall_jij = asm["dynCall_jij"];
  asm["dynCall_jij"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_jij.apply(null, arguments);
  };
  
  var real_dynCall_didd = asm["dynCall_didd"];
  asm["dynCall_didd"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_didd.apply(null, arguments);
  };
  
  var real_dynCall_jijj = asm["dynCall_jijj"];
  asm["dynCall_jijj"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_jijj.apply(null, arguments);
  };
  
  var real_dynCall_fiff = asm["dynCall_fiff"];
  asm["dynCall_fiff"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_fiff.apply(null, arguments);
  };
  
  var real_dynCall_did = asm["dynCall_did"];
  asm["dynCall_did"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_did.apply(null, arguments);
  };
  
  var real_dynCall_fif = asm["dynCall_fif"];
  asm["dynCall_fif"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_fif.apply(null, arguments);
  };
  
  var real_dynCall_di = asm["dynCall_di"];
  asm["dynCall_di"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_di.apply(null, arguments);
  };
  
  var real_dynCall_fi = asm["dynCall_fi"];
  asm["dynCall_fi"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_fi.apply(null, arguments);
  };
  
  var real_dynCall_vid = asm["dynCall_vid"];
  asm["dynCall_vid"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_vid.apply(null, arguments);
  };
  
  var real_dynCall_vij = asm["dynCall_vij"];
  asm["dynCall_vij"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_vij.apply(null, arguments);
  };
  
  var real_dynCall_vif = asm["dynCall_vif"];
  asm["dynCall_vif"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_vif.apply(null, arguments);
  };
  
  var real_dynCall_jd = asm["dynCall_jd"];
  asm["dynCall_jd"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_jd.apply(null, arguments);
  };
  
  var real_dynCall_jf = asm["dynCall_jf"];
  asm["dynCall_jf"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_jf.apply(null, arguments);
  };
  
  var real_dynCall_id = asm["dynCall_id"];
  asm["dynCall_id"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_id.apply(null, arguments);
  };
  
  var real_dynCall_if = asm["dynCall_if"];
  asm["dynCall_if"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_if.apply(null, arguments);
  };
  
  var real_dynCall_d = asm["dynCall_d"];
  asm["dynCall_d"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_d.apply(null, arguments);
  };
  
  var real_dynCall_jiji = asm["dynCall_jiji"];
  asm["dynCall_jiji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_jiji.apply(null, arguments);
  };
  
  var real_dynCall_iidiiii = asm["dynCall_iidiiii"];
  asm["dynCall_iidiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return real_dynCall_iidiiii.apply(null, arguments);
  };
  
  Module["asm"] = asm;
  var ___wasm_call_ctors = Module["___wasm_call_ctors"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["__wasm_call_ctors"].apply(null, arguments)
  };
  
  var _mono_wasm_add_assembly = Module["_mono_wasm_add_assembly"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_add_assembly"].apply(null, arguments)
  };
  
  var _malloc = Module["_malloc"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["malloc"].apply(null, arguments)
  };
  
  var _mono_wasm_setenv = Module["_mono_wasm_setenv"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_setenv"].apply(null, arguments)
  };
  
  var _free = Module["_free"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["free"].apply(null, arguments)
  };
  
  var _mono_wasm_load_runtime = Module["_mono_wasm_load_runtime"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_load_runtime"].apply(null, arguments)
  };
  
  var _mono_wasm_assembly_load = Module["_mono_wasm_assembly_load"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_assembly_load"].apply(null, arguments)
  };
  
  var _mono_wasm_assembly_find_class = Module["_mono_wasm_assembly_find_class"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_assembly_find_class"].apply(null, arguments)
  };
  
  var _mono_wasm_assembly_find_method = Module["_mono_wasm_assembly_find_method"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_assembly_find_method"].apply(null, arguments)
  };
  
  var _mono_wasm_invoke_method = Module["_mono_wasm_invoke_method"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_invoke_method"].apply(null, arguments)
  };
  
  var _mono_wasm_assembly_get_entry_point = Module["_mono_wasm_assembly_get_entry_point"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_assembly_get_entry_point"].apply(null, arguments)
  };
  
  var _mono_wasm_string_get_utf8 = Module["_mono_wasm_string_get_utf8"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_string_get_utf8"].apply(null, arguments)
  };
  
  var _mono_wasm_string_from_js = Module["_mono_wasm_string_from_js"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_string_from_js"].apply(null, arguments)
  };
  
  var _mono_wasm_get_obj_type = Module["_mono_wasm_get_obj_type"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_get_obj_type"].apply(null, arguments)
  };
  
  var _mono_unbox_int = Module["_mono_unbox_int"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_unbox_int"].apply(null, arguments)
  };
  
  var _mono_wasm_unbox_float = Module["_mono_wasm_unbox_float"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_unbox_float"].apply(null, arguments)
  };
  
  var _mono_wasm_array_length = Module["_mono_wasm_array_length"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_array_length"].apply(null, arguments)
  };
  
  var _mono_wasm_array_get = Module["_mono_wasm_array_get"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_array_get"].apply(null, arguments)
  };
  
  var _mono_wasm_obj_array_new = Module["_mono_wasm_obj_array_new"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_obj_array_new"].apply(null, arguments)
  };
  
  var _mono_wasm_obj_array_set = Module["_mono_wasm_obj_array_set"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_obj_array_set"].apply(null, arguments)
  };
  
  var _mono_wasm_string_array_new = Module["_mono_wasm_string_array_new"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_string_array_new"].apply(null, arguments)
  };
  
  var _mono_wasm_exec_regression = Module["_mono_wasm_exec_regression"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_exec_regression"].apply(null, arguments)
  };
  
  var _mono_wasm_exit = Module["_mono_wasm_exit"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_exit"].apply(null, arguments)
  };
  
  var _mono_wasm_set_main_args = Module["_mono_wasm_set_main_args"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_set_main_args"].apply(null, arguments)
  };
  
  var _mono_wasm_strdup = Module["_mono_wasm_strdup"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_strdup"].apply(null, arguments)
  };
  
  var _mono_wasm_parse_runtime_options = Module["_mono_wasm_parse_runtime_options"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_parse_runtime_options"].apply(null, arguments)
  };
  
  var _mono_wasm_enable_on_demand_gc = Module["_mono_wasm_enable_on_demand_gc"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_enable_on_demand_gc"].apply(null, arguments)
  };
  
  var _mono_wasm_typed_array_new = Module["_mono_wasm_typed_array_new"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_typed_array_new"].apply(null, arguments)
  };
  
  var _mono_wasm_unbox_enum = Module["_mono_wasm_unbox_enum"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_unbox_enum"].apply(null, arguments)
  };
  
  var ___errno_location = Module["___errno_location"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["__errno_location"].apply(null, arguments)
  };
  
  var _fflush = Module["_fflush"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["fflush"].apply(null, arguments)
  };
  
  var _mono_print_method_from_ip = Module["_mono_print_method_from_ip"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_print_method_from_ip"].apply(null, arguments)
  };
  
  var _putchar = Module["_putchar"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["putchar"].apply(null, arguments)
  };
  
  var _mono_wasm_setup_single_step = Module["_mono_wasm_setup_single_step"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_setup_single_step"].apply(null, arguments)
  };
  
  var _mono_wasm_clear_all_breakpoints = Module["_mono_wasm_clear_all_breakpoints"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_clear_all_breakpoints"].apply(null, arguments)
  };
  
  var _mono_wasm_set_breakpoint = Module["_mono_wasm_set_breakpoint"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_set_breakpoint"].apply(null, arguments)
  };
  
  var _mono_wasm_remove_breakpoint = Module["_mono_wasm_remove_breakpoint"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_remove_breakpoint"].apply(null, arguments)
  };
  
  var _mono_wasm_current_bp_id = Module["_mono_wasm_current_bp_id"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_current_bp_id"].apply(null, arguments)
  };
  
  var _mono_wasm_enum_frames = Module["_mono_wasm_enum_frames"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_enum_frames"].apply(null, arguments)
  };
  
  var _mono_wasm_get_var_info = Module["_mono_wasm_get_var_info"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_get_var_info"].apply(null, arguments)
  };
  
  var _mono_wasm_get_object_properties = Module["_mono_wasm_get_object_properties"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_get_object_properties"].apply(null, arguments)
  };
  
  var _mono_wasm_get_array_values = Module["_mono_wasm_get_array_values"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_wasm_get_array_values"].apply(null, arguments)
  };
  
  var _mono_set_timeout_exec = Module["_mono_set_timeout_exec"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_set_timeout_exec"].apply(null, arguments)
  };
  
  var _htonl = Module["_htonl"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["htonl"].apply(null, arguments)
  };
  
  var _htons = Module["_htons"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["htons"].apply(null, arguments)
  };
  
  var _ntohs = Module["_ntohs"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["ntohs"].apply(null, arguments)
  };
  
  var _mono_background_exec = Module["_mono_background_exec"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["mono_background_exec"].apply(null, arguments)
  };
  
  var __ZSt18uncaught_exceptionv = Module["__ZSt18uncaught_exceptionv"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["_ZSt18uncaught_exceptionv"].apply(null, arguments)
  };
  
  var ___cxa_can_catch = Module["___cxa_can_catch"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["__cxa_can_catch"].apply(null, arguments)
  };
  
  var ___cxa_is_pointer_type = Module["___cxa_is_pointer_type"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["__cxa_is_pointer_type"].apply(null, arguments)
  };
  
  var __get_tzname = Module["__get_tzname"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["_get_tzname"].apply(null, arguments)
  };
  
  var __get_daylight = Module["__get_daylight"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["_get_daylight"].apply(null, arguments)
  };
  
  var __get_timezone = Module["__get_timezone"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["_get_timezone"].apply(null, arguments)
  };
  
  var __get_environ = Module["__get_environ"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["_get_environ"].apply(null, arguments)
  };
  
  var _memalign = Module["_memalign"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["memalign"].apply(null, arguments)
  };
  
  var _emscripten_builtin_free = Module["_emscripten_builtin_free"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["emscripten_builtin_free"].apply(null, arguments)
  };
  
  var _emscripten_builtin_memalign = Module["_emscripten_builtin_memalign"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["emscripten_builtin_memalign"].apply(null, arguments)
  };
  
  var _setThrew = Module["_setThrew"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["setThrew"].apply(null, arguments)
  };
  
  var dynCall_vi = Module["dynCall_vi"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_vi"].apply(null, arguments)
  };
  
  var stackSave = Module["stackSave"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["stackSave"].apply(null, arguments)
  };
  
  var stackAlloc = Module["stackAlloc"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["stackAlloc"].apply(null, arguments)
  };
  
  var stackRestore = Module["stackRestore"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["stackRestore"].apply(null, arguments)
  };
  
  var __growWasmMemory = Module["__growWasmMemory"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["__growWasmMemory"].apply(null, arguments)
  };
  
  var dynCall_iii = Module["dynCall_iii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iii"].apply(null, arguments)
  };
  
  var dynCall_iiiii = Module["dynCall_iiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iiiii"].apply(null, arguments)
  };
  
  var dynCall_iiiiii = Module["dynCall_iiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iiiiii"].apply(null, arguments)
  };
  
  var dynCall_viiiii = Module["dynCall_viiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viiiii"].apply(null, arguments)
  };
  
  var dynCall_ii = Module["dynCall_ii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_ii"].apply(null, arguments)
  };
  
  var dynCall_iiii = Module["dynCall_iiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iiii"].apply(null, arguments)
  };
  
  var dynCall_vii = Module["dynCall_vii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_vii"].apply(null, arguments)
  };
  
  var dynCall_i = Module["dynCall_i"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_i"].apply(null, arguments)
  };
  
  var dynCall_iiiiiii = Module["dynCall_iiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iiiiiii"].apply(null, arguments)
  };
  
  var dynCall_v = Module["dynCall_v"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_v"].apply(null, arguments)
  };
  
  var dynCall_viiii = Module["dynCall_viiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viiii"].apply(null, arguments)
  };
  
  var dynCall_viii = Module["dynCall_viii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viii"].apply(null, arguments)
  };
  
  var dynCall_viiiiii = Module["dynCall_viiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viiiiii"].apply(null, arguments)
  };
  
  var dynCall_viiiiiii = Module["dynCall_viiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viiiiiii"].apply(null, arguments)
  };
  
  var dynCall_viiiiiiii = Module["dynCall_viiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viiiiiiii"].apply(null, arguments)
  };
  
  var dynCall_viiiiiiiii = Module["dynCall_viiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viiiiiiiii"].apply(null, arguments)
  };
  
  var dynCall_viiiiiiiiii = Module["dynCall_viiiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viiiiiiiiii"].apply(null, arguments)
  };
  
  var dynCall_viiiiiiiiiii = Module["dynCall_viiiiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viiiiiiiiiii"].apply(null, arguments)
  };
  
  var dynCall_idiii = Module["dynCall_idiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_idiii"].apply(null, arguments)
  };
  
  var dynCall_vijji = Module["dynCall_vijji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_vijji"].apply(null, arguments)
  };
  
  var dynCall_jiii = Module["dynCall_jiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_jiii"].apply(null, arguments)
  };
  
  var dynCall_j = Module["dynCall_j"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_j"].apply(null, arguments)
  };
  
  var dynCall_iiiiiiiiii = Module["dynCall_iiiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iiiiiiiiii"].apply(null, arguments)
  };
  
  var dynCall_jiij = Module["dynCall_jiij"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_jiij"].apply(null, arguments)
  };
  
  var dynCall_iiiiiiii = Module["dynCall_iiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iiiiiiii"].apply(null, arguments)
  };
  
  var dynCall_iiji = Module["dynCall_iiji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iiji"].apply(null, arguments)
  };
  
  var dynCall_ji = Module["dynCall_ji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_ji"].apply(null, arguments)
  };
  
  var dynCall_vj = Module["dynCall_vj"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_vj"].apply(null, arguments)
  };
  
  var dynCall_iijiiiii = Module["dynCall_iijiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iijiiiii"].apply(null, arguments)
  };
  
  var dynCall_iiiiiiiiiii = Module["dynCall_iiiiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iiiiiiiiiii"].apply(null, arguments)
  };
  
  var dynCall_iiiiiiiii = Module["dynCall_iiiiiiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iiiiiiiii"].apply(null, arguments)
  };
  
  var dynCall_jii = Module["dynCall_jii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_jii"].apply(null, arguments)
  };
  
  var dynCall_jijii = Module["dynCall_jijii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_jijii"].apply(null, arguments)
  };
  
  var dynCall_iijjji = Module["dynCall_iijjji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iijjji"].apply(null, arguments)
  };
  
  var dynCall_dd = Module["dynCall_dd"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_dd"].apply(null, arguments)
  };
  
  var dynCall_ff = Module["dynCall_ff"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_ff"].apply(null, arguments)
  };
  
  var dynCall_ddd = Module["dynCall_ddd"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_ddd"].apply(null, arguments)
  };
  
  var dynCall_ddi = Module["dynCall_ddi"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_ddi"].apply(null, arguments)
  };
  
  var dynCall_fff = Module["dynCall_fff"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_fff"].apply(null, arguments)
  };
  
  var dynCall_ffi = Module["dynCall_ffi"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_ffi"].apply(null, arguments)
  };
  
  var dynCall_viidiii = Module["dynCall_viidiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_viidiii"].apply(null, arguments)
  };
  
  var dynCall_jij = Module["dynCall_jij"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_jij"].apply(null, arguments)
  };
  
  var dynCall_didd = Module["dynCall_didd"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_didd"].apply(null, arguments)
  };
  
  var dynCall_jijj = Module["dynCall_jijj"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_jijj"].apply(null, arguments)
  };
  
  var dynCall_fiff = Module["dynCall_fiff"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_fiff"].apply(null, arguments)
  };
  
  var dynCall_did = Module["dynCall_did"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_did"].apply(null, arguments)
  };
  
  var dynCall_fif = Module["dynCall_fif"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_fif"].apply(null, arguments)
  };
  
  var dynCall_di = Module["dynCall_di"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_di"].apply(null, arguments)
  };
  
  var dynCall_fi = Module["dynCall_fi"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_fi"].apply(null, arguments)
  };
  
  var dynCall_vid = Module["dynCall_vid"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_vid"].apply(null, arguments)
  };
  
  var dynCall_vij = Module["dynCall_vij"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_vij"].apply(null, arguments)
  };
  
  var dynCall_vif = Module["dynCall_vif"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_vif"].apply(null, arguments)
  };
  
  var dynCall_jd = Module["dynCall_jd"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_jd"].apply(null, arguments)
  };
  
  var dynCall_jf = Module["dynCall_jf"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_jf"].apply(null, arguments)
  };
  
  var dynCall_id = Module["dynCall_id"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_id"].apply(null, arguments)
  };
  
  var dynCall_if = Module["dynCall_if"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_if"].apply(null, arguments)
  };
  
  var dynCall_d = Module["dynCall_d"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_d"].apply(null, arguments)
  };
  
  var dynCall_jiji = Module["dynCall_jiji"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_jiji"].apply(null, arguments)
  };
  
  var dynCall_iidiiii = Module["dynCall_iidiiii"] = function() {
    assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
    assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
    return Module["asm"]["dynCall_iidiiii"].apply(null, arguments)
  };
  
  
  function invoke_vi(index,a1) {
    var sp = stackSave();
    try {
      dynCall_vi(index,a1);
    } catch(e) {
      stackRestore(sp);
      if (e !== e+0 && e !== 'longjmp') throw e;
      _setThrew(1, 0);
    }
  }
  
  
  
  // === Auto-generated postamble setup entry stuff ===
  
  Module['asm'] = asm;
  
  if (!Module["intArrayFromString"]) Module["intArrayFromString"] = function() { abort("'intArrayFromString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["intArrayToString"]) Module["intArrayToString"] = function() { abort("'intArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  Module["ccall"] = ccall;
  Module["cwrap"] = cwrap;
  Module["setValue"] = setValue;
  Module["getValue"] = getValue;
  if (!Module["allocate"]) Module["allocate"] = function() { abort("'allocate' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["getMemory"]) Module["getMemory"] = function() { abort("'getMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
  if (!Module["AsciiToString"]) Module["AsciiToString"] = function() { abort("'AsciiToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["stringToAscii"]) Module["stringToAscii"] = function() { abort("'stringToAscii' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["UTF8ArrayToString"]) Module["UTF8ArrayToString"] = function() { abort("'UTF8ArrayToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  Module["UTF8ToString"] = UTF8ToString;
  if (!Module["stringToUTF8Array"]) Module["stringToUTF8Array"] = function() { abort("'stringToUTF8Array' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["stringToUTF8"]) Module["stringToUTF8"] = function() { abort("'stringToUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["lengthBytesUTF8"]) Module["lengthBytesUTF8"] = function() { abort("'lengthBytesUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["UTF16ToString"]) Module["UTF16ToString"] = function() { abort("'UTF16ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["stringToUTF16"]) Module["stringToUTF16"] = function() { abort("'stringToUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["lengthBytesUTF16"]) Module["lengthBytesUTF16"] = function() { abort("'lengthBytesUTF16' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["UTF32ToString"]) Module["UTF32ToString"] = function() { abort("'UTF32ToString' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["stringToUTF32"]) Module["stringToUTF32"] = function() { abort("'stringToUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["lengthBytesUTF32"]) Module["lengthBytesUTF32"] = function() { abort("'lengthBytesUTF32' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["allocateUTF8"]) Module["allocateUTF8"] = function() { abort("'allocateUTF8' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["stackTrace"]) Module["stackTrace"] = function() { abort("'stackTrace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["addOnPreRun"]) Module["addOnPreRun"] = function() { abort("'addOnPreRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["addOnInit"]) Module["addOnInit"] = function() { abort("'addOnInit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["addOnPreMain"]) Module["addOnPreMain"] = function() { abort("'addOnPreMain' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["addOnExit"]) Module["addOnExit"] = function() { abort("'addOnExit' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["addOnPostRun"]) Module["addOnPostRun"] = function() { abort("'addOnPostRun' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["writeStringToMemory"]) Module["writeStringToMemory"] = function() { abort("'writeStringToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["writeArrayToMemory"]) Module["writeArrayToMemory"] = function() { abort("'writeArrayToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["writeAsciiToMemory"]) Module["writeAsciiToMemory"] = function() { abort("'writeAsciiToMemory' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["addRunDependency"]) Module["addRunDependency"] = function() { abort("'addRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
  if (!Module["removeRunDependency"]) Module["removeRunDependency"] = function() { abort("'removeRunDependency' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
  if (!Module["ENV"]) Module["ENV"] = function() { abort("'ENV' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["FS"]) Module["FS"] = function() { abort("'FS' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["FS_createFolder"]) Module["FS_createFolder"] = function() { abort("'FS_createFolder' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
  Module["FS_createPath"] = FS.createPath;
  Module["FS_createDataFile"] = FS.createDataFile;
  if (!Module["FS_createPreloadedFile"]) Module["FS_createPreloadedFile"] = function() { abort("'FS_createPreloadedFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
  if (!Module["FS_createLazyFile"]) Module["FS_createLazyFile"] = function() { abort("'FS_createLazyFile' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
  if (!Module["FS_createLink"]) Module["FS_createLink"] = function() { abort("'FS_createLink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
  if (!Module["FS_createDevice"]) Module["FS_createDevice"] = function() { abort("'FS_createDevice' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
  if (!Module["FS_unlink"]) Module["FS_unlink"] = function() { abort("'FS_unlink' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ). Alternatively, forcing filesystem support (-s FORCE_FILESYSTEM=1) can export this for you") };
  if (!Module["GL"]) Module["GL"] = function() { abort("'GL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["dynamicAlloc"]) Module["dynamicAlloc"] = function() { abort("'dynamicAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["warnOnce"]) Module["warnOnce"] = function() { abort("'warnOnce' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["loadDynamicLibrary"]) Module["loadDynamicLibrary"] = function() { abort("'loadDynamicLibrary' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["loadWebAssemblyModule"]) Module["loadWebAssemblyModule"] = function() { abort("'loadWebAssemblyModule' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["getLEB"]) Module["getLEB"] = function() { abort("'getLEB' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["getFunctionTables"]) Module["getFunctionTables"] = function() { abort("'getFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["alignFunctionTables"]) Module["alignFunctionTables"] = function() { abort("'alignFunctionTables' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["registerFunctions"]) Module["registerFunctions"] = function() { abort("'registerFunctions' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  Module["addFunction"] = addFunction;
  if (!Module["removeFunction"]) Module["removeFunction"] = function() { abort("'removeFunction' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["getFuncWrapper"]) Module["getFuncWrapper"] = function() { abort("'getFuncWrapper' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["prettyPrint"]) Module["prettyPrint"] = function() { abort("'prettyPrint' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["makeBigInt"]) Module["makeBigInt"] = function() { abort("'makeBigInt' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["dynCall"]) Module["dynCall"] = function() { abort("'dynCall' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["getCompilerSetting"]) Module["getCompilerSetting"] = function() { abort("'getCompilerSetting' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["stackSave"]) Module["stackSave"] = function() { abort("'stackSave' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["stackRestore"]) Module["stackRestore"] = function() { abort("'stackRestore' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["stackAlloc"]) Module["stackAlloc"] = function() { abort("'stackAlloc' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["establishStackSpace"]) Module["establishStackSpace"] = function() { abort("'establishStackSpace' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["print"]) Module["print"] = function() { abort("'print' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["printErr"]) Module["printErr"] = function() { abort("'printErr' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["getTempRet0"]) Module["getTempRet0"] = function() { abort("'getTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["setTempRet0"]) Module["setTempRet0"] = function() { abort("'setTempRet0' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };
  if (!Module["Pointer_stringify"]) Module["Pointer_stringify"] = function() { abort("'Pointer_stringify' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") };if (!Module["ALLOC_NORMAL"]) Object.defineProperty(Module, "ALLOC_NORMAL", { get: function() { abort("'ALLOC_NORMAL' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } });
  if (!Module["ALLOC_STACK"]) Object.defineProperty(Module, "ALLOC_STACK", { get: function() { abort("'ALLOC_STACK' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } });
  if (!Module["ALLOC_DYNAMIC"]) Object.defineProperty(Module, "ALLOC_DYNAMIC", { get: function() { abort("'ALLOC_DYNAMIC' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } });
  if (!Module["ALLOC_NONE"]) Object.defineProperty(Module, "ALLOC_NONE", { get: function() { abort("'ALLOC_NONE' was not exported. add it to EXTRA_EXPORTED_RUNTIME_METHODS (see the FAQ)") } });
  
  
  
  
  /**
   * @constructor
   * @extends {Error}
   * @this {ExitStatus}
   */
  function ExitStatus(status) {
    this.name = "ExitStatus";
    this.message = "Program terminated with exit(" + status + ")";
    this.status = status;
  };
  ExitStatus.prototype = new Error();
  ExitStatus.prototype.constructor = ExitStatus;
  
  var calledMain = false;
  
  dependenciesFulfilled = function runCaller() {
    // If run has never been called, and we should call run (INVOKE_RUN is true, and Module.noInitialRun is not false)
    if (!Module['calledRun']) run();
    if (!Module['calledRun']) dependenciesFulfilled = runCaller; // try this again later, after new deps are fulfilled
  }
  
  
  
  
  
  /** @type {function(Array=)} */
  function run(args) {
    args = args || Module['arguments'];
  
    if (runDependencies > 0) {
      return;
    }
  
    writeStackCookie();
  
    preRun();
  
    if (runDependencies > 0) return; // a preRun added a dependency, run will be called later
    if (Module['calledRun']) return; // run may have just been called through dependencies being fulfilled just in this very frame
  
    function doRun() {
      if (Module['calledRun']) return; // run may have just been called while the async setStatus time below was happening
      Module['calledRun'] = true;
  
      if (ABORT) return;
  
      initRuntime();
  
      preMain();
  
      if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']();
  
      assert(!Module['_main'], 'compiled without a main, but one is present. if you added it from JS, use Module["onRuntimeInitialized"]');
  
      postRun();
    }
  
    if (Module['setStatus']) {
      Module['setStatus']('Running...');
      setTimeout(function() {
        setTimeout(function() {
          Module['setStatus']('');
        }, 1);
        doRun();
      }, 1);
    } else {
      doRun();
    }
    checkStackCookie();
  }
  Module['run'] = run;
  
  function checkUnflushedContent() {
    // Compiler settings do not allow exiting the runtime, so flushing
    // the streams is not possible. but in ASSERTIONS mode we check
    // if there was something to flush, and if so tell the user they
    // should request that the runtime be exitable.
    // Normally we would not even include flush() at all, but in ASSERTIONS
    // builds we do so just for this check, and here we see if there is any
    // content to flush, that is, we check if there would have been
    // something a non-ASSERTIONS build would have not seen.
    // How we flush the streams depends on whether we are in SYSCALLS_REQUIRE_FILESYSTEM=0
    // mode (which has its own special function for this; otherwise, all
    // the code is inside libc)
    var print = out;
    var printErr = err;
    var has = false;
    out = err = function(x) {
      has = true;
    }
    try { // it doesn't matter if it fails
      var flush = Module['_fflush'];
      if (flush) flush(0);
      // also flush in the JS FS layer
      ['stdout', 'stderr'].forEach(function(name) {
        var info = FS.analyzePath('/dev/' + name);
        if (!info) return;
        var stream = info.object;
        var rdev = stream.rdev;
        var tty = TTY.ttys[rdev];
        if (tty && tty.output && tty.output.length) {
          has = true;
        }
      });
    } catch(e) {}
    out = print;
    err = printErr;
    if (has) {
      warnOnce('stdio streams had content in them that was not flushed. you should set EXIT_RUNTIME to 1 (see the FAQ), or make sure to emit a newline when you printf etc.');
    }
  }
  
  function exit(status, implicit) {
    checkUnflushedContent();
  
    // if this is just main exit-ing implicitly, and the status is 0, then we
    // don't need to do anything here and can just leave. if the status is
    // non-zero, though, then we need to report it.
    // (we may have warned about this earlier, if a situation justifies doing so)
    if (implicit && Module['noExitRuntime'] && status === 0) {
      return;
    }
  
    if (Module['noExitRuntime']) {
      // if exit() was called, we may warn the user if the runtime isn't actually being shut down
      if (!implicit) {
        err('exit(' + status + ') called, but EXIT_RUNTIME is not set, so halting execution but not exiting the runtime or preventing further async execution (build with EXIT_RUNTIME=1, if you want a true shutdown)');
      }
    } else {
  
      ABORT = true;
      EXITSTATUS = status;
  
      exitRuntime();
  
      if (Module['onExit']) Module['onExit'](status);
    }
  
    Module['quit'](status, new ExitStatus(status));
  }
  
  var abortDecorators = [];
  
  function abort(what) {
    if (Module['onAbort']) {
      Module['onAbort'](what);
    }
  
    if (what !== undefined) {
      out(what);
      err(what);
      what = '"' + what + '"';
    } else {
      what = '';
    }
  
    ABORT = true;
    EXITSTATUS = 1;
  
    var extra = '';
    var output = 'abort(' + what + ') at ' + stackTrace() + extra;
    if (abortDecorators) {
      abortDecorators.forEach(function(decorator) {
        output = decorator(output, what);
      });
    }
    throw output;
  }
  Module['abort'] = abort;
  
  if (Module['preInit']) {
    if (typeof Module['preInit'] == 'function') Module['preInit'] = [Module['preInit']];
    while (Module['preInit'].length > 0) {
      Module['preInit'].pop()();
    }
  }
  
  
    Module["noExitRuntime"] = true;
  global.MONO=MONO
  run();
  
  
  
  
  
  // {{MODULE_ADDITIONS}}
  
  
  
  