[
  {
    "path": ".babelrc",
    "content": "{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"browsers\": [\"last 2 versions\"]\n        },\n        \"useBuiltIns\": false\n      }\n    ],\n    \"mobx\"\n  ],\n  \"plugins\": [\n    \"@babel/plugin-transform-runtime\",\n    [\"@babel/plugin-proposal-decorators\", { \"legacy\": true }],\n    [\"@babel/plugin-proposal-class-properties\", { \"loose\": false }]\n  ]\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "# editorconfig.org\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  env: {\n    browser: true,\n    es2021: true,\n  },\n  extends: ['eslint:recommended', 'prettier'],\n  parserOptions: {\n    ecmaVersion: 'latest',\n    sourceType: 'module',\n  },\n  rules: {},\n}\n"
  },
  {
    "path": ".github/workflows/build-test.yml",
    "content": "name: Build and Test\non: [push, pull_request]\n\njobs:\n  build:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-22.04, macos-13, windows-2022]\n        node: [20, 22]\n    name: ${{ matrix.os }} and node ${{ matrix.node }}\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup node\n        uses: actions/setup-node@v4\n        with:\n          node-version: ${{ matrix.node }}\n\n      - name: Install dependencies\n        run: npm ci\n\n      - name: Download testing data\n        shell: bash\n        run: |\n          curl -OL https://github.com/Kitware/itk-vtk-viewer/releases/download/v14.35.1/itk-vtk-viewer-testing-data.tar.gz\n          tar xvzf ./itk-vtk-viewer-testing-data.tar.gz -C test/\n\n      - name: Build\n        run: npm run build\n\n      - name: Test\n        if: ${{ runner.os == 'Linux' }}\n        run: |\n          npm run test:downloadData\n          # Allow writing test/output.html\n          sudo chmod -R 777 test\n          # To debug, run `./test/run.sh -d`\n          npm run test:headless\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "name: Release\non:\n  push:\n    branches:\n      - master\n\njobs:\n  publish:\n    name: Publish\n    runs-on: ubuntu-22.04\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n      - name: Setup node\n        uses: actions/setup-node@v4\n        with:\n          node-version: 22\n\n      - name: Install dependencies\n        run: |\n          npm ci\n          sudo apt-get install xvfb\n\n      - name: Download testing data\n        shell: bash\n        run: |\n          curl -OL https://github.com/Kitware/itk-vtk-viewer/releases/download/v14.35.1/itk-vtk-viewer-testing-data.tar.gz\n          tar xvzf ./itk-vtk-viewer-testing-data.tar.gz -C test/\n          rm ./itk-vtk-viewer-testing-data.tar.gz\n\n      - name: Build\n        run: npm run build\n\n      - name: Chrome and Firefox tests\n        run: |\n          # Failing based on vtk.js piecewisegaussian?\n          # xvfb-run --auto-servernum npm run test -- --browsers Chrome,Firefox\n\n          # Allow writing test/output.html\n          sudo chmod -R 777 test\n          # To debug, run `./test/run.sh -d`\n          npm run test:headless\n      - name: Release\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}\n        run: |\n          git config --global user.name \"Github Actions\"\n          git config --global user.email \"sebastien.jourdain@kitware.com\"\n          npm run semantic-release\n      - name: Publish docs\n        if: github.ref == 'refs/heads/master'\n        env:\n          GIT_PUBLISH_URL: https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/Kitware/itk-vtk-viewer.git\n        run: npm run doc:publish\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n*.swp\n.npm-packages\n.npmrc\nyarn.lock\nnpm-debug.log\nnode_modules\nData\ndist/\ncoverage/\ntest/output.html\ntest/TESTS-*.xml\ntest/testUINoPlaneSlidersBundle.js\n\nsrc/Compression/blosc-zarr/web-build/*\n!src/Compression/blosc-zarr/web-build/BloscZarr.js\n!src/Compression/blosc-zarr/web-build/BloscZarr.umd.js\n!src/Compression/blosc-zarr/web-build/BloscZarr.wasm\ntest/data/\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"src/blosc/c-blosc\"]\n\tpath = src/Compression/blosc-zarr/c-blosc\n\turl = https://github.com/Blosc/c-blosc\n"
  },
  {
    "path": ".npmignore",
    "content": ".DS_Store\n.gitmodules\n.npmrc\n.sass-cache\n.travis.yml\ndoc\nnpm-debug.log\nsrc/UI/reference-ui/node_modules\nsrc/Compression/blosc-zarr\ntest\nsrc/Compression/blosc-zarr/web-build\nsrc/IO/Downsample/web-build\n.github\ndist/itk/image-io/node_modules\ndist/itk/mesh-io/node_modules\ndist/*.map\n"
  },
  {
    "path": ".prettierrc",
    "content": "{\n  \"endOfLine\": \"lf\",\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"tabWidth\": 2,\n  \"trailingComma\": \"es5\"\n}\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Contributing to ITK/VTK ImageViewer\n====================================\n\nThis page documents at a very high level how to contribute to itk-vtk-viewer.\n\n1. The itk-vtk-viewer source is maintained on Github at [github.com/kitware/itk-vtk-viewer](https://github.com/kitware/itk-vtk-viewer)\n\n2. [Fork the repository] into your user's namespace on Github.\n\n3. Create a local clone of the main repository:\n\n    ```sh\n    $ git clone https://github.com/kitware/itk-vtk-viewer.git\n    $ cd itk-vtk-viewer\n    ```\n\n    The main repository will be configured as your `origin` remote.\n\n4. Run the setup script to prepare itk-vtk-viewer:\n    ```sh\n    $ npm install\n    $ npm install -g commitizen\n    ```\n\n5. Edit files and create commits (repeat as needed):\n    ```sh\n    $ edit file1 file2 file3\n    $ git add file1 file2 file3\n    $ npm run commit\n    ```\n\n6. Push commits in your topic branch to your fork in Github:\n    ```sh\n    $ git push\n    ```\n\n7. Visit your fork in Github, browse to the \"**Pull Requests**\" link on the\n   left, and use the \"**New Pull Request**\" button in the upper right to\n   create a Pull Request.\n\n   For more information see: [Create a Pull Request]\n\nThis project uses GitHub for code review and Travis-CI to test proposed\npatches before they are merged.\n\nOur [DevSite] is used to document features, flesh out designs and host other\ndocumentation as well as the API.\n\n\n[Fork the repository]: https://help.github.com/articles/fork-a-repo/\n[Create a Pull Request]: https://help.github.com/articles/creating-a-pull-request/\n[DevSite]: http://kitware.github.io/itk-vtk-viewer\n"
  },
  {
    "path": "Copyright.txt",
    "content": "/*=========================================================================\n\n  Program:   ITK/VTK ImageViewer\n  Module:    Copyright.txt\n\nCopyright (c) 2016 Ken Martin, Will Schroeder, Bill Lorensen\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n * Redistributions of source code must retain the above copyright notice,\n   this list of conditions and the following disclaimer.\n\n * Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names\n   of any contributors may be used to endorse or promote products derived\n   from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n=========================================================================*/\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2016, Kitware Inc.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above copyright\n      notice, this list of conditions and the following disclaimer in the\n      documentation and/or other materials provided with the distribution.\n    * Neither the name of the <organization> nor the\n      names of its contributors may be used to endorse or promote products\n      derived from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY\nDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "## [ITK/VTK Viewer - Web based Image, Mesh, and Point Set Viewer](http://kitware.github.io/itk-vtk-viewer/)\n\n![Build and Test](https://github.com/Kitware/itk-vtk-viewer/workflows/Build%20and%20Test/badge.svg)\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n![npm-download](https://img.shields.io/npm/dm/itk-vtk-viewer.svg)\n[![](https://data.jsdelivr.com/v1/package/npm/itk-vtk-viewer/badge?style=rounded)](https://www.jsdelivr.com/package/npm/itk-vtk-viewer)\n![npm-version-requirement](https://img.shields.io/badge/npm->=8.0.0-brightgreen.svg)\n![node-version-requirement](https://img.shields.io/badge/node->=12.0.0-brightgreen.svg)\n[![launch ImJoy](https://imjoy.io/static/badge/launch-imjoy-badge.svg)](http://imjoy.io/#/app?plugin=https://kitware.github.io/itk-vtk-viewer/app/)\n[![DOI](https://zenodo.org/badge/92198432.svg)](https://zenodo.org/badge/latestdoi/92198432)\n\n# Introduction\n\nITK/VTK Viewer is an open-source software system for medical and\nscientific image, mesh, and point set visualization.\n\n# Reporting Issues\n\nIf you would like to discuss a bug or possible improvement:\n\n1. If you have a patch, please read the [CONTRIBUTING.md][] document.\n\n2. Open an entry in the [Issue Tracker][].\n\n[contributing.md]: CONTRIBUTING.md\n[issue tracker]: https://github.com/Kitware/itk-vtk-viewer/issues\n\n# Requirements\n\nIn general ITK/VTK Viewer tries to be as portable as possible; the specific configurations below are tested and known to work.\n\nITK/VTK Viewer supports the following development environments:\n\n- Node 16+\n- NPM 8+\n\nand the following browsers:\n\n- Firefox\n- Chrome\n- Safari\n\n# Documentation\n\nSee the [documentation](https://kitware.github.io/itk-vtk-viewer) for a\ngetting started guide, advanced documentation, and API descriptions.\n\n# Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for instructions to contribute.\n\n# License\n\nITK/VTK Viewer is distributed under the OSI-approved BSD 3-clause License.\nSee [Copyright.txt][] for details.\n\n[copyright.txt]: Copyright.txt\n\n# Build Blosc with Debug\n\nCheckout `c-blosc` git submodule, then\n\n`itk-wasm --build-dir web-build build -- -DCMAKE_BUILD_TYPE=Debug`\n"
  },
  {
    "path": "bin/itk-vtk-viewer-cli.js",
    "content": "#!/usr/bin/env node\n\nlet program = require('commander');\nlet ipList = require('./network');\nlet server = require('./server');\nlet pkg = require('../package.json');\nlet openFn = require('open');\nlet path = require('path');\n\nlet app = null;\nlet version = /semantically-release/.test(pkg.version) ? 'development version' : pkg.version;\nlet dataPath = process.cwd();\n\nfunction handlePort(value) {\n  if (!isNaN(parseInt(value, 10))) {\n    return parseInt(value, 10);\n  }\n  throw Error('port option requires a number');\n}\n\nprogram\n  .version(version)\n  .option('-p, --port [3000]', 'Start web server with given port', handlePort, 3000)\n  .option('-s, --server-only', 'Do not open the web browser\\n')\n  .arguments('[inputFile]')\n  .parse(process.argv);\n\nconst inputFilePath = program.args[0];\nlet urlOptions = '';\nif (inputFilePath) {\n  const fullPath = path.normalize(inputFilePath);\n  dataPath = path.dirname(fullPath);\n  const inputFileName = path.basename(fullPath);\n  urlOptions = `?fileToLoad=/data/${inputFileName.replace(/ /g, '%20')}`\n}\n\n// Start server and listening\napp = server(dataPath);\napp.listen(program.port);\n\n// Print server information\nif (ipList.length === 1) {\n  console.log(['\\nitk-vtk-viewer\\n  => Serving ', dataPath, '\\n\\n     http://', ipList[0].ip, ':', program.port, `/${urlOptions}\\n`].join(''));\n} else {\n  function printIP(l) {\n    console.log('    ', l.name, ['=> http://', l.ip, ':', program.port, `/${urlOptions}`].join(''));\n  }\n  console.log(['\\nitk-vtk-viewer\\n  => Serving ', dataPath, ' on port ', program.port, '\\n'].join(''));\n  ipList.forEach(printIP);\n  console.log();\n}\n\n// Open browser if asked\nif (!program.serverOnly) {\n  openFn(['http://localhost:', program.port, `/${urlOptions}`].join(''));\n}\n"
  },
  {
    "path": "bin/network.js",
    "content": "var os = require('os');\n\nvar ifaces = os.networkInterfaces();\nvar networkInterfaces = [];\nvar alias = 0;\nvar currentName = '';\n\nfunction netInterface(iface) {\n  if (iface.family !== 'IPv4' || iface.internal !== false) {\n    // skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses\n    return;\n  }\n\n  if (alias >= 1) {\n    // this single interface has multiple ipv4 addresses\n    networkInterfaces.push({\n      name: [currentName, alias].join(':'),\n      ip: iface.address,\n    });\n  } else {\n    // this interface has only one ipv4 adress\n    networkInterfaces.push({\n      name: currentName,\n      ip: iface.address,\n    });\n  }\n  ++alias;\n}\n\nfunction device(ifname) {\n  alias = 0;\n  currentName = ifname;\n  ifaces[ifname].forEach(netInterface);\n}\n\nObject.keys(ifaces).forEach(device);\n\nmodule.exports = networkInterfaces;\n"
  },
  {
    "path": "bin/server.js",
    "content": "var path = require('path');\nvar express = require('express');\n\nfunction webServer(dataPath) {\n  var app = express();\n  var fullDataPath = dataPath;\n\n  // Handle relative path\n  if (fullDataPath[0] === '.') {\n    fullDataPath = path.normalize(path.join(process.cwd(), dataPath));\n  }\n\n  app.use(express.static(path.join(__dirname, '/../dist')));\n  app.use('/data', express.static(fullDataPath));\n\n  return app;\n}\n\nmodule.exports = webServer;\n"
  },
  {
    "path": "buildUI.js",
    "content": "#!/usr/bin/env node\n\nconst path = require('path')\nconst spawnSync = require('child_process').spawnSync\n\nconst cwd = path.join(__dirname, 'src', 'UI', 'reference-ui')\nspawnSync('npm', ['ci'], { cwd, env: process.env, stdio: 'inherit' })\nspawnSync('npm', ['run', 'build'], { cwd, env: process.env, stdio: 'inherit' })\n"
  },
  {
    "path": "doc/.gitignore",
    "content": "build-tmp\n"
  },
  {
    "path": "doc/config.js",
    "content": "module.exports = {\n  baseUrl: '/itk-vtk-viewer',\n  work: './build-tmp',\n  examples: [],\n  config: {\n    title: 'itk-vtk-viewer',\n    description: '\"ITK/VTK Image Viewer for the Web\"',\n    subtitle: '\"Enable medical imaging to the Web.\"',\n    author: 'Kitware Inc.',\n    timezone: 'UTC',\n    url: 'https://kitware.github.io/itk-vtk-viewer',\n    root: '/itk-vtk-viewer/',\n    github: 'kitware/itk-vtk-viewer',\n    google_analytics: 'UA-90338862-7',\n  },\n  copy: [\n    { src: '../dist/*', dest: './build-tmp/public/app' },\n  ],\n};\n"
  },
  {
    "path": "doc/content/api/index.md",
    "content": "# API\n\nThis documentation provides more detailed information about the viewer application programming interface (API).\n\n## Viewer API\n\n### getConfig()\n\nGet the viewer configuration. This can be used to restore a viewer's\nconfiguration when created.\n\n### setRenderingViewContainerStyle(containerStyle)\n\n### getRenderingViewContainerStyle()\n\nSet/get the CSS style for the rendering view `div`'s.\n\n### setBackgroundColor(bgColor)\n\n### getBackgroundColor()\n\nSet/get the rendering background color. An array of RGB values from 0.0 to 1.0,\ne.g. [1.0, 0.5, 0.5].\n\n### setUnits(units)\n\n### getUnits()\n\nSet/get the string identifying the spatial length units in the scale bar.\n\n### setUICollapsed(collapsed)\n\n### getUICollapsed()\n\nSet/get whether the user interface is collapsed.\n\n## Viewer Main API\n\n### setRotateEnabled(enabled)\n\n### getRotateEnabled()\n\nSet/get whether the 3D scene is continuously rotated.\n\n### setAnnotationsEnabled(enabled)\n\n### getAnnotationsEnabled()\n\nSet/get whether annotations such as the current pixel value, scale bar, or orientation widget are displayed.\n\n### setAxesEnabled(enabled)\n\n### getAxesEnabled()\n\nSet/get whether spatial axes are visualized in the scene.\n\n### setXSlice(position)\n\n### getXSlice()\n\nSet/get the position in world space of the X slicing plane.\n\n### setYSlice(position)\n\n### getYSlice()\n\nSet/get the position in world space of the Y slicing plane.\n\n### setZSlice(position)\n\n### getZSlice()\n\nSet/get the position in world space of the Z slicing plane.\n\n### setViewMode(mode)\n\n### getViewMode()\n\nSet/get the viewer mode for the current primary view. Valid values: 'XPlane', 'YPlane', 'ZPlane', or 'Volume'.\n\n### getLayerNames()\n\nGet the names of all data layers.\n\n### setLayerVisibility(visible, name)\n\n### getLayerVisibility(name)\n\nSet/get whether the named layer is visible.\n\n### selectLayer(name)\n\nSelect the layer identified by `name` in the user interface.\n\n### setCroppingPlanes(croppingPlanes)\n\nThe croppingPlanes parameter is an array of plane defining objects. Example: `[ { normal: [1, 0, 0], origin: [1, 2, 3] }, ...]`. Maximum number of planes is 6.\n\n### getCroppingPlanes(): [ { normal: [number, number, number], origin: [number, number, number] }, ...]\n\nReturns array of plane objects.\n\n### resetCroppingPlanes()\n\nSets cropping box to encompass all images and geometries\n\n### setCroppingPlanesEnabled(enabled)\n\nControl visibility of croppingPlanes\n\n### getCroppingPlanesEnabled(): Boolean\n\n## Viewer Image API\n\n### setImage(image)\n\nSet the image to be visualized. Can be an [itk.js Image](https://insightsoftwareconsortium.github.io/itk-js/api/Image.html) or a [scijs ndarray](http://scijs.net/packages/#scijs/ndarray) for JavaScript; for Python, it can be a [numpy](https://numpy.org) array.\n\n### setPointSets(pointSets)\n\nSet a set of points to be visualized. It can be an array of or a single imjoy-rpc encoded ndarray. The ndarray should be an array with the shape [x, 2] or [x, 3].\n\n### captureImage()\n\nTake a screenshot for the current view and return a base64 encoded image string.\n\n### setImageInterpolationEnabled(enabled)\n\n### getImageInterpolationEnabled()\n\nSet/get whether bilinear interpolation is used in the image slicing planes.\n\n### setImageComponentVisibility(visibility, component, name)\n\n### getImageComponentVisibility(component, name)\n\nSet/get the given image intensity component index's visibility.\n\n### setImageColorRange(range, component, name)\n\n### getImageColorRange(component, name)\n\nSet/get the [min, max] range of intensity values mapped to colors for the given\nimage component identified by name.\n\n### setImageColorRangeBounds(bounds, component, name)\n\n### getImageColorRangeBounds(component, name)\n\nSet/get the [min, max] range of intensity values for color maps that provide a bounds\nfor user inputs.\n\n### setImageColorMap(colorMap, component, name)\n\n### getImageColorMap(component, name)\n\nSet/get the color map for the given component/channel.\n\n<!---\n### setImagePiecewiseFunctionGaussians(gaussians, component, name)\n\n### getImagePiecewiseFunctionGaussians(component, name)\n\nSet/get the gaussian parameters that define the piecewise function used to define\nthe volume rendering opacity transfer function and multi-component slice blending.\n-->\n\n### setImagePiecewiseFunctionPoints(points, component, name = current)\n\n### getImagePiecewiseFunctionPoints(component, name)\n\nSet/get the points defining the piecewise volume opacity transfer and multi-component\nslice blending function. Parameter points is of type `[intensity: number, opacity:number][]` with\nintensity and opacity values going from 0 to 1. The 0 to 1 intensity values are scaled between\nthe component's range of intensity values.\nExample: If the intensity values for component 0 go from 100 to 200,\n`viewer.setImagePiecewiseFunctionPoints([[0, 0], [.5, 1]], 0)` puts a point at intensity 100 and another at intensity 150.\nFor volume rendering, intensities above or below the range of points have 0 opacity.\nFor 2D or slice rendering, intensities above or below the range of points take the last color of the color map.\nWith 2 or more components in 2D or slice rendering, the `y` value of points controls the contribution of matching intensities.\nIntensities before the start point take the `y`/mix-factor of the start point, intensities after the end point take the end point `y` value.\n\n### setImageShadowEnabled(enabled, name)\n\n### getImageShadowEnabled(name)\n\nSet/get whether to used gradient-based shadows in the volume rendering.\n\n### setImageGradientOpacity(opacity, name)\n\n### getImageGradientOpacity(name)\n\nSet/get the gradient opacity in the volume rendering. Values range from 0.0 to 1.0.\n\n### setImageGradientOpacityScale(scale, name)\n\n### getImageGradientOpacityScale(name)\n\nSet/get the gradient scale for gradient-based opacity in the volume rendering. Values range from 0.0 to 1.0.\n\n### setImageVolumeSampleDistance(distance, name)\n\n### getImageVolumeSampleDistance(name)\n\nSet/get the depth sampling distance in the volume rendering. Values range from 0.0 to 1.0.\n\n### setImageBlendMode(mode, name)\n\n### getImageBlendMode(name)\n\nSet/get the volume rendering blend mode. Supported modes: 'Composite',\n'Maximum', 'Minimum', 'Average'.\n\n### setLabelImage(labelImageToLoad, layerImageName)\n\nLoads a label image and fuses with selected image or layerImageName.\nsetLabelImage disables 2D image interpolation.\n\n### setLabelImageLookupTable(lookupTable, name)\n\n### getLabelImageLookupTable(name)\n\nSet/get the label image lookup table.\n\n### setLabelImageBlend(blend, name)\n\n### getLabelImageBlend(name)\n\nSet/get the blend ratio between the label image and the intensity image.\n\n### setLabelImageLabelNames(labeNames, name)\n\n### getLabelImageLabelNames(name)\n\nSet/get the string names for the integer label values. A Map of label integer to\nstring values.\n\n### setLabelImageWeights(weights, name)\n\n### getLabelImageWeights(name)\n\nSet/get the rendering weights assigned to labels. A Map of label integer to\nfloat, 0.0 to 1.0, weight.\nstring values.\n\n### setImageScale(resolutionScale)\n\nresolutionScale is a integer with 0 being the most detailed scale.\n\n### setCompareImages(fixedImageName, movingImageName, options)\n\nPost processing to detect difference in images. The moving and fixed images are separately\ncompressed to one component with a vector magnitude or luminance filter. Then, the moving image is\nre-sampled to the fixed image space. The final rendered image has the fixed image on the first component,\nthe moving image is on the second component.\n\nThe moving image must have been added last.\n\n`options` is an Object with:\n\n```\n{\n    method: 'checkerboard' | 'cyan-magenta' | 'blend' | 'disabled',\n    imageMix?: number,\n    checkerboard?: boolean,\n    pattern?: number[],\n    swapImageOrder?: boolean\n}\n```\n\n`method` can be `blend`, `green-magenta`, `cyan-red`, `cyan-magenta`, `checkerboard`, or `disabled`.\n`blend` simply initiates the comparison composition of images.\n`cyan-magenta` changes the color map for fixed image to cyan, moving image to magenta. If images match perfectly, the color will be purple.\n`green-magenta` and `cyan-red` changes the color map for the fixed and moving image. If images match, the color will be gray/white.\n`checkerboard` is equivalent to `blend` with `imageMix` set to `0`.\n\n`imageMix` changes the percent contribution the fixed vs moving image makes to the\nrender by modifying the opacity transfer function. Value of 1 means max opacity for\nmoving image, 0 for fixed image.\n\n`checkerboard` picks pixels from the fixed and moving image to create a\ncheckerboard pattern. The 2 components in the output image differ by the\nimage order for each checkerboard box.\n\n`pattern` is an array with the number of checkerboard boxes for each dimension.\nIf pattern === undefined, it defaults to 4 boxes across each dimension\n\n`swapImageOrder` toggles the checkerboard pattern by switching the imageMix parameter between 0 and 1.\n"
  },
  {
    "path": "doc/content/config/index.md",
    "content": "title: Config\n---\n\nThis documentation provides more detailed information about the viewer configuration.\n\nThe viewer configuration is a JSON-serializable JavaScript object in the browser and Python dictionary in a Python environment.\n\nTo obtain a viewer's configuration, call the [viewer API `getConfig()` method](../api/).\n\nPass a viewer's configuration during creation with the `config` option.\n\nThe followings sections describe the configuration fields.\n\n## Viewer Config\n\n### viewerConfigVersion\n\nThis is a \"major.minor\" version of the configuration. The major version\nchanges with incompatible configuration -- a viewer will only use a\nconfiguration that has the same major version. The minor version indicates\nsupported configuration entries.\n\n### uiMachineOptions\n\nHow to render the user interface. Either `'reference'` or `{ href: 'https://url.to/uiMachineOptionsESM.js, export: 'default' }`, or a JavaScript object with the UI machine options. If a JavaScript object, it will not be serializable.\n\n### xyLowerLeft\n\nWhen viewing the Z slice, the X-Y plane, whether the origin is in the lower left\nor upper left.\n\n### renderingViewContainerStyle\n\nCSS style of the container (`div`) for the rendering views.\n\n### uiCollapsed\n\nWhether the user interface is collapsed.\n\n## Main Config\n\n### backgroundColor\n\nBackground color of the renderer.\n\n### units\n\nSpatial length units displayed in the scale bar.\n"
  },
  {
    "path": "doc/content/docs/cli.md",
    "content": "title: Command Line Interface\n---\n\nITK/VTK Viewer can be used as a command line tool for opening and visualizing your local data file.\n\n## Installation\n\nFirst, [install Node.js](https://nodejs.org/en/download/), if not already installed. After Node.js is installed, the `node` and `npm` executables should be in your `PATH`.\n\n```sh\n$ npm install itk-vtk-viewer -g\n```\n\nThis command will install the application globally, which will provide a new command line executable, `itk-vtk-viewer`:\n\n```sh\n$ itk-vtk-viewer\n\n  Usage: itk-vtk-viewer [options] ] [inputFile]\n\n    Options:\n\n    -V, --version      output the version number\n    -p, --port [3000]  Start web server with given port (default: 3000)\n    -s, --server-only  Do not open the web browser\n\n    -h, --help         output usage information\n```\n\n### Quick start\n\nTo visualize an image, pass the path to the file to visualize. By default, a new tab will open in your browser with your visualization.\n\n```sh\n$ itk-vtk-viewer ./MRHead.nrrd\n\nitk-vtk-viewer\n  => Serving .\n\n       http://10.10.10.10:3000/?fileToLoad=/data/MRHead.nrrd\n```\n\n### Drag and drop viewer\n\nInstead of specifying files via the command line,\n\n1. drag and drop,\n2. click on the viewer page, or\n3. press the *Enter* key\n\nafter starting the executable without positional arguments:\n\n```sh\n$ itk-vtk-viewer\n```\n\n![ItkVtkViewer](./viewer.jpg)\n"
  },
  {
    "path": "doc/content/docs/customizeUI.md",
    "content": "title: User Interface (UI) Customization\n---\n\nThe viewer's user interface (UI) is completely customizable. An existing viewer user interface can be tweaked, or a new user interface can be built from scratch. Use vanilla HTML/CSS/JavaScript or your favorite UI framework, such as React.js or Vue.js.\n\nThe user interface is specified on viewer creation with a JavaScript object or an object that specifies an [ES Module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). The UI object should contain functions that implement **actions** called as UI [state machines](https://xstate.js.org/docs/) respond to events. Nested objects provide actions for child state machines. A few example actions are `toggleDarkMode` or `toggleUICollapsed`.\n\nEach [action function](https://xstate.js.org/docs/about/glossary.html#action) is expected to accept two arguments: `context` and `event`.\n\nThe `context` is the current state machine context. A `context` object is comprised of the context generated by the [viewer configuration](../config/) and additional objects generated by the UI or renderer. For example, the `createInterface` action may add a `div` property to the `context` for the UI that other UI actions may reference later.\n\nThe `event` argument is the current event object that triggered the action. An `event` object contains the event name, an upper case string by convention. Optionally, the `event` may contain a payload in the `data` property. In addition to responding to events, a UI implementation will trigger events from user input and pass those events to the state machine by calling `context.service.send(<triggeredEvent>)`. For example,\n\n```\ncollapseUIButton.addEventListener('click', () => { context.service.send('TOGGLE_UI_COLLAPSED'))\n```\n\n## UI options architecture\n\n**Warning**: the viewer machine's architecture is experimental and it is subject to change without modification to the major version of the package. We mean it!\n\nAvailable actions can be observed in the [Reference UI Machine Options](https://github.com/Kitware/itk-vtk-viewer/blob/master/src/UI/reference-ui/src/referenceUIMachineOptions.js). If an action is not implemented, it is a no-op. Nested options objects correspond to the nested state machines. They are:\n\n* [`main`](https://github.com/Kitware/itk-vtk-viewer/blob/master/src/UI/Reference/Main/mainUIMachineOptions.js): UI components impacting the entire viewer's state. For example, the UI to toggle fullscreen mode or change the viewer's background color.\n* [`layers`](https://github.com/Kitware/itk-vtk-viewer/blob/master/src/UI/Reference/Layers/layersUIMachineOptions.js): UI components related to dataset layers. For example, the UI to select a layer or toggle its visibility.\n* [`widgets`](https://github.com/Kitware/itk-vtk-viewer/blob/master/src/UI/Reference/Widgets/widgetsUIMachineOptions.js): UI components for interactive widget parameters. For example, display the current distance measured by a distance widget.\n* [`images`](https://github.com/Kitware/itk-vtk-viewer/blob/master/src/UI/Reference/Images/imagesUIMachineOptions.js): UI components related to the currently selected image layer. For example, the current color map used.\n* `geometries` (todo): UI components related to the currently selected geometry layer. For example, the current geometry opacity.\n* `pointSets` (todo): UI components related to the currently selected point set layer. For example, the current point set opacity.\n\n## Example: Main UI with only a screenshot button\n\nThis example demonstrates how to customize the `reference` UI so the `main` interface only presents a screenshot button.\n\n### Create repository\n\nLet's create a repository for our interface.\n\nEither use the *Use this template* button on the [itk-viewer-reference-ui-template GitHub repository](https://github.com/InsightSoftwareConsortium/itk-viewer-reference-ui-template):\n\n![itk-viewer-reference-ui-template button](./referenceUITemplateGitHub.png)\n\nor use the template repository on the command line:\n\n```\nnpx degit InsightSoftwareConsortium/itk-viewer-reference-ui-template my-viewer-ui\n```\n\n### Edit interface\n\nTo create our interface, first install the Node.js packages:\n\n```\ncd my-viewer-ui\nnpm ci\n```\n\nThen start the development server:\n\n```\nnpm run dev\n```\n\nAnd visit *http://localhost:3000* in your web browser. The template has customized the viewer's [Reference UI](https://www.npmjs.com/package/itk-viewer-reference-ui) to only present a screenshot button in the viewer's main interface. The main interface is customized with the `createMainInterface` action.\n\n```\nimport referenceUIMachineOptions from 'itk-viewer-reference-ui/src/referenceUIMachineOptions.js'\nimport style from 'itk-viewer-reference-ui/src/ItkVtkViewer.module.css'\nimport createScreenshotButton from 'itk-viewer-reference-ui/src/Main/createScreenshotButton.js'\n\nfunction modifiedCreateMainInterface(context) {\n  const mainUIGroup = document.createElement('div')\n  mainUIGroup.setAttribute('class', style.uiGroup)\n  context.uiGroups.set('main', mainUIGroup)\n\n  const mainUIRow1 = document.createElement('div')\n  mainUIRow1.setAttribute('class', style.mainUIRow)\n  mainUIGroup.appendChild(mainUIRow1)\n\n  createScreenshotButton(context, mainUIRow1)\n\n  context.uiContainer.appendChild(mainUIGroup)\n}\n```\n\n![screenshot button](./screenshotButton.png)\n\nWe re-use the rest of the user interface machine actions:\n\n```\nconst uiMachineOptions = { ...referenceUIMachineOptions }\n\nconst uiMainActions = { ...uiMachineOptions.main.actions }\nuiMainActions.createMainInterface = modifiedCreateMainInterface\n\nconst uiMain = { ...uiMachineOptions.main }\nuiMain.actions = uiMainActions\nuiMachineOptions.main = uiMain\n```\n\nAnd use the `uiMachineOptions` as the default module export:\n\n```\nexport default uiMachineOptions\n```\n\nLet's make the background of the main user interface green by editing *main.js*:\n\n```\n  [...]\n  createScreenshotButton(context, mainUIRow1)\n\n  // Add this line\n  mainUIGroup.style.backgroundColor = \"green\"\n\n  context.uiContainer.appendChild(mainUIGroup)\n  [...]\n```\n\nAfter saving *main.js*, the page will reload with our change applied:\n\n![screenshot button green](./screenshotButtonGreen.png)\n\n### Publish the UI module\n\nExit the development server with *Ctrl+C* if still open, then build a production version of the user interface module:\n\n```\nnpm run build\n```\n\nThis builds the module `dist/referenceUIMachineOptions.js.es.js`.\n\nWe can publish our interface to [npmjs.com](https://www.npmjs.com/). First change the package `name` in the *package.json* file to something unique:\n\n```\n{\n  \"version\": \"0.1.0\",\n  \"name\": \"my-viewer-ui\",\n  \"scripts\": {\n```\n\nThen publish the package:\n\n```\nnpm login\nnpm publish\n```\n\nAfter published and propagated on the network, your package is available for download. The package files are also served by services like [jsdelivr](https://jsdelivr.com) (better for production use) or [unpkg](https://unpkg.com) (better for testing). Use your user interface by specifying it in the [viewer config](../config.html):\n\n```\nconst uiMachineOptions = { href: \"https://cdn.jsdelivr.net/npm/itk-viewer-reference-ui-template@0.1.2/dist/referenceUIMachineOptions.js.es.js\" }\n// or\n// const uiMachineOptions = { href: \"https://unpkg.com/itk-viewer-reference-ui-template@0.1.2/dist/referenceUIMachineOptions.js.es.js\" }\nitkVtkViewer.createViewer(container,\n  {\n  image: ipfsImage,\n  rotate: false,\n  config: { uiMachineOptions },\n  })\n```\n"
  },
  {
    "path": "doc/content/docs/embeddedViewer.md",
    "content": "title: Embedded Viewer\n---\n\nITK/VTK Viewer can be used within an existing web site as a library to embed interactive 3D visualizations for remote or local datasets. To do so, create a container element for the viewer as follows.\n\n```html\n<div class=\"itk-vtk-viewer\" />\n```\n\nMoreover, the JavaScript library should also be added to the web page. Only one of the following is required\n\n```html\n<script type=\"text/javascript\" src=\"https://kitware.github.io/itk-vtk-viewer/app/itkVtkViewerCDN.js\"></script>\n```\n\nor\n\n```html\n<script type=\"text/javascript\" src=\"https://unpkg.io/itk-vtk-viewer/dist/itkVtkViewerCDN.js\"></script>\n```\n\nor, fixed to a specific version:\n\n```html\n<script type=\"text/javascript\" src=\"https://unpkg.io/itk-vtk-viewer@9.14.1/dist/itkVtkViewerCDN.js\"></script>\n```\n\n### Viewer configuration\n\nThe container `<div/>` can be extended with the following set of [data attributes](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes):\n\n- (Mandatory) __data-url__=\"/data/005_36months_T2_RegT1_Reg2Atlas_ManualBrainMask_Stripped.nrrd\"\n- (Optional) __data-viewport__=\"300x200\" | default is 500x500\n- (Optional) __data-background-color__=\"00aa00\" | default is black\n- (Optional) __data-use2D=\"false\"\n\n\n![ItkVtkViewer-embedded](./embeddedViewer.png)\n\n```html\n<!DOCTYPE html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\"/>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  </head>\n  <body>\n\n    [...]\n\n    <div\n      style=\"float: right; display: inline-block; border: 2px solid gray; margin: 20px; margin-right: 50px;\"\n      class=\"itk-vtk-viewer\"\n      data-url=\"https://data.kitware.com/api/v1/file/564a65d58d777f7522dbfb61/download/data.nrrd\"\n      data-viewport=\"450x300\"\n    ></div>\n\n    [...]\n\n    <div\n      style=\"float: left; display: inline-block; border: 2px solid gray;\n      class=\"itk-vtk-viewer\"\n      data-url=\"https://data.kitware.com/api/v1/file/5b8446868d777f43cc8d5ec1/download/data.nrrd\"\n      data-viewport=\"450x400\"\n      data-background-color=\"ffffff\"\n    ></div>\n\n    [...]\n\n    <script type=\"text/javascript\" src=\"https://unpkg.io/itk-vtk-viewer/dist/itkVtkViewerCDN.js\"></script>\n  </body>\n</html>\n```\n"
  },
  {
    "path": "doc/content/docs/imjoy.md",
    "content": "title: ImJoy Plugin\n---\n\n[![launch ImJoy](https://imjoy.io/static/badge/launch-imjoy-badge.svg)](http://imjoy.io/#/app?plugin=https://kitware.github.io/itk-vtk-viewer/app/)\n\nAn *itk-vtk-viewer* plugin is available for [ImJoy](https://imjoy.io), a plugin powered hybrid computing platform for deploying deep learning applications such as advanced image analysis tools.\n\n![ImJoy itk-vtk-viewer plugin](./imjoy.png)\n\n## Installation\n\nInstall the plugin into the workspace with the following [ImJoy Web App](http://imjoy.io/#/app?plugin=https://kitware.github.io/itk-vtk-viewer/app/) or [ImJoy Lite App](http://imjoy.io/lite?plugin=https://kitware.github.io/itk-vtk-viewer/app/) links with the plugin URI:\n\n```\nhttps://kitware.github.io/itk-vtk-viewer/app/\n```\n\nNote that the link can also be used directly.\n\nTo install a specific version associated with a specific commit, click the *Details* link associated with the *fleek/build* check found in checkmark link popup in the [GitHub commit interface](https://github.com/Kitware/itk-vtk-viewer/commits/master).\n\n![CID link](./fleek-build-link.png)\n\nThis results in a URL that contains a root [Content Identifier (CID)](https://proto.school/anatomy-of-a-cid/01). For example,\n\n```\nhttps://bafybeihh34vpeoczdl3bu5wff3cvx35g2u3h3cbs6cmc3werg7drobr3ty.on.fleek.co/\n```\n\n## Inputs\n\nSupported context `data` inputs:\n\n**image**: Image to be visualized. Can be:\n\n- An [itk-wasm Image](https://wasm.itk.org/api/Image.html)\n- A [scijs ndarray](http://scijs.net/packages/#scijs/ndarray) for JavaScript; for Python, it can be a [numpy](https://numpy.org) array.\n- A [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) pointing to an [image file supported by itk-wasm](https://wasm.itk.org/docs/image_formats.html).\n\nFor [scijs ndarray](http://scijs.net/packages/#scijs/ndarray), you can use the following function to encoded it into an imjoy-rpc encoded ndarray.\n```\nfunction encodeScijsArray(array){\n  return {\n    _rtype: 'ndarray',\n    _rdtype: array.dtype,\n    _rshape: array.shape,\n    _rvalue: array.data.buffer,\n  }\n}\n```\n\nThe `image` key is optional; one can also call `setImage()` later.\n\n**pointSets**: An array of pointSet or a single pointSet to be visualized. Can be **an array** of imjoy-rpc encoded ndarray (as described in **image**):\n\nThe `pointSets` key is optional; one can also call `setPointSets()` later.\n\n\nContext `config`:\n\nAn optional [viewer configuration](../config/) can be passed with the context `config`. To\nretrieve the configuration from an existing viewer, call `viewer.getConfig()`.\n\nUsage in javascript:\n```javascript\nconst imageArray = ... // itk-wasm Image or imjoy-rpc encoded ndarray\nconst viewer = await api.createWindow({\n  src: \"https://kitware.github.io/itk-vtk-viewer/app/\",\n  data: { image: imageArray },\n  config: config,\n  })\n```\n\nUsage in Python\n```python\nfrom imjoy import api\nimport numpy as np\n\n# a 2D or 3D numpy array\nimage_array = np.random.randint(0, 255, [500, 500], dtype='uint8')\n\nasync def setup():\n    viewer = await api.createWindow(src=\"https://kitware.github.io/itk-vtk-viewer/app/\", data={\"image\": imageArray}, config=config)\n\napi.export({\"setup\": setup})\n```\n\nDisplaying a point cloud in Python:\n```python\nimport numpy as np\nfrom imjoy import api\n\n# make a point set array\ngaussian_1_mean = [0.0, 0.0, 0.0]\ngaussian_1_cov = [[1.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 0.5]]\nnumber_of_points = 1000000\npoint_set_array = np.random.multivariate_normal(gaussian_1_mean,\n                                                gaussian_1_cov,\n                                                number_of_points)\npoint_set_array = point_set_array.astype('float32')\n\nasync def setup():\n    viewer = await api.createWindow(\n        src=\"https://kitware.github.io/itk-vtk-viewer/app/\"\n    )\n    await viewer.setPointSets([point_set_array])\n\napi.export({\"setup\": setup})\n```\n## API functions\n\nIn addition to the standard `setup` and `run` methods, the *itk-vtk-viewer* plugin exposes the full [viewer API](../api/).\n"
  },
  {
    "path": "doc/content/docs/index.md",
    "content": "title: Overview\n---\n\n![Build and Test](https://github.com/Kitware/itk-vtk-viewer/workflows/Build%20and%20Test/badge.svg) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) ![npm-download](https://img.shields.io/npm/dm/itk-vtk-viewer.svg) [![DOI](https://zenodo.org/badge/92198432.svg)](https://zenodo.org/badge/latestdoi/92198432) [![launch ImJoy](https://imjoy.io/static/badge/launch-imjoy-badge.svg)](http://imjoy.io/#/app?plugin=https://kitware.github.io/itk-vtk-viewer/app/)\n\nITK/VTK Viewer is an open-source web application for medical and scientific image, mesh, and point set visualization.\n\n![How it works](./howToUse.jpg)\n\n"
  },
  {
    "path": "doc/content/docs/shortcuts.md",
    "content": "title: Keyboard Shortcuts and Controls\n---\n\nThe viewer supports mouse-based controls, touchscreen interaction, and\nkeyboard shortcuts. To use the keyboard shortcuts when the viewer is embedded,\nthe mouse must be over the viewer.\n\n**Key** | **Action**\n--- | --- |\n**1** | X-plane mode\n**2** | Y-plane mode\n**3** | Z-plane mode\n**4** | Volume rendering mode\n**q** | Toggle user interface\n**w** | Toggle region of interest (ROI) selection widget\n**e** | Reset ROI\n**r** | Reset camera\n**p** | Toggle spinning\n**s** | Toggle slicing planes in volume rendering mode\n**f** | Toggle fullscreen\n\n**Mouse** | **Action**\n--- | --- |\n**Left click + drag** | Rotate\n**Right click + drag** or **shift + left click + drag** | Pan\n**Mouse wheel** or **control + left click + drag** or **pinch** | Zoom\n**Alt + left click + drag left-right** | Change color transfer function level\n**Alt + left click + drag top-bottom** | Change color transfer function window\n**Alt + right click + drag top-bottom** | Change primary volume opacity transfer function magnitude\n"
  },
  {
    "path": "doc/content/docs/viewer.md",
    "content": "title: Progressive Web App\n---\n\nThe [default ITK/VTK Viewer page](https://kitware.github.io/itk-vtk-viewer/app/) lets you drag and drop or select a data file from your local filesystem to visualize. Once you have loaded data with this [progressive web app](https://en.wikipedia.org/wiki/Progressive_Web_Apps), the app will also work offline.\n\nAdditionally, visualization links for data files available on the web can be created by providing extra arguments to the app URL. The resulting link can be quickly shared to distribute interative visualizations for your data.\n\nFor example,\n\n<div>\n<label for=\"dataVisualizationLink\"><a href=\"https://kitware.github.io/itk-vtk-viewer/app/?fileToLoad=https://data.kitware.com/api/v1/file/564a65d58d777f7522dbfb61/download/data.nrrd\" target=\"_blank\" id=\"linkForNewTab\">Visualization link:</a></label>\n<textarea name=\"dataVisualizationLink\" id=\"dataVisualizationLink\" rows=\"1\" cols=\"100\" wrap=\"off\" readonly></textarea>\n<button onclick=\"copyLinkToClipboard()\">Copy to clipboard</button>\n</div>\n\n<script>\nvar textarea = document.getElementById(\"dataVisualizationLink\");\n// Avoid Markdown from messing with it\ntextarea.value = 'https://kitware.github.io/itk-vtk-viewer/app/?fileToLoad=https://data.kitware.com/api/v1/file/564a65d58d777f7522dbfb61/download/data.nrrd';\n\nfunction generateDataVisualizationLink() {\n  var url = \"https://kitware.github.io/itk-vtk-viewer/app/?fileToLoad=\" + document.getElementById(\"dataURL\").value.trim();\n  var previewer = document.getElementById(\"linkPreview\");\n  var linkForNewTab = document.getElementById(\"linkForNewTab\");\n  previewer.src = url;\n  textarea.value = url;\n  linkForNewTab.href = url;\n}\n\nfunction copyLinkToClipboard() {\n  textarea.select();\n  document.execCommand(\"copy\");\n}\n</script>\n\n<div>\n<label for=\"dataURL\">Enter an image, mesh, or point set file URL:</label>\n<input type=\"url\" name=\"dataURL\" id=\"dataURL\" placeholder=\"https://data.kitware.com/api/v1/file/564a65d58d777f7522dbfb61/download/data.nrrd\" size=\"100\" required oninput=\"generateDataVisualizationLink()\" />\n</div>\n\n<br>\n\nThe extra argument, `?fileToLoad=[...]`, uses a full `http://` url to the data file.\n\n![ItkVtkViewer](./dataViewer.jpg)\n\nAn additional parameter can be added to force the slice viewing mode. Just add `?use2D` or `?fileToLoad=[..]&use2D` inside the URL.\n\n![ItkVtkViewer2D](./2dViewer.jpg)\n\n### Compare Images URL Parameters\n\nTo compare 2 images use these parameters:\n\n`image`: full `http://` url to a data file\n\n`fixedImage`: full `http://` url to a data file\n\n`compare`: sets the compare \"method\". Could be `blend`, `green-magenta`, `cyan-red`, `cyan-magenta` or `checkerboard`\n\n`imageMix`: 0 to 1 percent contribution the fixed vs moving image\n\n`checkerboard`: `true` or `false` to force checkerboard for other methods like `blend` or `cyan-magenta`\n\n`pattern`: Checkerboard pattern as array with length matching the number of dimension in the images. Example: `pattern=[1,3,4]`\n\n`swapImageOrder`: `true` or `false` which toggles the checkerboard pattern.\n\nExample:\n`http://localhost:8082/?rotate=false&image=http://localhost:8082/test-data/HeadMRVolume.nrrd&fixedImage=http://localhost:8082/test-data/HeadMRVolume2Components.nrrd&compare=checkerboard&pattern=[1,3,4]&swapImageOrder=true`\n\nMore information under setCompareImages on the API docs.\n"
  },
  {
    "path": "doc/content/index.html",
    "content": "<html>\n<head>\n  <meta http-equiv=\"refresh\" content=\"0; URL=./docs/\" />\n</head>\n<body>\n  <p>Redirecting to the documentation. For the application, go to <a href=\"./app/\">./app/</a>.</p>\n</body>\n</html>\n"
  },
  {
    "path": "doc/content/index.jade",
    "content": "layout: index\ndescription: ITK/VTK Viewer\nsubtitle: An open-source software system for medical and scientific image, mesh, and point set visualization.\ncmd: itk-vtk-viewer --help\ncomments: false\n---\n\nul#intro-feature-list\n  li.intro-feature-wrap\n    .intro-feature\n      .intro-feature-icon\n        i.fa.fa-cloud-download\n      h3.intro-feature-title\n        a(href=\"https://www.npmjs.com/package/itk-vtk-viewer\").link Releases\n        img(style=\"padding-left: 25px\",src=\"https://badge.fury.io/js/itk-vtk-viewer.svg\")\n      p.intro-feature-desc ITK/VTK Viewer is a web-based viewer for loading 2D/3D images and more...\n\n  li.intro-feature-wrap\n    .intro-feature\n      .intro-feature-icon\n          i.fa.fa-life-ring\n      h3.intro-feature-title\n        a(href=\"http://www.vtk.org/services/\").link Support and Services\n      p.intro-feature-desc Kitware offers advanced software R&D solutions and services. Find out how we can help with your next project.\n\nul#intro-cmd-wrap(style='margin-top: 25px;border-radius: 10px;')\n  li.intro-cmd-item npm install itk-vtk-viewer -g\n  li.intro-cmd-item itk-vtk-viewer\n\np(style='text-align: center; margin: 20px auto; max-width: 700px;')\n  img(src='./docs/howToUse.jpg', width='100%')\n"
  },
  {
    "path": "doc/data/menu.yml",
    "content": "docs: /docs/\napi: /api/\nconfig: /config/\napp: /app/\n"
  },
  {
    "path": "doc/tpl/__en__",
    "content": "menu:\n  docs: Documentation\n  api: API\n  config: Config\n  examples: Examples\n  news: News\n  search: Search\n  app: Application\n\nindex:\n  get_started: Get started\n\npage:\n  contents: Contents\n  back_to_top: Back to Top\n  improve: Improve this doc\n  prev: Prev\n  next: Next\n  last_updated: \"Last updated: %s\"\n\nsidebar:\n  docs:\n    getting_started: Getting Started\n    overview: Overview\n    develop: Development\n    requirement: Requirements\n    troubleshooting: Troubleshooting\n    debugging: Debugging\n    contributing: Contributing\n    testing: Testing\n    tests: Tests\n    coverage: Coverage\n    cli: Command Line App\n    viewer: Progressive Web App\n    embeddedViewer: Inline Viewer\n    imjoy: ImJoy Plugin\n    shortcuts: Keyboard Shortcuts\n    customizeUI: UI Customization\n\n"
  },
  {
    "path": "doc/tpl/__sidebar__",
    "content": "docs:\n  getting_started:\n    overview: index.html\n    viewer: viewer.html\n    cli: cli.html\n    embeddedViewer: embeddedViewer.html\n    imjoy: imjoy.html\n    shortcuts: shortcuts.html\n    customizeUI: customizeUI.html\n"
  },
  {
    "path": "examples/compare-image.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  </head>\n  <body>\n    <div\n      style=\"position: relative; border: 1px solid red; width: 100%; height: 99vh;\"\n      id=\"viewport\"\n    ></div>\n\n    <script type=\"text/javascript\" src=\"itkVtkViewer.js\"></script>\n    <script>\n      async function main() {\n        const image = new URL(\n          'test-data/HeadMRVolume.nrrd',\n          // 'test-data/HeadMRVolume2Components.nrrd',\n          // 'http://localhost:8082/test-data/idr/6001240.zarr',\n          // 'test-data/HeadMRVolume2DTop.nrrd',\n          window.location.origin\n        )\n\n        const fixedImage = new URL(\n          // 'test-data/HeadMRVolume.nrrd',\n          // 'test-data/HeadMRVolumeLabels.nrrd',\n          // 'test-data/HeadMRVolumeLabelsSmaller.nrrd',\n          'test-data/HeadMRVolume2Components.nrrd',\n          // 'test-data/HeadMRVolume2DTop.nrrd',\n          window.location.origin\n        )\n\n        const labelImage = new URL(\n          'test-data/HeadMRVolumeLabels.nrrd',\n          window.location.origin\n        )\n\n        const container = document.querySelector('#viewport')\n\n        // Provide fixedImage and compare as createViewer options example:\n        const viewer = await itkVtkViewer.createViewer(container, {\n          rotate: false,\n          image,\n          fixedImage,\n          // labelImage,\n          compare: { method: 'blend', imageMix: 0.25 },\n        })\n\n        // Call setImage to add images, then setCompareImages example:\n        // const viewer = await itkVtkViewer.createViewer(container, {\n        //   rotate: false,\n        // })\n        // viewer.setImage(fixedImage, 'Fixed') // fixed image must be first one added\n        // viewer.setImage(image, 'Image')\n        // viewer.setLabelImage(labelImage)\n\n        // viewer.setCompareImages('Fixed', 'Image', {\n        //   method: 'checkerboard',\n        //   swapImageOrder: false,\n        // })\n\n        // setTimeout(\n        //   () =>\n        //     viewer.setCompareImages('Fixed', 'Image', {\n        //       method: 'disabled',\n        //     }),\n        //   2000\n        // )\n\n        setTimeout(\n          () =>\n            viewer.setCompareImages('Fixed', 'Image', {\n              method: 'checkerboard',\n              pattern: [1, 2, 3],\n            }),\n          4000\n        )\n\n        setTimeout(\n          () =>\n            viewer.setCompareImages('Fixed', 'Image', {\n              method: 'cyan-magenta',\n              checkerboard: false,\n            }),\n          6000\n        )\n\n        window.viewer = viewer\n      }\n\n      main()\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/cyan-magenta-compare-image.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  </head>\n  <body>\n    <div\n      style=\"position: relative; border: 1px solid red; width: 100%; height: 99vh;\"\n      id=\"viewport\"\n    ></div>\n\n    <script type=\"text/javascript\" src=\"itkVtkViewer.js\"></script>\n    <script>\n      async function main() {\n        const image = new URL(\n          // 'test-data/HeadMRVolume.nrrd',\n          'test-data/HeadMRVolume2Components.nrrd',\n          // 'test-data/HeadMRVolumeLabels.nrrd',\n          // 'http://localhost:8082/test-data/idr/6001240.zarr',\n          // 'test-data/HeadMRVolume2DTop.nrrd',\n          window.location.origin\n        )\n\n        const fixedImage = new URL(\n          'test-data/HeadMRVolume.nrrd',\n          // 'test-data/HeadMRVolumeLabels.nrrd',\n          // 'test-data/HeadMRVolumeLabelsSmaller.nrrd',\n          // 'test-data/HeadMRVolume2Components.nrrd',\n          // 'test-data/HeadMRVolume2DTop.nrrd',\n          window.location.origin\n        )\n\n        const labelImage = new URL(\n          'test-data/HeadMRVolumeLabels.nrrd',\n          window.location.origin\n        )\n\n        const container = document.querySelector('#viewport')\n\n        // Provide fixedImage and compare as createViewer options example:\n        const viewer = await itkVtkViewer.createViewer(container, {\n          rotate: false,\n          image,\n          fixedImage,\n          // labelImage,\n          compare: { method: 'cyan-red' },\n        })\n\n        // Call setImage to add images, then setCompareImages example:\n        // const viewer = await itkVtkViewer.createViewer(container, {\n        //   rotate: false,\n        // })\n        // viewer.setImage(fixedImage, 'Fixed') // fixed image must be first one added\n        // viewer.setImage(image, 'Image')\n        // viewer.setLabelImage(labelImage, 'Image')\n\n        // viewer.setCompareImages('Fixed', 'Image', {\n        //   method: 'cyan-magenta',\n        // })\n\n        // setTimeout(\n        //   () =>\n        //     viewer.setCompareImages('Fixed', 'Image', {\n        //       method: 'disabled',\n        //     }),\n        //   2000\n        // )\n\n        // setTimeout(\n        //   () =>\n        //     viewer.setCompareImages('Fixed', 'Image', {\n        //       method: 'cyan-magenta',\n        //     }),\n        //   4000\n        // )\n\n        window.viewer = viewer\n      }\n\n      main()\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/test-conglomerate.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  </head>\n  <body>\n    <div\n      style=\"position: relative; border: 1px solid red; width: 1000px; height: 1000px;\"\n      id=\"viewport\"\n    ></div>\n\n    <script type=\"text/javascript\" src=\"itkVtkViewer.js\"></script>\n    <script>\n      async function main() {\n        const imageUrl = new URL(\n          'test-data/HeadMRVolume.nrrd',\n          window.location.origin\n        )\n        const images = await Promise.all(\n          [imageUrl, imageUrl].map(itkVtkViewer.utils.toMultiscaleSpatialImage)\n        )\n        const image = new itkVtkViewer.utils.ConglomerateMultiscaleSpatialImage(\n          images\n        )\n        const container = document.querySelector('#viewport')\n        const viewer = await itkVtkViewer.createViewer(container, {\n          // image,\n          rotate: false,\n        })\n\n        viewer.setImage(image)\n        // need the await for the setImagePiecewiseFunctionPoints to take\n        await viewer.setLabelImage(\n          new URL('test-data/HeadMRVolumeLabels.nrrd', window.location.origin)\n        )\n\n        const newPoints = [\n          [0, 0],\n          [0.75, 0.9],\n          [0.9, 1],\n        ]\n        viewer.setImagePiecewiseFunctionPoints(newPoints, 0)\n        viewer.setImageColorMap('glasbey', 0)\n        viewer.setImageColorRangeMin(30)\n        viewer.setImageColorRangeMax(200)\n        window.viewer = viewer\n      }\n\n      main()\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/test-pointsets.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  </head>\n  <body>\n    <div\n      style=\"position: relative; border: 1px solid red; width: 1000px; height: 1000px;\"\n      id=\"viewport\"\n    ></div>\n\n    <script type=\"text/javascript\" src=\"itkVtkViewer.js\"></script>\n    <script\n      type=\"text/javascript\"\n      src=\"https://unpkg.com/vtk.js@25.8.2/vtk.js\"\n    ></script>\n    <script>\n      const points = vtk({\n        vtkClass: 'vtkPolyData',\n        points: {\n          vtkClass: 'vtkPoints',\n          name: '_points',\n          numberOfComponents: 3,\n          dataType: 'Float32Array',\n          values: new Float32Array([\n            -0.44442534,\n            -1.1349318,\n            0.8388769,\n            2.0538256,\n            -1.9028517,\n            0.71276945,\n          ]),\n        },\n        verts: {\n          vtkClass: 'vtkCellArray',\n          name: '_verts',\n          numberOfComponents: 1,\n          dataType: 'Uint32Array',\n          size: 4,\n          values: new Uint16Array([1, 0, 1, 1]),\n        },\n      })\n\n      const container = document.querySelector('#viewport')\n      itkVtkViewer.createViewer(container, {\n        pointSets: [points],\n        rotate: false,\n      })\n    </script>\n  </body>\n</html>\n"
  },
  {
    "path": "examples/test.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <meta http-equiv=\"Content-type\" content=\"text/html; charset=utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n  </head>\n  <body>\n    <div\n      style=\"display: inline-block; border: 1px solid red;\"\n      class=\"itk-vtk-viewer\"\n      data-url=\"test-data/first_instar_brain_zyxc.zarr\"\n      data-viewport=\"600x600\"\n      data-background-color=\"008800\"\n      data-rotate=\"false\"\n    ></div>\n\n    <div\n      style=\"display: inline-block; border: 1px solid red;\"\n      class=\"itk-vtk-viewer\"\n      data-url=\"test-data/astronaut.zarr\"\n      data-background-color=\"008800\"\n      data-rotate=\"false\"\n    ></div>\n\n    <!-- \n      test-data/astronaut.zarr\n      test-data/first_instar_brain_zyxc.zarr\n      test-data/ome-ngff-prototypes/single_image/v0.4/zyx.ome.zarr\n      test-data/ome-ngff-prototypes/single_image/v0.4/tczyx.ome.zarr\n      test-data/idr/1884807.zarr\n      test-data/idr/6001240.zarr\n      test-data/idr/6001256.zarr\n      test-data/idr/9836841.zarr\n      test-data/HeadMRVolume.nrrd\n      test-data/HeadMRVolumeLabels.nrrd\n      https://dandiarchive.s3.amazonaws.com/zarr/3d313fc2-0204-496d-bfa1-5c90951ee640\n      https://data.kitware.com/api/v1/file/564a65d58d777f7522dbfb61/download/data.nrrd\n      https://data.kitware.com/api/v1/file/625d10dc4acac99f426404e0/download/chameleon.nrrd\n      https://data.kitware.com/api/v1/file/5b843d468d777f43cc8d4f6b/download/engine.nrrd\n      https://data.kitware.com/api/v1/file/5a826c198d777f0685782976/download/test_vmtkbranchmetrics_branch_metrics_surf.vtp\n    -->\n\n    <script type=\"text/javascript\" src=\"itkVtkViewer.js\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "karma.conf.js",
    "content": "/* eslint-disable global-require */\nconst path = require('path')\n\nconst vtkRules = require('vtk.js/Utilities/config/dependency.js').webpack.core\n  .rules\nconst cssRules = require('vtk.js/Utilities/config/dependency.js').webpack.css\n  .rules\n\nvar webpack = require('webpack')\n\nvar sourcePath = path.join(__dirname, './src')\n\nif (!process.env.NODE_ENV) process.env.NODE_ENV = 'test'\n\nprocess.env.CHROME_BIN = require('puppeteer').executablePath()\n\nconst fallback = {\n  path: false,\n  url: false,\n  module: false,\n  fs: false,\n  stream: require.resolve('stream-browserify'),\n  crypto: false,\n}\n\nconst itkConfigTest = path.resolve(__dirname, 'test', 'itkConfigBrowserTest.js')\n\n// should be same as in webpack.config.js\nconst moduleConfigRules = [\n  { test: /\\.js$/, loader: 'babel-loader', dependency: { not: ['url'] } },\n  {\n    test: /\\.worker.js$/,\n    use: [{ loader: 'worker-loader', options: { inline: 'no-fallback' } }],\n  },\n  {\n    test: /\\.(png|jpg)$/,\n    type: 'asset',\n    parser: { dataUrlCondition: { maxSize: 128 * 1024 } },\n  }, // 128kb\n  { test: /\\.svg$/, type: 'asset/source' },\n].concat(vtkRules, cssRules)\n\nconst entry = path.join(__dirname, './src/index.js')\n\nmodule.exports = function init(config) {\n  config.set({\n    plugins: [\n      require('karma-webpack'),\n      require('karma-tap'),\n      require('karma-chrome-launcher'),\n      require('karma-firefox-launcher'),\n      require('karma-tap-pretty-reporter'),\n      require('karma-junit-reporter'),\n    ],\n\n    basePath: '',\n    frameworks: ['tap', 'webpack'],\n    files: [\n      './test/tests.js',\n      {\n        pattern: './dist/itk/image-io/**',\n        watched: true,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './dist/itk/mesh-io/**',\n        watched: true,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './dist/itk/web-workers/**',\n        watched: true,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './dist/itk/pipeline/**',\n        watched: true,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './test/data/**',\n        watched: false,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './test/data/**/.*',\n        watched: false,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './dist/index.html',\n        watched: true,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './dist/itkVtkViewer.js',\n        watched: true,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './src/UI/reference-ui/dist/referenceUIMachineOptions.js',\n        watched: true,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './src/UI/reference-ui/**/**',\n        watched: true,\n        served: true,\n        included: false,\n      },\n      {\n        pattern: './test/testUINoPlaneSlidersBundle.js',\n        watched: true,\n        served: true,\n        included: false,\n      },\n    ],\n\n    preprocessors: {\n      './test/tests.js': ['webpack'],\n    },\n\n    webpack: {\n      mode: 'development',\n      devtool: 'eval-source-map',\n      module: {\n        rules: moduleConfigRules.concat([\n          {\n            test: entry,\n            loader: 'expose-loader',\n            options: { exposes: 'itkVtkViewer' },\n          },\n        ]),\n      },\n      resolve: {\n        modules: [path.resolve(__dirname, 'node_modules'), sourcePath],\n        alias: {\n          '../itkConfig.js': itkConfigTest,\n          '../../itkConfig.js': itkConfigTest,\n          stream: 'stream-browserify',\n          buffer: 'buffer',\n        },\n        fallback,\n      },\n      plugins: [\n        new webpack.DefinePlugin({\n          __BASE_PATH__: \"'/base'\",\n        }),\n        new webpack.ProvidePlugin({ process: ['process/browser'] }),\n      ],\n    },\n\n    webpackMiddleware: {\n      noInfo: true,\n    },\n\n    reporters: ['tap-pretty', 'junit'],\n\n    tapReporter: {\n      outputFile: 'test/output.html',\n      separator:\n        '\\n=========================================================\\n=========================================================\\n',\n    },\n\n    junitReporter: {\n      outputDir: 'test',\n    },\n\n    client: {\n      useIframe: true,\n      args: config.dockered ? ['--dockered'] : [],\n    },\n\n    browserDisconnectTimeout: 60000,\n    browserNoActivityTimeout: 60000,\n\n    port: 9876,\n    colors: true,\n    logLevel: config.LOG_INFO,\n    autoWatch: true,\n    browsers: ['Chrome_without_sandbox'],\n    singleRun: true,\n    customLaunchers: {\n      Chrome_without_sandbox: {\n        base: 'Chrome',\n        flags: ['--no-sandbox'],\n      },\n    },\n  })\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"itk-vtk-viewer\",\n  \"version\": \"0.0.0-semantically-release\",\n  \"description\": \"Web-based image, mesh, and point set viewer\",\n  \"keywords\": [\n    \"3d\",\n    \"visualization\",\n    \"webgl\",\n    \"medical\",\n    \"scientific\",\n    \"itk\",\n    \"vtk\",\n    \"image\",\n    \"geometry\",\n    \"point cloud\",\n    \"mesh\",\n    \"gl-vis\",\n    \"volume\",\n    \"graphics\"\n  ],\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/kitware/itk-vtk-viewer.git\"\n  },\n  \"license\": \"BSD-3-Clause\",\n  \"bugs\": {\n    \"url\": \"https://github.com/kitware/itk-vtk-viewer/issues\"\n  },\n  \"homepage\": \"https://kitware.github.io/itk-vtk-viewer/\",\n  \"main\": \"./dist/itkVtkViewer.js\",\n  \"types\": \"./src/index.d.ts\",\n  \"dependencies\": {\n    \"@kitware/vtk.js\": \"^29.4.6\",\n    \"@material/web\": \"^1.0.1\",\n    \"@thewtex/iconselect.js\": \"^2.1.2\",\n    \"@xstate/inspect\": \"^0.4.1\",\n    \"axios\": \"^1.6.0\",\n    \"commander\": \"^2.20.3\",\n    \"core-js\": \"^3.36.0\",\n    \"css-element-queries\": \"^1.2.3\",\n    \"curry\": \"^1.2.0\",\n    \"eventemitter3\": \"^4.0.7\",\n    \"express\": \"^4.17.1\",\n    \"gl-matrix\": \"^3.4.3\",\n    \"itk-image-io\": \"^1.0.0-b.84\",\n    \"itk-mesh-io\": \"^1.0.0-b.84\",\n    \"itk-viewer-color-maps\": \"^1.2.0\",\n    \"itk-viewer-transfer-function-editor\": \"^1.6.0\",\n    \"itk-wasm\": \"^1.0.0-b.83\",\n    \"mobx\": \"^5.15.7\",\n    \"mousetrap\": \"^1.6.5\",\n    \"open\": \"^6.4.0\",\n    \"p-queue\": \"^7.3.0\",\n    \"promise-file-reader\": \"^1.0.3\",\n    \"promise.any\": \"^2.0.2\",\n    \"regenerator-runtime\": \"^0.13.7\",\n    \"vtk.js\": \"^29.4.6\",\n    \"webworker-promise\": \"^0.4.2\",\n    \"xstate\": \"^4.37.0\"\n  },\n  \"devDependencies\": {\n    \"@babel/plugin-proposal-class-properties\": \"^7.18.6\",\n    \"@babel/plugin-transform-runtime\": \"^7.13.6\",\n    \"@babel/preset-env\": \"^7.13.5\",\n    \"@babel/runtime\": \"^7.13.6\",\n    \"@rollup/plugin-babel\": \"^5.3.0\",\n    \"@rollup/plugin-commonjs\": \"^21.0.2\",\n    \"@rollup/plugin-node-resolve\": \"^13.0.0\",\n    \"@rollup/plugin-typescript\": \"^9.0.2\",\n    \"@web3-storage/w3\": \"^2.6.0\",\n    \"autoprefixer\": \"^10.2.6\",\n    \"babel-loader\": \"^8.2.2\",\n    \"babel-plugin-istanbul\": \"^6.0.0\",\n    \"babel-preset-mobx\": \"^2.0.0\",\n    \"buffer\": \"^6.0.3\",\n    \"copy-webpack-plugin\": \"^9.0.1\",\n    \"css-loader\": \"^5.0.2\",\n    \"es-abstract\": \"1.18.0-next.1\",\n    \"eslint\": \"^8.13.0\",\n    \"eslint-config-prettier\": \"^8.5.0\",\n    \"expose-loader\": \"^1.0.3\",\n    \"husky\": \"^4.3.7\",\n    \"imjoy-core\": \"^0.14.5\",\n    \"is-buffer\": \"^2.0.5\",\n    \"karma\": \"^6.3.16\",\n    \"karma-chrome-launcher\": \"^3.1.0\",\n    \"karma-firefox-launcher\": \"^2.1.0\",\n    \"karma-junit-reporter\": \"^2.0.1\",\n    \"karma-tap\": \"^4.2.0\",\n    \"karma-tap-pretty-reporter\": \"^4.2.0\",\n    \"karma-webpack\": \"5.0.0\",\n    \"kw-doc\": \"^3.0.6\",\n    \"lint-staged\": \"^10.5.4\",\n    \"ndarray\": \"^1.0.19\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"pixelmatch\": \"^5.2.1\",\n    \"postcss\": \"^8.3.5\",\n    \"postcss-loader\": \"^4.1.0\",\n    \"prettier\": \"^1.19.1\",\n    \"process\": \"^0.11.10\",\n    \"puppeteer\": \"^5.0.0\",\n    \"raw-loader\": \"^4.0.2\",\n    \"readable-stream\": \"^3.6.0\",\n    \"request\": \"^2.88.2\",\n    \"resemblejs\": \"^4.1.0\",\n    \"rollup\": \"^2.52.7\",\n    \"rollup-plugin-ignore\": \"^1.0.10\",\n    \"rollup-plugin-postcss\": \"^4.0.0\",\n    \"rollup-plugin-svgo\": \"^2.0.0\",\n    \"semantic-release\": \"^19.0.3\",\n    \"sockjs-client\": \"^1.5.0\",\n    \"stream-browserify\": \"^3.0.0\",\n    \"style-loader\": \"^2.0.0\",\n    \"tap-spec\": \"^5.0.0\",\n    \"tape\": \"^5.2.0\",\n    \"tape-catch\": \"^1.0.6\",\n    \"typescript\": \"^5.3.3\",\n    \"webpack\": \"^5.65.0\",\n    \"webpack-cli\": \"^4.8.0\",\n    \"webpack-dev-server\": \"^4.7.4\",\n    \"webpackbar\": \"^5.0.0-3\",\n    \"workbox-build\": \"^6.5.1\",\n    \"workbox-webpack-plugin\": \"^6.5.1\",\n    \"worker-loader\": \"^3.0.8\"\n  },\n  \"scripts\": {\n    \"doc\": \"kw-doc -c ./doc/config.js\",\n    \"doc:www\": \"kw-doc -c ./doc/config.js -s\",\n    \"doc:publish\": \"kw-doc -c ./doc/config.js -mp\",\n    \"build\": \"npm-run-all build:release build:ui\",\n    \"build:debug\": \"webpack --progress --color --mode development\",\n    \"build:release\": \"webpack --progress --color --mode production\",\n    \"build:ui\": \"node ./buildUI.js\",\n    \"build:test-ui\": \"rollup -c ./test/test-ui-rollup.config.js\",\n    \"prepack\": \"npm run build\",\n    \"bundle\": \"StandaloneHTML ./dist/index.html ./dist/ItkVtkViewer.html\",\n    \"commit\": \"git cz\",\n    \"format\": \"prettier --write src/UserInterface/**/*.js src/*.js\",\n    \"lint:types\": \"tsc --noEmit\",\n    \"start\": \"webpack serve --mode development --static ./dist/ --open --port 8082\",\n    \"dev\": \"webpack serve --mode development --static ./dist/ --port 8082\",\n    \"semantic-release\": \"semantic-release\",\n    \"test\": \"npm run test:downloadData && npm run lint:types && npm run build:test-ui && karma start ./karma.conf.js --browsers Chrome_without_sandbox,Firefox\",\n    \"test:downloadData\": \"node test/downloadData.mjs\",\n    \"test:headless\": \"./test/run.sh\",\n    \"test:headless-debug\": \"./test/run.sh -d\",\n    \"test:debug\": \"npm run build:test-ui && karma start ./karma.conf.js --no-single-run\"\n  },\n  \"config\": {\n    \"commitizen\": {\n      \"path\": \"cz-conventional-changelog\"\n    }\n  },\n  \"bin\": {\n    \"itk-vtk-viewer\": \"./bin/itk-vtk-viewer-cli.js\"\n  },\n  \"husky\": {\n    \"hooks\": {\n      \"pre-commit\": \"lint-staged\"\n    }\n  },\n  \"lint-staged\": {\n    \"*.js\": \"prettier --write\"\n  }\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "const autoprefix = require('autoprefixer');\n\nmodule.exports = {\n  plugins: [autoprefix],\n};\n"
  },
  {
    "path": "src/Compression/blosc-zarr/BloscZarr.cxx",
    "content": "#include <stdio.h>\n#include <blosc.h>\n\n#include \"itkPipeline.h\"\n#include \"itkInputBinaryStream.h\"\n#include \"itkOutputBinaryStream.h\"\n#include <fstream>\n\nint main(int argc, char * argv[]){\n\n  itk::wasm::Pipeline pipeline (\"Compress or decompress binaries with Blosc\", argc, argv);\n\n  itk::wasm::InputBinaryStream input_binary_stream;\n  pipeline.add_option(\"input-binary-stream\", input_binary_stream, \"The input binary stream\")->required();\n\n  itk::wasm::OutputBinaryStream output_binary_stream;\n  pipeline.add_option(\"output-binary-stream\", output_binary_stream, \"The output binary stream\")->required();\n\n  std::string compressor;\n  pipeline.add_option(\"compressor\", compressor, \"Blosc compressor\")->required();\n\n  size_t input_size;\n  pipeline.add_option(\"input-size\", input_size, \"Input binary size in bytes\")->required();\n\n  bool decompress = false;\n  const auto decompress_option = pipeline.add_flag(\"-d,--decompress\", decompress, \"Decompress instead of compress\");\n\n  size_t output_size = 0;\n  pipeline.add_option(\"--output-size\", output_size, \"Output binary size in bytes\")->needs(decompress_option);\n\n  int compression_level = 3;\n  pipeline.add_option(\"-c,--compression-level\", compression_level, \"Compression level in compression, 0 to 9\")->excludes(decompress_option);\n\n  size_t typesize = 1;\n  pipeline.add_option(\"--typesize\", typesize, \"Assumed type size in compression\")->excludes(decompress_option);\n\n  bool no_shuffle = false;\n  pipeline.add_flag(\"--no-shuffle\", no_shuffle, \"Do not add bitshuffle support in compression\")->excludes(decompress_option);\n\n  bool verbose = false;\n  pipeline.add_flag(\"-v,--verbose\", verbose, \"Output status information\");\n\n  ITK_WASM_PARSE(pipeline);\n\n  /* Register the filter with the library */\n  if (verbose)\n    {\n    printf(\"Blosc version info: %s (%s)\\n\", BLOSC_VERSION_STRING, BLOSC_VERSION_DATE);\n    }\n\n  /* Initialize the Blosc compressor */\n  blosc_init();\n\n  const int nthreads = 1;\n  const int pnthreads = blosc_set_nthreads(nthreads);\n  if (verbose)\n    {\n    printf(\"Using %d threads (previously using %d)\\n\", nthreads, pnthreads);\n    }\n\n  int rcode = blosc_set_compressor(compressor.c_str());\n  if (rcode < 0)\n    {\n    printf(\"Error setting %s compressor. Does it really exist?\\n\", compressor.c_str());\n    blosc_destroy();\n    return rcode;\n    }\n  if (verbose)\n    {\n    printf(\"Using %s compressor\\n\", compressor.c_str());\n    }\n\n  void * input_array = malloc(input_size);\n  if(input_array == NULL)\n    {\n    printf(\"Input memory allocation failed\\n\");\n    blosc_destroy();\n    return 1;\n    }\n  input_binary_stream.Get().read(static_cast<char *>(input_array), input_size);\n  const auto read_size = input_binary_stream.Get().gcount();\n  if(read_size != input_size)\n    {\n    printf(\"Could only read %zu bytes from input file.\\n\", read_size);\n    blosc_destroy();\n    free(input_array);\n    return 1;\n    }\n  if (!decompress)\n    {\n    output_size = input_size;\n    }\n  else if(output_size == 0)\n    {\n    blosc_destroy();\n    free(input_array);\n    CLI::Error err(\"Runtime error\", \"--output-size must be specified for decompression\", 1);\n    pipeline.exit(err);\n    return 1;\n    }\n  void * output_array = malloc(output_size + BLOSC_MAX_OVERHEAD);\n  if(output_array == NULL)\n    {\n    printf(\"Output memory allocation failed\\n\");\n    blosc_destroy();\n    free(input_array);\n    return 1;\n    }\n\n  if (!decompress)\n    {\n    if (verbose)\n      {\n      printf(\"Compression level %d\\n\", compression_level);\n      }\n    /* Compress */\n    const size_t compressed_size = blosc_compress(compression_level, !no_shuffle, typesize, input_size, input_array, output_array, output_size + BLOSC_MAX_OVERHEAD);\n    free(input_array);\n    /* After using it, destroy the Blosc environment */\n    blosc_destroy();\n    if (compressed_size < 0)\n      {\n      printf(\"Compression error. Error code: %lu\\n\", compressed_size);\n      free(output_array);\n      return compressed_size;\n      }\n\n    if (verbose)\n      {\n      printf(\"Compression: %zu -> %lu (%.1fx)\\n\", input_size, compressed_size, (1.*input_size) / compressed_size);\n      }\n\n    output_binary_stream.Get().write(static_cast<char *>(output_array), compressed_size);\n    free(output_array);\n    }\n  else\n    {\n    /* Decompress */\n    const int decompressed_size = blosc_decompress(input_array, output_array, output_size);\n    free(input_array);\n    /* After using it, destroy the Blosc environment */\n    blosc_destroy();\n    if (decompressed_size < 0)\n      {\n      printf(\"Decompression error. Error code: %d\\n\", decompressed_size);\n      free(output_array);\n      return decompressed_size;\n      }\n    output_binary_stream.Get().write(static_cast<char *>(output_array), output_size);\n    free(output_array);\n    }\n\n  return 0;\n}\n"
  },
  {
    "path": "src/Compression/blosc-zarr/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16.0)\nproject(blosc-zarr)\n\nset(BUILD_STATIC ON CACHE BOOL \"Build a static version of the blosc library.\")\nset(BUILD_SHARED OFF CACHE BOOL \"Build a shared library version of the blosc library.\")\nset(BUILD_TESTS OFF CACHE BOOL \"Build test programs form the blosc compression library\")\nset(BUILD_BENCHMARKS OFF CACHE BOOL \"Build benchmark programs form the blosc compression library\")\nif(EMSCRIPTEN OR WASI)\n  set(HAVE_THREADS OFF CACHE BOOL \"Whether we use threading\")\nendif()\nif(EMSCRIPTEN)\n  set(CMAKE_C_FLAGS \"-s STRICT=1\")\n  set(CMAKE_EXE_LINKER_FLAGS \"-s STRICT=1\")\nendif()\nadd_subdirectory(c-blosc)\n\nfind_package(ITK REQUIRED\n  COMPONENTS WebAssemblyInterface\n  )\ninclude(${ITK_USE_FILE})\n\nadd_executable(BloscZarr BloscZarr.cxx)\ntarget_link_libraries(BloscZarr PUBLIC blosc_static ${ITK_LIBRARIES})\n"
  },
  {
    "path": "src/Compression/blosc-zarr/web-build/BloscZarr.js",
    "content": "\nvar BloscZarr = (() => {\n  var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;\n  if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;\n  return (\nfunction(BloscZarr) {\n  BloscZarr = BloscZarr || {};\n\nnull;var Module=typeof BloscZarr!=\"undefined\"?BloscZarr:{};var readyPromiseResolve,readyPromiseReject;Module[\"ready\"]=new Promise(function(resolve,reject){readyPromiseResolve=resolve;readyPromiseReject=reject});var mStdout=null;var mStderr=null;Module[\"resetModuleStdout\"]=function(){mStdout=\"\"};Module[\"resetModuleStderr\"]=function(){mStderr=\"\"};Module[\"print\"]=function(text){console.log(text);mStdout+=text+\"\\n\"};Module[\"printErr\"]=function(text){console.error(text);mStderr+=text+\"\\n\"};Module[\"getModuleStdout\"]=function(){return mStdout};Module[\"getModuleStderr\"]=function(){return mStderr};var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram=\"./this.program\";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window==\"object\";var ENVIRONMENT_IS_WORKER=typeof importScripts==\"function\";var ENVIRONMENT_IS_NODE=typeof process==\"object\"&&typeof process.versions==\"object\"&&typeof process.versions.node==\"string\";var scriptDirectory=\"\";function locateFile(path){if(Module[\"locateFile\"]){return Module[\"locateFile\"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;function logExceptionOnExit(e){if(e instanceof ExitStatus)return;let toLog=e;err(\"exiting due to exception: \"+toLog)}var fs;var nodePath;var requireNodeFS;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require(\"path\").dirname(scriptDirectory)+\"/\"}else{scriptDirectory=__dirname+\"/\"}requireNodeFS=(()=>{if(!nodePath){fs=require(\"fs\");nodePath=require(\"path\")}});read_=function shell_read(filename,binary){requireNodeFS();filename=nodePath[\"normalize\"](filename);return fs.readFileSync(filename,binary?undefined:\"utf8\")};readBinary=(filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret});readAsync=((filename,onload,onerror)=>{requireNodeFS();filename=nodePath[\"normalize\"](filename);fs.readFile(filename,function(err,data){if(err)onerror(err);else onload(data.buffer)})});if(process[\"argv\"].length>1){thisProgram=process[\"argv\"][1].replace(/\\\\/g,\"/\")}arguments_=process[\"argv\"].slice(2);process[\"on\"](\"uncaughtException\",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process[\"on\"](\"unhandledRejection\",function(reason){throw reason});quit_=((status,toThrow)=>{if(keepRuntimeAlive()){process[\"exitCode\"]=status;throw toThrow}logExceptionOnExit(toThrow);process[\"exit\"](status)});Module[\"inspect\"]=function(){return\"[Emscripten Module object]\"}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!=\"undefined\"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf(\"blob:\")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,\"\").lastIndexOf(\"/\")+1)}else{scriptDirectory=\"\"}{read_=(url=>{var xhr=new XMLHttpRequest;xhr.open(\"GET\",url,false);xhr.send(null);return xhr.responseText});if(ENVIRONMENT_IS_WORKER){readBinary=(url=>{var xhr=new XMLHttpRequest;xhr.open(\"GET\",url,false);xhr.responseType=\"arraybuffer\";xhr.send(null);return new Uint8Array(xhr.response)})}readAsync=((url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open(\"GET\",url,true);xhr.responseType=\"arraybuffer\";xhr.onload=(()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()});xhr.onerror=onerror;xhr.send(null)})}setWindowTitle=(title=>document.title=title)}else{}var out=Module[\"print\"]||console.log.bind(console);var err=Module[\"printErr\"]||console.warn.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module[\"arguments\"])arguments_=Module[\"arguments\"];if(Module[\"thisProgram\"])thisProgram=Module[\"thisProgram\"];if(Module[\"quit\"])quit_=Module[\"quit\"];var wasmBinary;if(Module[\"wasmBinary\"])wasmBinary=Module[\"wasmBinary\"];var noExitRuntime=Module[\"noExitRuntime\"]||true;if(typeof WebAssembly!=\"object\"){abort(\"no native wasm support detected\")}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}function getCFunc(ident){var func=Module[\"_\"+ident];return func}function ccall(ident,returnType,argTypes,args,opts){var toC={\"string\":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==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;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);function onDone(ret){if(stack!==0)stackRestore(stack);return convertReturnValue(ret)}ret=onDone(ret);return ret}function cwrap(ident,returnType,argTypes,opts){argTypes=argTypes||[];var numericArgs=argTypes.every(function(type){return type===\"number\"});var numericRet=returnType!==\"string\";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return function(){return ccall(ident,returnType,argTypes,arguments,opts)}}var UTF8Decoder=typeof TextDecoder!=\"undefined\"?new TextDecoder(\"utf8\"):undefined;function UTF8ArrayToString(heap,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heap[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str=\"\";while(idx<endPtr){var u0=heap[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heap[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heap[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heap[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):\"\"}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}function AsciiToString(ptr){var str=\"\";while(1){var ch=HEAPU8[ptr++>>0];if(!ch)return str;str+=String.fromCharCode(ch)}}function allocateUTF8OnStack(str){var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8Array(str,HEAP8,ret,size);return ret}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i<str.length;++i){HEAP8[buffer++>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module[\"HEAP8\"]=HEAP8=new Int8Array(buf);Module[\"HEAP16\"]=HEAP16=new Int16Array(buf);Module[\"HEAP32\"]=HEAP32=new Int32Array(buf);Module[\"HEAPU8\"]=HEAPU8=new Uint8Array(buf);Module[\"HEAPU16\"]=HEAPU16=new Uint16Array(buf);Module[\"HEAPU32\"]=HEAPU32=new Uint32Array(buf);Module[\"HEAPF32\"]=HEAPF32=new Float32Array(buf);Module[\"HEAPF64\"]=HEAPF64=new Float64Array(buf)}var INITIAL_MEMORY=Module[\"INITIAL_MEMORY\"]||16777216;var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;var runtimeKeepaliveCounter=0;function keepRuntimeAlive(){return noExitRuntime||runtimeKeepaliveCounter>0}function preRun(){if(Module[\"preRun\"]){if(typeof Module[\"preRun\"]==\"function\")Module[\"preRun\"]=[Module[\"preRun\"]];while(Module[\"preRun\"].length){addOnPreRun(Module[\"preRun\"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module[\"noFSInit\"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){runtimeExited=true}function postRun(){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 addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module[\"monitorRunDependencies\"]){Module[\"monitorRunDependencies\"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module[\"monitorRunDependencies\"]){Module[\"monitorRunDependencies\"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module[\"preloadedImages\"]={};Module[\"preloadedAudios\"]={};function abort(what){{if(Module[\"onAbort\"]){Module[\"onAbort\"](what)}}what=\"Aborted(\"+what+\")\";err(what);ABORT=true;EXITSTATUS=1;what+=\". Build with -s ASSERTIONS=1 for more info.\";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix=\"data:application/octet-stream;base64,\";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith(\"file://\")}var wasmBinaryFile;wasmBinaryFile=\"BloscZarr.wasm\";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}else{throw\"both async and sync fetching of the wasm failed\"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch==\"function\"&&!isFileURI(wasmBinaryFile)){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(wasmBinaryFile)})}else{if(readAsync){return new Promise(function(resolve,reject){readAsync(wasmBinaryFile,function(response){resolve(new Uint8Array(response))},reject)})}}}return Promise.resolve().then(function(){return getBinary(wasmBinaryFile)})}function createWasm(){var info={\"a\":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module[\"asm\"]=exports;wasmMemory=Module[\"asm\"][\"u\"];updateGlobalBufferAndViews(wasmMemory.buffer);wasmTable=Module[\"asm\"][\"y\"];addOnInit(Module[\"asm\"][\"v\"]);removeRunDependency(\"wasm-instantiate\")}addRunDependency(\"wasm-instantiate\");function receiveInstantiationResult(result){receiveInstance(result[\"instance\"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(function(instance){return instance}).then(receiver,function(reason){err(\"failed to asynchronously prepare wasm: \"+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==\"function\"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==\"function\"){return fetch(wasmBinaryFile,{credentials:\"same-origin\"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiationResult,function(reason){err(\"wasm streaming compile failed: \"+reason);err(\"falling back to ArrayBuffer instantiation\");return instantiateArrayBuffer(receiveInstantiationResult)})})}else{return instantiateArrayBuffer(receiveInstantiationResult)}}if(Module[\"instantiateWasm\"]){try{var exports=Module[\"instantiateWasm\"](info,receiveInstance);return exports}catch(e){err(\"Module.instantiateWasm callback failed with error: \"+e);return false}}instantiateAsync().catch(readyPromiseReject);return{}}var tempDouble;var tempI64;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback==\"function\"){callback(Module);continue}var func=callback.func;if(typeof func==\"number\"){if(callback.arg===undefined){getWasmTableEntry(func)()}else{getWasmTableEntry(func)(callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var wasmTableMirror=[];function getWasmTableEntry(funcPtr){var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func}function handleException(e){if(e instanceof ExitStatus||e==\"unwind\"){return EXITSTATUS}quit_(1,e)}function ___cxa_allocate_exception(size){return _malloc(size+16)+16}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-16;this.set_type=function(type){HEAP32[this.ptr+4>>2]=type};this.get_type=function(){return HEAP32[this.ptr+4>>2]};this.set_destructor=function(destructor){HEAP32[this.ptr+8>>2]=destructor};this.get_destructor=function(){return HEAP32[this.ptr+8>>2]};this.set_refcount=function(refcount){HEAP32[this.ptr>>2]=refcount};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+12>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_type(type);this.set_destructor(destructor);this.set_refcount(0);this.set_caught(false);this.set_rethrown(false)};this.add_ref=function(){var value=HEAP32[this.ptr>>2];HEAP32[this.ptr>>2]=value+1};this.release_ref=function(){var prev=HEAP32[this.ptr>>2];HEAP32[this.ptr>>2]=prev-1;return prev===1}}var exceptionLast=0;var uncaughtExceptionCount=0;function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw ptr}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}var PATH={splitPath:function(filename){var splitPathRe=/^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){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(allowAboveRoot){for(;up;up--){parts.unshift(\"..\")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)===\"/\",trailingSlash=path.substr(-1)===\"/\";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){return\".\"}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path===\"/\")return\"/\";path=PATH.normalize(path);path=path.replace(/\\/$/,\"\");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)}};function getRandomDevice(){if(typeof crypto==\"object\"&&typeof crypto[\"getRandomValues\"]==\"function\"){var randomBuffer=new Uint8Array(1);return function(){crypto.getRandomValues(randomBuffer);return randomBuffer[0]}}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require(\"crypto\");return function(){return crypto_module[\"randomBytes\"](1)[0]}}catch(e){}}return function(){abort(\"randomDevice\")}}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();if(typeof path!=\"string\"){throw new TypeError(\"Arguments to path.resolve must be strings\")}else if(!path){return\"\"}resolvedPath=path+\"/\"+resolvedPath;resolvedAbsolute=path.charAt(0)===\"/\"}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(){},shutdown:function(){},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(43)}stream.tty=tty;stream.seekable=false},close:function(stream){stream.tty.ops.flush(stream.tty)},flush:function(stream){stream.tty.ops.flush(stream.tty)},read:function(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}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(29)}if(result===undefined&&bytesRead===0){throw new FS.ErrnoError(6)}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(60)}try{for(var i=0;i<length;i++){stream.tty.ops.put_char(stream.tty,buffer[offset+i])}}catch(e){throw new FS.ErrnoError(29)}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){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;try{bytesRead=fs.readSync(process.stdin.fd,buf,0,BUFSIZE,-1)}catch(e){if(e.toString().includes(\"EOF\"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString(\"utf-8\")}else{result=null}}else if(typeof window!=\"undefined\"&&typeof window.prompt==\"function\"){result=window.prompt(\"Input: \");if(result!==null){result+=\"\\n\"}}else if(typeof readline==\"function\"){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)}},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=[]}}}};function mmapAlloc(size){abort()}var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,\"/\",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}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;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();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray:function(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage:function(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity<CAPACITY_DOUBLING_MAX?2:1.125)>>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr:function(node){var attr={};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);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[44]},mknod:function(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename:function(old_node,new_dir,new_name){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(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink:function(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir:function(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},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|40960,0);node.link=oldpath;return node},readlink:function(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}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);if(size>8&&contents.subarray){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(buffer.buffer===HEAP8.buffer){canOwn=false}if(!length)return 0;var node=stream.node;node.timestamp=Date.now();if(buffer.subarray&&(!node.contents||node.contents.subarray)){if(canOwn){node.contents=buffer.subarray(offset,offset+length);node.usedBytes=length;return length}else if(node.usedBytes===0&&position===0){node.contents=buffer.slice(offset,offset+length);node.usedBytes=length;return length}else if(position+length<=node.usedBytes){node.contents.set(buffer.subarray(offset,offset+length),position);return length}}MEMFS.expandFileStorage(node,position+length);if(node.contents.subarray&&buffer.subarray){node.contents.set(buffer.subarray(offset,offset+length),position)}else{for(var i=0;i<length;i++){node.contents[position+i]=buffer[offset+i]}}node.usedBytes=Math.max(node.usedBytes,position+length);return length},llseek:function(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){position+=stream.node.usedBytes}}if(position<0){throw new FS.ErrnoError(28)}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,address,length,position,prot,flags){if(address!==0){throw new FS.ErrnoError(28)}if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr;var allocated;var contents=stream.node.contents;if(!(flags&2)&&contents.buffer===buffer){allocated=false;ptr=contents.byteOffset}else{if(position>0||position+length<contents.length){if(contents.subarray){contents=contents.subarray(position,position+length)}else{contents=Array.prototype.slice.call(contents,position,position+length)}}allocated=true;ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}HEAP8.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(43)}if(mmapFlags&2){return 0}var bytesWritten=MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};function asyncLoad(url,onload,onerror,noRunDep){var dep=!noRunDep?getUniqueRunDependency(\"al \"+url):\"\";readAsync(url,function(arrayBuffer){assert(arrayBuffer,'Loading data file \"'+url+'\" failed (no arrayBuffer).');onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},function(event){if(onerror){onerror()}else{throw'Loading data file \"'+url+'\" failed.'}});if(dep)addRunDependency(dep)}var ERRNO_CODES={};var NODEFS={isWindows:false,staticInit:()=>{NODEFS.isWindows=!!process.platform.match(/^win/);var flags=process[\"binding\"](\"constants\");if(flags[\"fs\"]){flags=flags[\"fs\"]}NODEFS.flagsForNodeMap={1024:flags[\"O_APPEND\"],64:flags[\"O_CREAT\"],128:flags[\"O_EXCL\"],256:flags[\"O_NOCTTY\"],0:flags[\"O_RDONLY\"],2:flags[\"O_RDWR\"],4096:flags[\"O_SYNC\"],512:flags[\"O_TRUNC\"],1:flags[\"O_WRONLY\"],131072:flags[\"O_NOFOLLOW\"]}},convertNodeCode:e=>{var code=e.code;return ERRNO_CODES[code]},mount:mount=>{return NODEFS.createNode(null,\"/\",NODEFS.getMode(mount.opts.root),0)},createNode:(parent,name,mode,dev)=>{if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(28)}var node=FS.createNode(parent,name,mode);node.node_ops=NODEFS.node_ops;node.stream_ops=NODEFS.stream_ops;return node},getMode:path=>{var stat;try{stat=fs.lstatSync(path);if(NODEFS.isWindows){stat.mode=stat.mode|(stat.mode&292)>>2}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}return stat.mode},realPath: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:flags=>{flags&=~2097152;flags&=~2048;flags&=~32768;flags&=~524288;flags&=~65536;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(28)}},node_ops:{getattr:node=>{var path=NODEFS.realPath(node);var stat;try{stat=fs.lstatSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}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:(node,attr)=>{var path=NODEFS.realPath(node);try{if(attr.mode!==undefined){fs.chmodSync(path,attr.mode);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(NODEFS.convertNodeCode(e))}},lookup:(parent,name)=>{var path=PATH.join2(NODEFS.realPath(parent),name);var mode=NODEFS.getMode(path);return NODEFS.createNode(parent,name,mode)},mknod:(parent,name,mode,dev)=>{var node=NODEFS.createNode(parent,name,mode,dev);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(NODEFS.convertNodeCode(e))}return node},rename:(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(NODEFS.convertNodeCode(e))}oldNode.name=newName},unlink:(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(NODEFS.convertNodeCode(e))}},rmdir:(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(NODEFS.convertNodeCode(e))}},readdir:node=>{var path=NODEFS.realPath(node);try{return fs.readdirSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},symlink:(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(NODEFS.convertNodeCode(e))}},readlink:node=>{var path=NODEFS.realPath(node);try{path=fs.readlinkSync(path);path=nodePath.relative(nodePath.resolve(node.mount.opts.root),path);return path}catch(e){if(!e.code)throw e;if(e.code===\"UNKNOWN\")throw new FS.ErrnoError(28);throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}}},stream_ops:{open: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(NODEFS.convertNodeCode(e))}},close: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(NODEFS.convertNodeCode(e))}},read:(stream,buffer,offset,length,position)=>{if(length===0)return 0;try{return fs.readSync(stream.nfd,Buffer.from(buffer.buffer),offset,length,position)}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},write:(stream,buffer,offset,length,position)=>{try{return fs.writeSync(stream.nfd,Buffer.from(buffer.buffer),offset,length,position)}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},llseek:(stream,offset,whence)=>{var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){try{var stat=fs.fstatSync(stream.nfd);position+=stat.size}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}}}if(position<0){throw new FS.ErrnoError(28)}return position},mmap:(stream,address,length,position,prot,flags)=>{if(address!==0){throw new FS.ErrnoError(28)}if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr=mmapAlloc(length);NODEFS.stream_ops.read(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(mmapFlags&2){return 0}var bytesWritten=NODEFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:\"/\",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath:(path,opts={})=>{path=PATH_FS.resolve(FS.cwd(),path);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){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split(\"/\").filter(p=>!!p),false);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){break}current=FS.lookupNode(current,parts[i]);current_path=PATH.join2(current_path,parts[i]);if(FS.isMountpoint(current)){if(!islast||islast&&opts.follow_mount){current=current.mounted.root}}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){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath: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:(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:node=>{var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode: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:(parent,name)=>{var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,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}}return FS.lookup(parent,name)},createNode:(parent,name,mode,rdev)=>{var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:node=>{FS.hashRemoveNode(node)},isRoot:node=>{return node===node.parent},isMountpoint:node=>{return!!node.mounted},isFile:mode=>{return(mode&61440)===32768},isDir:mode=>{return(mode&61440)===16384},isLink:mode=>{return(mode&61440)===40960},isChrdev:mode=>{return(mode&61440)===8192},isBlkdev:mode=>{return(mode&61440)===24576},isFIFO:mode=>{return(mode&61440)===4096},isSocket:mode=>{return(mode&49152)===49152},flagModes:{\"r\":0,\"r+\":2,\"w\":577,\"w+\":578,\"a\":1089,\"a+\":1090},modeStringToFlags:str=>{var flags=FS.flagModes[str];if(typeof flags==\"undefined\"){throw new Error(\"Unknown file open mode: \"+str)}return flags},flagsToPermissionString:flag=>{var perms=[\"r\",\"w\",\"rw\"][flag&3];if(flag&512){perms+=\"w\"}return perms},nodePermissions:(node,perms)=>{if(FS.ignorePermissions){return 0}if(perms.includes(\"r\")&&!(node.mode&292)){return 2}else if(perms.includes(\"w\")&&!(node.mode&146)){return 2}else if(perms.includes(\"x\")&&!(node.mode&73)){return 2}return 0},mayLookup:dir=>{var errCode=FS.nodePermissions(dir,\"x\");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:(dir,name)=>{try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,\"wx\")},mayDelete:(dir,name,isdir)=>{var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,\"wx\");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:(node,flags)=>{if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!==\"r\"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:(fd_start=0,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(33)},getStream:fd=>FS.streams[fd],createStream:(stream,fd_start,fd_end)=>{if(!FS.FSStream){FS.FSStream=function(){};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}}}}stream=Object.assign(new FS.FSStream,stream);var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:fd=>{FS.streams[fd]=null},chrdev_stream_ops:{open:stream=>{var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:()=>{throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice:(dev,ops)=>{FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts: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:(populate,callback)=>{if(typeof populate==\"function\"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(\"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(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:(type,opts,mountpoint)=>{var root=mountpoint===\"/\";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:mountpoint=>{var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:(parent,name)=>{return parent.node_ops.lookup(parent,name)},mknod:(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(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:(path,mode)=>{mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:(path,mode)=>{mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:(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!=20)throw e}}},mkdev:(path,mode,dev)=>{if(typeof dev==\"undefined\"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink:(oldpath,newpath)=>{if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},rename:(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);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!==\".\"){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!==\".\"){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,\"w\");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name)}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir:path=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node.node_ops.readdir){throw new FS.ErrnoError(54)}return node.node_ops.readdir(node)},unlink:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink:path=>{var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return PATH_FS.resolve(FS.getPath(link.parent),link.node_ops.readlink(link))},stat:(path,dontFollow)=>{var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;if(!node){throw new FS.ErrnoError(44)}if(!node.node_ops.getattr){throw new FS.ErrnoError(63)}return node.node_ops.getattr(node)},lstat:path=>{return FS.stat(path,true)},chmod:(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(63)}node.node_ops.setattr(node,{mode:mode&4095|node.mode&~4095,timestamp:Date.now()})},lchmod:(path,mode)=>{FS.chmod(path,mode,true)},fchmod:(fd,mode)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chmod(stream.node,mode)},chown:(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(63)}node.node_ops.setattr(node,{timestamp:Date.now()})},lchown:(path,uid,gid)=>{FS.chown(path,uid,gid,true)},fchown:(fd,uid,gid)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chown(stream.node,uid,gid)},truncate:(path,len)=>{if(len<0){throw new FS.ErrnoError(28)}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(63)}if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,\"w\");if(errCode){throw new FS.ErrnoError(errCode)}node.node_ops.setattr(node,{size:len,timestamp:Date.now()})},ftruncate:(fd,len)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.truncate(stream.node,len)},utime:(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:(path,flags,mode,fd_start,fd_end)=>{if(path===\"\"){throw new FS.ErrnoError(44)}flags=typeof flags==\"string\"?FS.modeStringToFlags(flags):flags;mode=typeof mode==\"undefined\"?438: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){}}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else{node=FS.mknod(path,mode,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node:node,path:FS.getPath(node),flags:flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false},fd_start,fd_end);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}}return stream},close:stream=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed:stream=>{return stream.fd===null},llseek:(stream,offset,whence)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read:(stream,buffer,offset,length,position)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!=\"undefined\";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write:(stream,buffer,offset,length,position,canOwn)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!=\"undefined\";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},allocate:(stream,offset,length)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(offset<0||length<=0){throw new FS.ErrnoError(28)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(!FS.isFile(stream.node.mode)&&!FS.isDir(stream.node.mode)){throw new FS.ErrnoError(43)}if(!stream.stream_ops.allocate){throw new FS.ErrnoError(138)}stream.stream_ops.allocate(stream,offset,length)},mmap:(stream,address,length,position,prot,flags)=>{if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}return stream.stream_ops.mmap(stream,address,length,position,prot,flags)},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!stream||!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},munmap:stream=>0,ioctl:(stream,cmd,arg)=>{if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile:(path,opts={})=>{opts.flags=opts.flags||0;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:(path,data,opts={})=>{opts.flags=opts.flags||577;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:()=>FS.currentPath,chdir:path=>{var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,\"x\");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories:()=>{FS.mkdir(\"/tmp\");FS.mkdir(\"/home\");FS.mkdir(\"/home/web_user\")},createDefaultDevices:()=>{FS.mkdir(\"/dev\");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev(\"/dev/null\",FS.makedev(1,3));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));var random_device=getRandomDevice();FS.createDevice(\"/dev\",\"random\",random_device);FS.createDevice(\"/dev\",\"urandom\",random_device);FS.mkdir(\"/dev/shm\");FS.mkdir(\"/dev/shm/tmp\")},createSpecialDirectories:()=>{FS.mkdir(\"/proc\");var proc_self=FS.mkdir(\"/proc/self\");FS.mkdir(\"/proc/self/fd\");FS.mount({mount:()=>{var node=FS.createNode(proc_self,\"fd\",16384|511,73);node.node_ops={lookup:(parent,name)=>{var fd=+name;var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);var ret={parent:null,mount:{mountpoint:\"fake\"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},\"/proc/self/fd\")},createStandardStreams:()=>{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\")}var stdin=FS.open(\"/dev/stdin\",0);var stdout=FS.open(\"/dev/stdout\",1);var stderr=FS.open(\"/dev/stderr\",1)},ensureErrnoError:()=>{if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message=\"FS error\"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=\"<generic error, no stack>\"})},staticInit:()=>{FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},\"/\");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={\"MEMFS\":MEMFS,\"NODEFS\":NODEFS}},init:(input,output,error)=>{FS.init.initialized=true;FS.ensureErrnoError();Module[\"stdin\"]=input||Module[\"stdin\"];Module[\"stdout\"]=output||Module[\"stdout\"];Module[\"stderr\"]=error||Module[\"stderr\"];FS.createStandardStreams()},quit:()=>{FS.init.initialized=false;for(var i=0;i<FS.streams.length;i++){var stream=FS.streams[i];if(!stream){continue}FS.close(stream)}},getMode:(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode},findObject:(path,dontResolveLastLink)=>{var ret=FS.analyzePath(path,dontResolveLastLink);if(ret.exists){return ret.object}else{return null}},analyzePath:(path,dontResolveLastLink)=>{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},createPath:(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){}parent=current}return current},createFile:(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:(parent,name,data,canRead,canWrite,canOwn)=>{var path=name;if(parent){parent=typeof parent==\"string\"?parent:FS.getPath(parent);path=name?PATH.join2(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}FS.chmod(node,mode|146);var stream=FS.open(node,577);FS.write(stream,data,0,data.length,0,canOwn);FS.close(stream);FS.chmod(node,mode)}return node},createDevice:(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);FS.registerDevice(dev,{open:stream=>{stream.seekable=false},close:stream=>{if(output&&output.buffer&&output.buffer.length){output(10)}},read:(stream,buffer,offset,length,pos)=>{var bytesRead=0;for(var i=0;i<length;i++){var result;try{result=input()}catch(e){throw new FS.ErrnoError(29)}if(result===undefined&&bytesRead===0){throw new FS.ErrnoError(6)}if(result===null||result===undefined)break;bytesRead++;buffer[offset+i]=result}if(bytesRead){stream.node.timestamp=Date.now()}return bytesRead},write:(stream,buffer,offset,length,pos)=>{for(var i=0;i<length;i++){try{output(buffer[offset+i])}catch(e){throw new FS.ErrnoError(29)}}if(length){stream.node.timestamp=Date.now()}return i}});return FS.mkdev(path,mode,dev)},forceLoadFile:obj=>{if(obj.isDevice||obj.isFolder||obj.link||obj.contents)return 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(read_){try{obj.contents=intArrayFromString(read_(obj.url),true);obj.usedBytes=obj.contents.length}catch(e){throw new FS.ErrnoError(29)}}else{throw new Error(\"Cannot load without read() or XMLHttpRequest.\")}},createLazyFile:(parent,name,url,canRead,canWrite)=>{function LazyUint8Array(){this.lengthKnown=false;this.chunks=[]}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(){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;if(!hasByteServing)chunkSize=datalength;var doXHR=(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!\");var xhr=new XMLHttpRequest;xhr.open(\"GET\",url,false);if(datalength!==chunkSize)xhr.setRequestHeader(\"Range\",\"bytes=\"+from+\"-\"+to);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(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);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){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out(\"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);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});stream_ops.read=((stream,buffer,offset,length,position)=>{FS.forceLoadFile(node);var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i<size;i++){buffer[offset+i]=contents[position+i]}}else{for(var i=0;i<size;i++){buffer[offset+i]=contents.get(position+i)}}return size});node.stream_ops=stream_ops;return node},createPreloadedFile:(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(\"cp \"+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)}if(Browser.handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url==\"string\"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}},indexedDB:()=>{return window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB},DB_NAME:()=>{return\"EM_FS_\"+window.location.pathname},DB_VERSION:20,DB_STORE_NAME:\"FILE_DATA\",saveFilesToDB:(paths,onload,onerror)=>{onload=onload||(()=>{});onerror=onerror||(()=>{});var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=(()=>{out(\"creating db\");var db=openRequest.result;db.createObjectStore(FS.DB_STORE_NAME)});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(path=>{var putRequest=files.put(FS.analyzePath(path).object.contents,path);putRequest.onsuccess=(()=>{ok++;if(ok+fail==total)finish()});putRequest.onerror=(()=>{fail++;if(ok+fail==total)finish()})});transaction.onerror=onerror});openRequest.onerror=onerror},loadFilesFromDB:(paths,onload,onerror)=>{onload=onload||(()=>{});onerror=onerror||(()=>{});var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=onerror;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(path=>{var getRequest=files.get(path);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=(()=>{fail++;if(ok+fail==total)finish()})});transaction.onerror=onerror});openRequest.onerror=onerror}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt:function(dirfd,path,allowEmpty){if(path[0]===\"/\"){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=FS.getStream(dirfd);if(!dirstream)throw new FS.ErrnoError(8);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,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))){return-54}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?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>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()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){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){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms=\"\";if(amode&4)perms+=\"r\";if(amode&2)perms+=\"w\";if(amode&1)perms+=\"x\";if(perms&&FS.nodePermissions(node,perms)){return-2}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}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:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(low,high){return low}};function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.open(stream.path,stream.flags,0,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_getcwd(buf,size){try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd);if(size<cwdLengthInBytes+1)return-68;stringToUTF8(cwd,buf,size);return buf}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:abort(\"bad ioctl syscall \"+op)}}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_open(path,flags,varargs){SYSCALLS.varargs=varargs;try{var pathname=SYSCALLS.getStr(path);var mode=varargs?SYSCALLS.get():0;var stream=FS.open(pathname,flags,mode);return stream.fd}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_readlink(path,buf,bufsize){try{path=SYSCALLS.getStr(path);return SYSCALLS.doReadlink(path,buf,bufsize)}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function _abort(){abort(\"\")}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function _emscripten_get_heap_max(){return 2147483648}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;var maxHeapSize=_emscripten_get_heap_max();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}var ENV={};function getExecutableName(){return thisProgram||\"./this.program\"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator==\"object\"&&navigator.languages&&navigator.languages[0]||\"C\").replace(\"-\",\"_\")+\".UTF-8\";var env={\"USER\":\"web_user\",\"LOGNAME\":\"web_user\",\"PATH\":\"/\",\"PWD\":\"/\",\"HOME\":\"/home/web_user\",\"LANG\":lang,\"_\":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+\"=\"+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4;HEAP8[pbuf>>0]=type;return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _fd_read(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doReadv(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var stream=SYSCALLS.getStreamFromFD(fd);var HIGH_OFFSET=4294967296;var offset=offset_high*HIGH_OFFSET+(offset_low>>>0);var DOUBLE_LIMIT=9007199254740992;if(offset<=-DOUBLE_LIMIT||offset>=DOUBLE_LIMIT){return-61}FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doWritev(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _getpwnam(){err(\"missing function: getpwnam\");abort(-1)}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()){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{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){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);var EXPANSION_RULES_1={\"%c\":\"%a %b %d %H:%M:%S %Y\",\"%D\":\"%m/%d/%y\",\"%F\":\"%Y-%m-%d\",\"%h\":\"%b\",\"%r\":\"%I:%M:%S %p\",\"%R\":\"%H:%M\",\"%T\":\"%H:%M:%S\",\"%x\":\"%m/%d/%y\",\"%X\":\"%H:%M:%S\",\"%Ec\":\"%c\",\"%EC\":\"%C\",\"%Ex\":\"%m/%d/%y\",\"%EX\":\"%H:%M:%S\",\"%Ey\":\"%y\",\"%EY\":\"%Y\",\"%Od\":\"%d\",\"%Oe\":\"%e\",\"%OH\":\"%H\",\"%OI\":\"%I\",\"%Om\":\"%m\",\"%OM\":\"%M\",\"%OS\":\"%S\",\"%Ou\":\"%u\",\"%OU\":\"%U\",\"%OV\":\"%V\",\"%Ow\":\"%w\",\"%OW\":\"%W\",\"%Oy\":\"%y\"};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:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6: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){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){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){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){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);if(compareByDay(firstSunday,endDate)<0){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){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){return\"53\"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return\"01\"}var daysDifference;if(firstWeekStartThisYear.getFullYear()<date.tm_year+1900){daysDifference=date.tm_yday+32-firstWeekStartThisYear.getDate()}else{daysDifference=date.tm_yday+1-firstWeekStartThisYear.getDate()}return leadingNulls(Math.ceil(daysDifference/7),2)},\"%w\":function(date){return date.tm_wday},\"%W\":function(date){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);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){return(date.tm_year+1900).toString().substring(2)},\"%Y\":function(date){return date.tm_year+1900},\"%z\":function(date){var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?\"+\":\"-\")+String(\"0000\"+off).slice(-4)},\"%Z\":function(date){return date.tm_zone},\"%%\":function(){return\"%\"}};pattern=pattern.replace(/%%/g,\"\\0\\0\");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,\"g\"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\\0\\0/g,\"%\");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}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};var readMode=292|73;var writeMode=146;Object.defineProperties(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)}}});FS.FSNode=FSNode;FS.staticInit();Module[\"FS_createPath\"]=FS.createPath;Module[\"FS_createDataFile\"]=FS.createDataFile;Module[\"FS_createPreloadedFile\"]=FS.createPreloadedFile;Module[\"FS_createLazyFile\"]=FS.createLazyFile;Module[\"FS_createDevice\"]=FS.createDevice;Module[\"FS_unlink\"]=FS.unlink;if(ENVIRONMENT_IS_NODE){requireNodeFS();NODEFS.staticInit()}ERRNO_CODES={\"EPERM\":63,\"ENOENT\":44,\"ESRCH\":71,\"EINTR\":27,\"EIO\":29,\"ENXIO\":60,\"E2BIG\":1,\"ENOEXEC\":45,\"EBADF\":8,\"ECHILD\":12,\"EAGAIN\":6,\"EWOULDBLOCK\":6,\"ENOMEM\":48,\"EACCES\":2,\"EFAULT\":21,\"ENOTBLK\":105,\"EBUSY\":10,\"EEXIST\":20,\"EXDEV\":75,\"ENODEV\":43,\"ENOTDIR\":54,\"EISDIR\":31,\"EINVAL\":28,\"ENFILE\":41,\"EMFILE\":33,\"ENOTTY\":59,\"ETXTBSY\":74,\"EFBIG\":22,\"ENOSPC\":51,\"ESPIPE\":70,\"EROFS\":69,\"EMLINK\":34,\"EPIPE\":64,\"EDOM\":18,\"ERANGE\":68,\"ENOMSG\":49,\"EIDRM\":24,\"ECHRNG\":106,\"EL2NSYNC\":156,\"EL3HLT\":107,\"EL3RST\":108,\"ELNRNG\":109,\"EUNATCH\":110,\"ENOCSI\":111,\"EL2HLT\":112,\"EDEADLK\":16,\"ENOLCK\":46,\"EBADE\":113,\"EBADR\":114,\"EXFULL\":115,\"ENOANO\":104,\"EBADRQC\":103,\"EBADSLT\":102,\"EDEADLOCK\":16,\"EBFONT\":101,\"ENOSTR\":100,\"ENODATA\":116,\"ETIME\":117,\"ENOSR\":118,\"ENONET\":119,\"ENOPKG\":120,\"EREMOTE\":121,\"ENOLINK\":47,\"EADV\":122,\"ESRMNT\":123,\"ECOMM\":124,\"EPROTO\":65,\"EMULTIHOP\":36,\"EDOTDOT\":125,\"EBADMSG\":9,\"ENOTUNIQ\":126,\"EBADFD\":127,\"EREMCHG\":128,\"ELIBACC\":129,\"ELIBBAD\":130,\"ELIBSCN\":131,\"ELIBMAX\":132,\"ELIBEXEC\":133,\"ENOSYS\":52,\"ENOTEMPTY\":55,\"ENAMETOOLONG\":37,\"ELOOP\":32,\"EOPNOTSUPP\":138,\"EPFNOSUPPORT\":139,\"ECONNRESET\":15,\"ENOBUFS\":42,\"EAFNOSUPPORT\":5,\"EPROTOTYPE\":67,\"ENOTSOCK\":57,\"ENOPROTOOPT\":50,\"ESHUTDOWN\":140,\"ECONNREFUSED\":14,\"EADDRINUSE\":3,\"ECONNABORTED\":13,\"ENETUNREACH\":40,\"ENETDOWN\":38,\"ETIMEDOUT\":73,\"EHOSTDOWN\":142,\"EHOSTUNREACH\":23,\"EINPROGRESS\":26,\"EALREADY\":7,\"EDESTADDRREQ\":17,\"EMSGSIZE\":35,\"EPROTONOSUPPORT\":66,\"ESOCKTNOSUPPORT\":137,\"EADDRNOTAVAIL\":4,\"ENETRESET\":39,\"EISCONN\":30,\"ENOTCONN\":53,\"ETOOMANYREFS\":141,\"EUSERS\":136,\"EDQUOT\":19,\"ESTALE\":72,\"ENOTSUP\":138,\"ENOMEDIUM\":148,\"EILSEQ\":25,\"EOVERFLOW\":61,\"ECANCELED\":11,\"ENOTRECOVERABLE\":56,\"EOWNERDEAD\":62,\"ESTRPIPE\":135};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}var asmLibraryArg={\"a\":___cxa_allocate_exception,\"b\":___cxa_throw,\"e\":___syscall_fcntl64,\"t\":___syscall_getcwd,\"j\":___syscall_ioctl,\"k\":___syscall_open,\"o\":___syscall_readlink,\"p\":___syscall_stat64,\"c\":_abort,\"l\":_emscripten_memcpy_big,\"d\":_emscripten_resize_heap,\"r\":_environ_get,\"s\":_environ_sizes_get,\"f\":_fd_close,\"q\":_fd_fdstat_get,\"i\":_fd_read,\"m\":_fd_seek,\"h\":_fd_write,\"g\":_getpwnam,\"n\":_strftime_l};var asm=createWasm();var ___wasm_call_ctors=Module[\"___wasm_call_ctors\"]=function(){return(___wasm_call_ctors=Module[\"___wasm_call_ctors\"]=Module[\"asm\"][\"v\"]).apply(null,arguments)};var _main=Module[\"_main\"]=function(){return(_main=Module[\"_main\"]=Module[\"asm\"][\"w\"]).apply(null,arguments)};var _malloc=Module[\"_malloc\"]=function(){return(_malloc=Module[\"_malloc\"]=Module[\"asm\"][\"x\"]).apply(null,arguments)};var _itk_wasm_input_array_alloc=Module[\"_itk_wasm_input_array_alloc\"]=function(){return(_itk_wasm_input_array_alloc=Module[\"_itk_wasm_input_array_alloc\"]=Module[\"asm\"][\"z\"]).apply(null,arguments)};var _itk_wasm_input_json_alloc=Module[\"_itk_wasm_input_json_alloc\"]=function(){return(_itk_wasm_input_json_alloc=Module[\"_itk_wasm_input_json_alloc\"]=Module[\"asm\"][\"A\"]).apply(null,arguments)};var _itk_wasm_output_json_address=Module[\"_itk_wasm_output_json_address\"]=function(){return(_itk_wasm_output_json_address=Module[\"_itk_wasm_output_json_address\"]=Module[\"asm\"][\"B\"]).apply(null,arguments)};var _itk_wasm_output_json_size=Module[\"_itk_wasm_output_json_size\"]=function(){return(_itk_wasm_output_json_size=Module[\"_itk_wasm_output_json_size\"]=Module[\"asm\"][\"C\"]).apply(null,arguments)};var _itk_wasm_output_array_address=Module[\"_itk_wasm_output_array_address\"]=function(){return(_itk_wasm_output_array_address=Module[\"_itk_wasm_output_array_address\"]=Module[\"asm\"][\"D\"]).apply(null,arguments)};var _itk_wasm_output_array_size=Module[\"_itk_wasm_output_array_size\"]=function(){return(_itk_wasm_output_array_size=Module[\"_itk_wasm_output_array_size\"]=Module[\"asm\"][\"E\"]).apply(null,arguments)};var _itk_wasm_free_all=Module[\"_itk_wasm_free_all\"]=function(){return(_itk_wasm_free_all=Module[\"_itk_wasm_free_all\"]=Module[\"asm\"][\"F\"]).apply(null,arguments)};var ___errno_location=Module[\"___errno_location\"]=function(){return(___errno_location=Module[\"___errno_location\"]=Module[\"asm\"][\"G\"]).apply(null,arguments)};var stackSave=Module[\"stackSave\"]=function(){return(stackSave=Module[\"stackSave\"]=Module[\"asm\"][\"H\"]).apply(null,arguments)};var stackRestore=Module[\"stackRestore\"]=function(){return(stackRestore=Module[\"stackRestore\"]=Module[\"asm\"][\"I\"]).apply(null,arguments)};var stackAlloc=Module[\"stackAlloc\"]=function(){return(stackAlloc=Module[\"stackAlloc\"]=Module[\"asm\"][\"J\"]).apply(null,arguments)};Module[\"ccall\"]=ccall;Module[\"cwrap\"]=cwrap;Module[\"writeArrayToMemory\"]=writeArrayToMemory;Module[\"writeAsciiToMemory\"]=writeAsciiToMemory;Module[\"addRunDependency\"]=addRunDependency;Module[\"removeRunDependency\"]=removeRunDependency;Module[\"FS_createPath\"]=FS.createPath;Module[\"FS_createDataFile\"]=FS.createDataFile;Module[\"FS_createPreloadedFile\"]=FS.createPreloadedFile;Module[\"FS_createLazyFile\"]=FS.createLazyFile;Module[\"FS_createDevice\"]=FS.createDevice;Module[\"FS_unlink\"]=FS.unlink;Module[\"callMain\"]=callMain;Module[\"AsciiToString\"]=AsciiToString;var calledRun;function ExitStatus(status){this.name=\"ExitStatus\";this.message=\"Program terminated with exit(\"+status+\")\";this.status=status}var calledMain=false;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args){var entryFunction=Module[\"_main\"];args=args||[];var argc=args.length+1;var argv=stackAlloc((argc+1)*4);HEAP32[argv>>2]=allocateUTF8OnStack(thisProgram);for(var i=1;i<argc;i++){HEAP32[(argv>>2)+i]=allocateUTF8OnStack(args[i-1])}HEAP32[(argv>>2)+argc]=0;try{var ret=entryFunction(argc,argv);exit(ret,true);return ret}catch(e){return handleException(e)}finally{calledMain=true}}function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module[\"calledRun\"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module[\"onRuntimeInitialized\"])Module[\"onRuntimeInitialized\"]();if(shouldRunNow)callMain(args);postRun()}if(Module[\"setStatus\"]){Module[\"setStatus\"](\"Running...\");setTimeout(function(){setTimeout(function(){Module[\"setStatus\"](\"\")},1);doRun()},1)}else{doRun()}}Module[\"run\"]=run;function exit(status,implicit){EXITSTATUS=status;if(keepRuntimeAlive()){}else{exitRuntime()}procExit(status)}function procExit(code){EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module[\"onExit\"])Module[\"onExit\"](code);ABORT=true}quit_(code,new ExitStatus(code))}if(Module[\"preInit\"]){if(typeof Module[\"preInit\"]==\"function\")Module[\"preInit\"]=[Module[\"preInit\"]];while(Module[\"preInit\"].length>0){Module[\"preInit\"].pop()()}}var shouldRunNow=false;if(Module[\"noInitialRun\"])shouldRunNow=false;run();Module.mountContainingDir=function(filePath){if(!ENVIRONMENT_IS_NODE){return}var path=require(\"path\");var containingDir=path.dirname(filePath);if(FS.isDir(containingDir)||containingDir===\"/\"){return}var currentDir=\"/\";var splitContainingDir=containingDir.split(path.sep);for(var ii=1;ii<splitContainingDir.length;ii++){currentDir+=splitContainingDir[ii];if(!FS.analyzePath(currentDir).exists){FS.mkdir(currentDir)}currentDir+=\"/\"}FS.mount(NODEFS,{root:containingDir},currentDir);return currentDir+path.basename(filePath)};Module.unmountContainingDir=function(filePath){if(!ENVIRONMENT_IS_NODE){return}var path=require(\"path\");var containingDir=path.dirname(filePath);FS.unmount(containingDir)};Module.fs_mkdirs=function(dirs){var currentDir=\"/\";var splitDirs=dirs.split(\"/\");for(var ii=1;ii<splitDirs.length;++ii){currentDir+=splitDirs[ii];if(!FS.analyzePath(currentDir).exists){FS.mkdir(currentDir)}currentDir+=\"/\"}};Module.fs_readFile=function(path,opts){return FS.readFile(path,opts)};Module.fs_writeFile=function(path,data,opts){return FS.writeFile(path,data,opts)};Module.fs_unlink=function(path){return FS.unlink(path)};Module.fs_open=function(path,flags,mode){return FS.open(path,flags,mode)};Module.fs_stat=function(path){return FS.stat(path)};Module.fs_read=function(stream,buffer,offset,length,position){return FS.read(stream,buffer,offset,length,position)};Module.fs_close=function(stream){return FS.close(stream)};\n\n\n  return BloscZarr.ready\n}\n);\n})();\nexport default BloscZarr;"
  },
  {
    "path": "src/Compression/blosc-zarr/web-build/BloscZarr.umd.js",
    "content": "\nvar BloscZarr = (() => {\n  var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;\n  if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;\n  return (\nfunction(BloscZarr) {\n  BloscZarr = BloscZarr || {};\n\nnull;var Module=typeof BloscZarr!=\"undefined\"?BloscZarr:{};var readyPromiseResolve,readyPromiseReject;Module[\"ready\"]=new Promise(function(resolve,reject){readyPromiseResolve=resolve;readyPromiseReject=reject});var mStdout=null;var mStderr=null;Module[\"resetModuleStdout\"]=function(){mStdout=\"\"};Module[\"resetModuleStderr\"]=function(){mStderr=\"\"};Module[\"print\"]=function(text){console.log(text);mStdout+=text+\"\\n\"};Module[\"printErr\"]=function(text){console.error(text);mStderr+=text+\"\\n\"};Module[\"getModuleStdout\"]=function(){return mStdout};Module[\"getModuleStderr\"]=function(){return mStderr};var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram=\"./this.program\";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window==\"object\";var ENVIRONMENT_IS_WORKER=typeof importScripts==\"function\";var ENVIRONMENT_IS_NODE=typeof process==\"object\"&&typeof process.versions==\"object\"&&typeof process.versions.node==\"string\";var scriptDirectory=\"\";function locateFile(path){if(Module[\"locateFile\"]){return Module[\"locateFile\"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;function logExceptionOnExit(e){if(e instanceof ExitStatus)return;let toLog=e;err(\"exiting due to exception: \"+toLog)}var fs;var nodePath;var requireNodeFS;if(ENVIRONMENT_IS_NODE){if(ENVIRONMENT_IS_WORKER){scriptDirectory=require(\"path\").dirname(scriptDirectory)+\"/\"}else{scriptDirectory=__dirname+\"/\"}requireNodeFS=(()=>{if(!nodePath){fs=require(\"fs\");nodePath=require(\"path\")}});read_=function shell_read(filename,binary){requireNodeFS();filename=nodePath[\"normalize\"](filename);return fs.readFileSync(filename,binary?undefined:\"utf8\")};readBinary=(filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret});readAsync=((filename,onload,onerror)=>{requireNodeFS();filename=nodePath[\"normalize\"](filename);fs.readFile(filename,function(err,data){if(err)onerror(err);else onload(data.buffer)})});if(process[\"argv\"].length>1){thisProgram=process[\"argv\"][1].replace(/\\\\/g,\"/\")}arguments_=process[\"argv\"].slice(2);process[\"on\"](\"uncaughtException\",function(ex){if(!(ex instanceof ExitStatus)){throw ex}});process[\"on\"](\"unhandledRejection\",function(reason){throw reason});quit_=((status,toThrow)=>{if(keepRuntimeAlive()){process[\"exitCode\"]=status;throw toThrow}logExceptionOnExit(toThrow);process[\"exit\"](status)});Module[\"inspect\"]=function(){return\"[Emscripten Module object]\"}}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!=\"undefined\"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf(\"blob:\")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,\"\").lastIndexOf(\"/\")+1)}else{scriptDirectory=\"\"}{read_=(url=>{var xhr=new XMLHttpRequest;xhr.open(\"GET\",url,false);xhr.send(null);return xhr.responseText});if(ENVIRONMENT_IS_WORKER){readBinary=(url=>{var xhr=new XMLHttpRequest;xhr.open(\"GET\",url,false);xhr.responseType=\"arraybuffer\";xhr.send(null);return new Uint8Array(xhr.response)})}readAsync=((url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open(\"GET\",url,true);xhr.responseType=\"arraybuffer\";xhr.onload=(()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()});xhr.onerror=onerror;xhr.send(null)})}setWindowTitle=(title=>document.title=title)}else{}var out=Module[\"print\"]||console.log.bind(console);var err=Module[\"printErr\"]||console.warn.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module[\"arguments\"])arguments_=Module[\"arguments\"];if(Module[\"thisProgram\"])thisProgram=Module[\"thisProgram\"];if(Module[\"quit\"])quit_=Module[\"quit\"];var wasmBinary;if(Module[\"wasmBinary\"])wasmBinary=Module[\"wasmBinary\"];var noExitRuntime=Module[\"noExitRuntime\"]||true;if(typeof WebAssembly!=\"object\"){abort(\"no native wasm support detected\")}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}function getCFunc(ident){var func=Module[\"_\"+ident];return func}function ccall(ident,returnType,argTypes,args,opts){var toC={\"string\":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==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;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);function onDone(ret){if(stack!==0)stackRestore(stack);return convertReturnValue(ret)}ret=onDone(ret);return ret}function cwrap(ident,returnType,argTypes,opts){argTypes=argTypes||[];var numericArgs=argTypes.every(function(type){return type===\"number\"});var numericRet=returnType!==\"string\";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return function(){return ccall(ident,returnType,argTypes,arguments,opts)}}var UTF8Decoder=typeof TextDecoder!=\"undefined\"?new TextDecoder(\"utf8\"):undefined;function UTF8ArrayToString(heap,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heap[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heap.subarray&&UTF8Decoder){return UTF8Decoder.decode(heap.subarray(idx,endPtr))}else{var str=\"\";while(idx<endPtr){var u0=heap[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heap[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heap[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heap[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):\"\"}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}function AsciiToString(ptr){var str=\"\";while(1){var ch=HEAPU8[ptr++>>0];if(!ch)return str;str+=String.fromCharCode(ch)}}function allocateUTF8OnStack(str){var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8Array(str,HEAP8,ret,size);return ret}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i<str.length;++i){HEAP8[buffer++>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}function alignUp(x,multiple){if(x%multiple>0){x+=multiple-x%multiple}return x}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module[\"HEAP8\"]=HEAP8=new Int8Array(buf);Module[\"HEAP16\"]=HEAP16=new Int16Array(buf);Module[\"HEAP32\"]=HEAP32=new Int32Array(buf);Module[\"HEAPU8\"]=HEAPU8=new Uint8Array(buf);Module[\"HEAPU16\"]=HEAPU16=new Uint16Array(buf);Module[\"HEAPU32\"]=HEAPU32=new Uint32Array(buf);Module[\"HEAPF32\"]=HEAPF32=new Float32Array(buf);Module[\"HEAPF64\"]=HEAPF64=new Float64Array(buf)}var INITIAL_MEMORY=Module[\"INITIAL_MEMORY\"]||16777216;var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;var runtimeKeepaliveCounter=0;function keepRuntimeAlive(){return noExitRuntime||runtimeKeepaliveCounter>0}function preRun(){if(Module[\"preRun\"]){if(typeof Module[\"preRun\"]==\"function\")Module[\"preRun\"]=[Module[\"preRun\"]];while(Module[\"preRun\"].length){addOnPreRun(Module[\"preRun\"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module[\"noFSInit\"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){runtimeExited=true}function postRun(){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 addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module[\"monitorRunDependencies\"]){Module[\"monitorRunDependencies\"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module[\"monitorRunDependencies\"]){Module[\"monitorRunDependencies\"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}Module[\"preloadedImages\"]={};Module[\"preloadedAudios\"]={};function abort(what){{if(Module[\"onAbort\"]){Module[\"onAbort\"](what)}}what=\"Aborted(\"+what+\")\";err(what);ABORT=true;EXITSTATUS=1;what+=\". Build with -s ASSERTIONS=1 for more info.\";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix=\"data:application/octet-stream;base64,\";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith(\"file://\")}var wasmBinaryFile;wasmBinaryFile=\"BloscZarr.umd.wasm\";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}else{throw\"both async and sync fetching of the wasm failed\"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch==\"function\"&&!isFileURI(wasmBinaryFile)){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(wasmBinaryFile)})}else{if(readAsync){return new Promise(function(resolve,reject){readAsync(wasmBinaryFile,function(response){resolve(new Uint8Array(response))},reject)})}}}return Promise.resolve().then(function(){return getBinary(wasmBinaryFile)})}function createWasm(){var info={\"a\":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module[\"asm\"]=exports;wasmMemory=Module[\"asm\"][\"u\"];updateGlobalBufferAndViews(wasmMemory.buffer);wasmTable=Module[\"asm\"][\"y\"];addOnInit(Module[\"asm\"][\"v\"]);removeRunDependency(\"wasm-instantiate\")}addRunDependency(\"wasm-instantiate\");function receiveInstantiationResult(result){receiveInstance(result[\"instance\"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(function(instance){return instance}).then(receiver,function(reason){err(\"failed to asynchronously prepare wasm: \"+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming==\"function\"&&!isDataURI(wasmBinaryFile)&&!isFileURI(wasmBinaryFile)&&typeof fetch==\"function\"){return fetch(wasmBinaryFile,{credentials:\"same-origin\"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiationResult,function(reason){err(\"wasm streaming compile failed: \"+reason);err(\"falling back to ArrayBuffer instantiation\");return instantiateArrayBuffer(receiveInstantiationResult)})})}else{return instantiateArrayBuffer(receiveInstantiationResult)}}if(Module[\"instantiateWasm\"]){try{var exports=Module[\"instantiateWasm\"](info,receiveInstance);return exports}catch(e){err(\"Module.instantiateWasm callback failed with error: \"+e);return false}}instantiateAsync().catch(readyPromiseReject);return{}}var tempDouble;var tempI64;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback==\"function\"){callback(Module);continue}var func=callback.func;if(typeof func==\"number\"){if(callback.arg===undefined){getWasmTableEntry(func)()}else{getWasmTableEntry(func)(callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}var wasmTableMirror=[];function getWasmTableEntry(funcPtr){var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func}function handleException(e){if(e instanceof ExitStatus||e==\"unwind\"){return EXITSTATUS}quit_(1,e)}function ___cxa_allocate_exception(size){return _malloc(size+16)+16}function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-16;this.set_type=function(type){HEAP32[this.ptr+4>>2]=type};this.get_type=function(){return HEAP32[this.ptr+4>>2]};this.set_destructor=function(destructor){HEAP32[this.ptr+8>>2]=destructor};this.get_destructor=function(){return HEAP32[this.ptr+8>>2]};this.set_refcount=function(refcount){HEAP32[this.ptr>>2]=refcount};this.set_caught=function(caught){caught=caught?1:0;HEAP8[this.ptr+12>>0]=caught};this.get_caught=function(){return HEAP8[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return HEAP8[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_type(type);this.set_destructor(destructor);this.set_refcount(0);this.set_caught(false);this.set_rethrown(false)};this.add_ref=function(){var value=HEAP32[this.ptr>>2];HEAP32[this.ptr>>2]=value+1};this.release_ref=function(){var prev=HEAP32[this.ptr>>2];HEAP32[this.ptr>>2]=prev-1;return prev===1}}var exceptionLast=0;var uncaughtExceptionCount=0;function ___cxa_throw(ptr,type,destructor){var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw ptr}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}var PATH={splitPath:function(filename){var splitPathRe=/^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:function(parts,allowAboveRoot){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(allowAboveRoot){for(;up;up--){parts.unshift(\"..\")}}return parts},normalize:function(path){var isAbsolute=path.charAt(0)===\"/\",trailingSlash=path.substr(-1)===\"/\";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){return\".\"}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:function(path){if(path===\"/\")return\"/\";path=PATH.normalize(path);path=path.replace(/\\/$/,\"\");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)}};function getRandomDevice(){if(typeof crypto==\"object\"&&typeof crypto[\"getRandomValues\"]==\"function\"){var randomBuffer=new Uint8Array(1);return function(){crypto.getRandomValues(randomBuffer);return randomBuffer[0]}}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require(\"crypto\");return function(){return crypto_module[\"randomBytes\"](1)[0]}}catch(e){}}return function(){abort(\"randomDevice\")}}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();if(typeof path!=\"string\"){throw new TypeError(\"Arguments to path.resolve must be strings\")}else if(!path){return\"\"}resolvedPath=path+\"/\"+resolvedPath;resolvedAbsolute=path.charAt(0)===\"/\"}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(){},shutdown:function(){},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(43)}stream.tty=tty;stream.seekable=false},close:function(stream){stream.tty.ops.flush(stream.tty)},flush:function(stream){stream.tty.ops.flush(stream.tty)},read:function(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}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(29)}if(result===undefined&&bytesRead===0){throw new FS.ErrnoError(6)}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(60)}try{for(var i=0;i<length;i++){stream.tty.ops.put_char(stream.tty,buffer[offset+i])}}catch(e){throw new FS.ErrnoError(29)}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){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;try{bytesRead=fs.readSync(process.stdin.fd,buf,0,BUFSIZE,-1)}catch(e){if(e.toString().includes(\"EOF\"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString(\"utf-8\")}else{result=null}}else if(typeof window!=\"undefined\"&&typeof window.prompt==\"function\"){result=window.prompt(\"Input: \");if(result!==null){result+=\"\\n\"}}else if(typeof readline==\"function\"){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)}},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=[]}}}};function mmapAlloc(size){abort()}var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,\"/\",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}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;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();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray:function(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage:function(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity<CAPACITY_DOUBLING_MAX?2:1.125)>>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr:function(node){var attr={};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);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[44]},mknod:function(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename:function(old_node,new_dir,new_name){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(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink:function(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir:function(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},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|40960,0);node.link=oldpath;return node},readlink:function(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}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);if(size>8&&contents.subarray){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(buffer.buffer===HEAP8.buffer){canOwn=false}if(!length)return 0;var node=stream.node;node.timestamp=Date.now();if(buffer.subarray&&(!node.contents||node.contents.subarray)){if(canOwn){node.contents=buffer.subarray(offset,offset+length);node.usedBytes=length;return length}else if(node.usedBytes===0&&position===0){node.contents=buffer.slice(offset,offset+length);node.usedBytes=length;return length}else if(position+length<=node.usedBytes){node.contents.set(buffer.subarray(offset,offset+length),position);return length}}MEMFS.expandFileStorage(node,position+length);if(node.contents.subarray&&buffer.subarray){node.contents.set(buffer.subarray(offset,offset+length),position)}else{for(var i=0;i<length;i++){node.contents[position+i]=buffer[offset+i]}}node.usedBytes=Math.max(node.usedBytes,position+length);return length},llseek:function(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){position+=stream.node.usedBytes}}if(position<0){throw new FS.ErrnoError(28)}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,address,length,position,prot,flags){if(address!==0){throw new FS.ErrnoError(28)}if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr;var allocated;var contents=stream.node.contents;if(!(flags&2)&&contents.buffer===buffer){allocated=false;ptr=contents.byteOffset}else{if(position>0||position+length<contents.length){if(contents.subarray){contents=contents.subarray(position,position+length)}else{contents=Array.prototype.slice.call(contents,position,position+length)}}allocated=true;ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}HEAP8.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(43)}if(mmapFlags&2){return 0}var bytesWritten=MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};function asyncLoad(url,onload,onerror,noRunDep){var dep=!noRunDep?getUniqueRunDependency(\"al \"+url):\"\";readAsync(url,function(arrayBuffer){assert(arrayBuffer,'Loading data file \"'+url+'\" failed (no arrayBuffer).');onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},function(event){if(onerror){onerror()}else{throw'Loading data file \"'+url+'\" failed.'}});if(dep)addRunDependency(dep)}var ERRNO_CODES={};var NODEFS={isWindows:false,staticInit:()=>{NODEFS.isWindows=!!process.platform.match(/^win/);var flags=process[\"binding\"](\"constants\");if(flags[\"fs\"]){flags=flags[\"fs\"]}NODEFS.flagsForNodeMap={1024:flags[\"O_APPEND\"],64:flags[\"O_CREAT\"],128:flags[\"O_EXCL\"],256:flags[\"O_NOCTTY\"],0:flags[\"O_RDONLY\"],2:flags[\"O_RDWR\"],4096:flags[\"O_SYNC\"],512:flags[\"O_TRUNC\"],1:flags[\"O_WRONLY\"],131072:flags[\"O_NOFOLLOW\"]}},convertNodeCode:e=>{var code=e.code;return ERRNO_CODES[code]},mount:mount=>{return NODEFS.createNode(null,\"/\",NODEFS.getMode(mount.opts.root),0)},createNode:(parent,name,mode,dev)=>{if(!FS.isDir(mode)&&!FS.isFile(mode)&&!FS.isLink(mode)){throw new FS.ErrnoError(28)}var node=FS.createNode(parent,name,mode);node.node_ops=NODEFS.node_ops;node.stream_ops=NODEFS.stream_ops;return node},getMode:path=>{var stat;try{stat=fs.lstatSync(path);if(NODEFS.isWindows){stat.mode=stat.mode|(stat.mode&292)>>2}}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}return stat.mode},realPath: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:flags=>{flags&=~2097152;flags&=~2048;flags&=~32768;flags&=~524288;flags&=~65536;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(28)}},node_ops:{getattr:node=>{var path=NODEFS.realPath(node);var stat;try{stat=fs.lstatSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}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:(node,attr)=>{var path=NODEFS.realPath(node);try{if(attr.mode!==undefined){fs.chmodSync(path,attr.mode);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(NODEFS.convertNodeCode(e))}},lookup:(parent,name)=>{var path=PATH.join2(NODEFS.realPath(parent),name);var mode=NODEFS.getMode(path);return NODEFS.createNode(parent,name,mode)},mknod:(parent,name,mode,dev)=>{var node=NODEFS.createNode(parent,name,mode,dev);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(NODEFS.convertNodeCode(e))}return node},rename:(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(NODEFS.convertNodeCode(e))}oldNode.name=newName},unlink:(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(NODEFS.convertNodeCode(e))}},rmdir:(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(NODEFS.convertNodeCode(e))}},readdir:node=>{var path=NODEFS.realPath(node);try{return fs.readdirSync(path)}catch(e){if(!e.code)throw e;throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},symlink:(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(NODEFS.convertNodeCode(e))}},readlink:node=>{var path=NODEFS.realPath(node);try{path=fs.readlinkSync(path);path=nodePath.relative(nodePath.resolve(node.mount.opts.root),path);return path}catch(e){if(!e.code)throw e;if(e.code===\"UNKNOWN\")throw new FS.ErrnoError(28);throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}}},stream_ops:{open: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(NODEFS.convertNodeCode(e))}},close: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(NODEFS.convertNodeCode(e))}},read:(stream,buffer,offset,length,position)=>{if(length===0)return 0;try{return fs.readSync(stream.nfd,Buffer.from(buffer.buffer),offset,length,position)}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},write:(stream,buffer,offset,length,position)=>{try{return fs.writeSync(stream.nfd,Buffer.from(buffer.buffer),offset,length,position)}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}},llseek:(stream,offset,whence)=>{var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){try{var stat=fs.fstatSync(stream.nfd);position+=stat.size}catch(e){throw new FS.ErrnoError(NODEFS.convertNodeCode(e))}}}if(position<0){throw new FS.ErrnoError(28)}return position},mmap:(stream,address,length,position,prot,flags)=>{if(address!==0){throw new FS.ErrnoError(28)}if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr=mmapAlloc(length);NODEFS.stream_ops.read(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(mmapFlags&2){return 0}var bytesWritten=NODEFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:\"/\",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath:(path,opts={})=>{path=PATH_FS.resolve(FS.cwd(),path);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){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split(\"/\").filter(p=>!!p),false);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){break}current=FS.lookupNode(current,parts[i]);current_path=PATH.join2(current_path,parts[i]);if(FS.isMountpoint(current)){if(!islast||islast&&opts.follow_mount){current=current.mounted.root}}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){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath: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:(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:node=>{var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode: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:(parent,name)=>{var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,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}}return FS.lookup(parent,name)},createNode:(parent,name,mode,rdev)=>{var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:node=>{FS.hashRemoveNode(node)},isRoot:node=>{return node===node.parent},isMountpoint:node=>{return!!node.mounted},isFile:mode=>{return(mode&61440)===32768},isDir:mode=>{return(mode&61440)===16384},isLink:mode=>{return(mode&61440)===40960},isChrdev:mode=>{return(mode&61440)===8192},isBlkdev:mode=>{return(mode&61440)===24576},isFIFO:mode=>{return(mode&61440)===4096},isSocket:mode=>{return(mode&49152)===49152},flagModes:{\"r\":0,\"r+\":2,\"w\":577,\"w+\":578,\"a\":1089,\"a+\":1090},modeStringToFlags:str=>{var flags=FS.flagModes[str];if(typeof flags==\"undefined\"){throw new Error(\"Unknown file open mode: \"+str)}return flags},flagsToPermissionString:flag=>{var perms=[\"r\",\"w\",\"rw\"][flag&3];if(flag&512){perms+=\"w\"}return perms},nodePermissions:(node,perms)=>{if(FS.ignorePermissions){return 0}if(perms.includes(\"r\")&&!(node.mode&292)){return 2}else if(perms.includes(\"w\")&&!(node.mode&146)){return 2}else if(perms.includes(\"x\")&&!(node.mode&73)){return 2}return 0},mayLookup:dir=>{var errCode=FS.nodePermissions(dir,\"x\");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:(dir,name)=>{try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,\"wx\")},mayDelete:(dir,name,isdir)=>{var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,\"wx\");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:(node,flags)=>{if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!==\"r\"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:(fd_start=0,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(33)},getStream:fd=>FS.streams[fd],createStream:(stream,fd_start,fd_end)=>{if(!FS.FSStream){FS.FSStream=function(){};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}}}}stream=Object.assign(new FS.FSStream,stream);var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:fd=>{FS.streams[fd]=null},chrdev_stream_ops:{open:stream=>{var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:()=>{throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice:(dev,ops)=>{FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts: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:(populate,callback)=>{if(typeof populate==\"function\"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(\"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(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:(type,opts,mountpoint)=>{var root=mountpoint===\"/\";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:mountpoint=>{var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:(parent,name)=>{return parent.node_ops.lookup(parent,name)},mknod:(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(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:(path,mode)=>{mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:(path,mode)=>{mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:(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!=20)throw e}}},mkdev:(path,mode,dev)=>{if(typeof dev==\"undefined\"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink:(oldpath,newpath)=>{if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},rename:(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);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!==\".\"){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!==\".\"){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,\"w\");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name)}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir:path=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node.node_ops.readdir){throw new FS.ErrnoError(54)}return node.node_ops.readdir(node)},unlink:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink:path=>{var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return PATH_FS.resolve(FS.getPath(link.parent),link.node_ops.readlink(link))},stat:(path,dontFollow)=>{var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;if(!node){throw new FS.ErrnoError(44)}if(!node.node_ops.getattr){throw new FS.ErrnoError(63)}return node.node_ops.getattr(node)},lstat:path=>{return FS.stat(path,true)},chmod:(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(63)}node.node_ops.setattr(node,{mode:mode&4095|node.mode&~4095,timestamp:Date.now()})},lchmod:(path,mode)=>{FS.chmod(path,mode,true)},fchmod:(fd,mode)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chmod(stream.node,mode)},chown:(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(63)}node.node_ops.setattr(node,{timestamp:Date.now()})},lchown:(path,uid,gid)=>{FS.chown(path,uid,gid,true)},fchown:(fd,uid,gid)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chown(stream.node,uid,gid)},truncate:(path,len)=>{if(len<0){throw new FS.ErrnoError(28)}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(63)}if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,\"w\");if(errCode){throw new FS.ErrnoError(errCode)}node.node_ops.setattr(node,{size:len,timestamp:Date.now()})},ftruncate:(fd,len)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.truncate(stream.node,len)},utime:(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:(path,flags,mode,fd_start,fd_end)=>{if(path===\"\"){throw new FS.ErrnoError(44)}flags=typeof flags==\"string\"?FS.modeStringToFlags(flags):flags;mode=typeof mode==\"undefined\"?438: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){}}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else{node=FS.mknod(path,mode,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node:node,path:FS.getPath(node),flags:flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false},fd_start,fd_end);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}}return stream},close:stream=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed:stream=>{return stream.fd===null},llseek:(stream,offset,whence)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read:(stream,buffer,offset,length,position)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!=\"undefined\";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write:(stream,buffer,offset,length,position,canOwn)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!=\"undefined\";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},allocate:(stream,offset,length)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(offset<0||length<=0){throw new FS.ErrnoError(28)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(!FS.isFile(stream.node.mode)&&!FS.isDir(stream.node.mode)){throw new FS.ErrnoError(43)}if(!stream.stream_ops.allocate){throw new FS.ErrnoError(138)}stream.stream_ops.allocate(stream,offset,length)},mmap:(stream,address,length,position,prot,flags)=>{if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}return stream.stream_ops.mmap(stream,address,length,position,prot,flags)},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!stream||!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},munmap:stream=>0,ioctl:(stream,cmd,arg)=>{if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile:(path,opts={})=>{opts.flags=opts.flags||0;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:(path,data,opts={})=>{opts.flags=opts.flags||577;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:()=>FS.currentPath,chdir:path=>{var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,\"x\");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories:()=>{FS.mkdir(\"/tmp\");FS.mkdir(\"/home\");FS.mkdir(\"/home/web_user\")},createDefaultDevices:()=>{FS.mkdir(\"/dev\");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev(\"/dev/null\",FS.makedev(1,3));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));var random_device=getRandomDevice();FS.createDevice(\"/dev\",\"random\",random_device);FS.createDevice(\"/dev\",\"urandom\",random_device);FS.mkdir(\"/dev/shm\");FS.mkdir(\"/dev/shm/tmp\")},createSpecialDirectories:()=>{FS.mkdir(\"/proc\");var proc_self=FS.mkdir(\"/proc/self\");FS.mkdir(\"/proc/self/fd\");FS.mount({mount:()=>{var node=FS.createNode(proc_self,\"fd\",16384|511,73);node.node_ops={lookup:(parent,name)=>{var fd=+name;var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);var ret={parent:null,mount:{mountpoint:\"fake\"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},\"/proc/self/fd\")},createStandardStreams:()=>{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\")}var stdin=FS.open(\"/dev/stdin\",0);var stdout=FS.open(\"/dev/stdout\",1);var stderr=FS.open(\"/dev/stderr\",1)},ensureErrnoError:()=>{if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message=\"FS error\"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=\"<generic error, no stack>\"})},staticInit:()=>{FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},\"/\");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={\"MEMFS\":MEMFS,\"NODEFS\":NODEFS}},init:(input,output,error)=>{FS.init.initialized=true;FS.ensureErrnoError();Module[\"stdin\"]=input||Module[\"stdin\"];Module[\"stdout\"]=output||Module[\"stdout\"];Module[\"stderr\"]=error||Module[\"stderr\"];FS.createStandardStreams()},quit:()=>{FS.init.initialized=false;for(var i=0;i<FS.streams.length;i++){var stream=FS.streams[i];if(!stream){continue}FS.close(stream)}},getMode:(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode},findObject:(path,dontResolveLastLink)=>{var ret=FS.analyzePath(path,dontResolveLastLink);if(ret.exists){return ret.object}else{return null}},analyzePath:(path,dontResolveLastLink)=>{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},createPath:(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){}parent=current}return current},createFile:(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:(parent,name,data,canRead,canWrite,canOwn)=>{var path=name;if(parent){parent=typeof parent==\"string\"?parent:FS.getPath(parent);path=name?PATH.join2(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}FS.chmod(node,mode|146);var stream=FS.open(node,577);FS.write(stream,data,0,data.length,0,canOwn);FS.close(stream);FS.chmod(node,mode)}return node},createDevice:(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);FS.registerDevice(dev,{open:stream=>{stream.seekable=false},close:stream=>{if(output&&output.buffer&&output.buffer.length){output(10)}},read:(stream,buffer,offset,length,pos)=>{var bytesRead=0;for(var i=0;i<length;i++){var result;try{result=input()}catch(e){throw new FS.ErrnoError(29)}if(result===undefined&&bytesRead===0){throw new FS.ErrnoError(6)}if(result===null||result===undefined)break;bytesRead++;buffer[offset+i]=result}if(bytesRead){stream.node.timestamp=Date.now()}return bytesRead},write:(stream,buffer,offset,length,pos)=>{for(var i=0;i<length;i++){try{output(buffer[offset+i])}catch(e){throw new FS.ErrnoError(29)}}if(length){stream.node.timestamp=Date.now()}return i}});return FS.mkdev(path,mode,dev)},forceLoadFile:obj=>{if(obj.isDevice||obj.isFolder||obj.link||obj.contents)return 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(read_){try{obj.contents=intArrayFromString(read_(obj.url),true);obj.usedBytes=obj.contents.length}catch(e){throw new FS.ErrnoError(29)}}else{throw new Error(\"Cannot load without read() or XMLHttpRequest.\")}},createLazyFile:(parent,name,url,canRead,canWrite)=>{function LazyUint8Array(){this.lengthKnown=false;this.chunks=[]}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(){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;if(!hasByteServing)chunkSize=datalength;var doXHR=(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!\");var xhr=new XMLHttpRequest;xhr.open(\"GET\",url,false);if(datalength!==chunkSize)xhr.setRequestHeader(\"Range\",\"bytes=\"+from+\"-\"+to);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(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);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){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out(\"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);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});stream_ops.read=((stream,buffer,offset,length,position)=>{FS.forceLoadFile(node);var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i<size;i++){buffer[offset+i]=contents[position+i]}}else{for(var i=0;i<size;i++){buffer[offset+i]=contents.get(position+i)}}return size});node.stream_ops=stream_ops;return node},createPreloadedFile:(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(\"cp \"+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)}if(Browser.handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url==\"string\"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}},indexedDB:()=>{return window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB},DB_NAME:()=>{return\"EM_FS_\"+window.location.pathname},DB_VERSION:20,DB_STORE_NAME:\"FILE_DATA\",saveFilesToDB:(paths,onload,onerror)=>{onload=onload||(()=>{});onerror=onerror||(()=>{});var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=(()=>{out(\"creating db\");var db=openRequest.result;db.createObjectStore(FS.DB_STORE_NAME)});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(path=>{var putRequest=files.put(FS.analyzePath(path).object.contents,path);putRequest.onsuccess=(()=>{ok++;if(ok+fail==total)finish()});putRequest.onerror=(()=>{fail++;if(ok+fail==total)finish()})});transaction.onerror=onerror});openRequest.onerror=onerror},loadFilesFromDB:(paths,onload,onerror)=>{onload=onload||(()=>{});onerror=onerror||(()=>{});var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=onerror;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(path=>{var getRequest=files.get(path);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=(()=>{fail++;if(ok+fail==total)finish()})});transaction.onerror=onerror});openRequest.onerror=onerror}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt:function(dirfd,path,allowEmpty){if(path[0]===\"/\"){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=FS.getStream(dirfd);if(!dirstream)throw new FS.ErrnoError(8);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,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))){return-54}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?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>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()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},doMkdir:function(path,mode){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){switch(mode&61440){case 32768:case 8192:case 24576:case 4096:case 49152:break;default:return-28}FS.mknod(path,mode,dev);return 0},doReadlink:function(path,buf,bufsize){if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len},doAccess:function(path,amode){if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms=\"\";if(amode&4)perms+=\"r\";if(amode&2)perms+=\"w\";if(amode&1)perms+=\"x\";if(perms&&FS.nodePermissions(node,perms)){return-2}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}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:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream},get64:function(low,high){return low}};function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.open(stream.path,stream.flags,0,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_getcwd(buf,size){try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd);if(size<cwdLengthInBytes+1)return-68;stringToUTF8(cwd,buf,size);return buf}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:abort(\"bad ioctl syscall \"+op)}}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_open(path,flags,varargs){SYSCALLS.varargs=varargs;try{var pathname=SYSCALLS.getStr(path);var mode=varargs?SYSCALLS.get():0;var stream=FS.open(pathname,flags,mode);return stream.fd}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_readlink(path,buf,bufsize){try{path=SYSCALLS.getStr(path);return SYSCALLS.doReadlink(path,buf,bufsize)}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function _abort(){abort(\"\")}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function _emscripten_get_heap_max(){return 2147483648}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;var maxHeapSize=_emscripten_get_heap_max();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}var ENV={};function getExecutableName(){return thisProgram||\"./this.program\"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator==\"object\"&&navigator.languages&&navigator.languages[0]||\"C\").replace(\"-\",\"_\")+\".UTF-8\";var env={\"USER\":\"web_user\",\"LOGNAME\":\"web_user\",\"PATH\":\"/\",\"PWD\":\"/\",\"HOME\":\"/home/web_user\",\"LANG\":lang,\"_\":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+\"=\"+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAP32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAP32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAP32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4;HEAP8[pbuf>>0]=type;return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _fd_read(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doReadv(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var stream=SYSCALLS.getStreamFromFD(fd);var HIGH_OFFSET=4294967296;var offset=offset_high*HIGH_OFFSET+(offset_low>>>0);var DOUBLE_LIMIT=9007199254740992;if(offset<=-DOUBLE_LIMIT||offset>=DOUBLE_LIMIT){return-61}FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=SYSCALLS.doWritev(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS==\"undefined\"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _getpwnam(){err(\"missing function: getpwnam\");abort(-1)}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()){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{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){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);var EXPANSION_RULES_1={\"%c\":\"%a %b %d %H:%M:%S %Y\",\"%D\":\"%m/%d/%y\",\"%F\":\"%Y-%m-%d\",\"%h\":\"%b\",\"%r\":\"%I:%M:%S %p\",\"%R\":\"%H:%M\",\"%T\":\"%H:%M:%S\",\"%x\":\"%m/%d/%y\",\"%X\":\"%H:%M:%S\",\"%Ec\":\"%c\",\"%EC\":\"%C\",\"%Ex\":\"%m/%d/%y\",\"%EX\":\"%H:%M:%S\",\"%Ey\":\"%y\",\"%EY\":\"%Y\",\"%Od\":\"%d\",\"%Oe\":\"%e\",\"%OH\":\"%H\",\"%OI\":\"%I\",\"%Om\":\"%m\",\"%OM\":\"%M\",\"%OS\":\"%S\",\"%Ou\":\"%u\",\"%OU\":\"%U\",\"%OV\":\"%V\",\"%Ow\":\"%w\",\"%OW\":\"%W\",\"%Oy\":\"%y\"};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:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6: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){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){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){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){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);if(compareByDay(firstSunday,endDate)<0){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){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){return\"53\"}if(compareByDay(firstWeekStartNextYear,endDate)<=0){return\"01\"}var daysDifference;if(firstWeekStartThisYear.getFullYear()<date.tm_year+1900){daysDifference=date.tm_yday+32-firstWeekStartThisYear.getDate()}else{daysDifference=date.tm_yday+1-firstWeekStartThisYear.getDate()}return leadingNulls(Math.ceil(daysDifference/7),2)},\"%w\":function(date){return date.tm_wday},\"%W\":function(date){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);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){return(date.tm_year+1900).toString().substring(2)},\"%Y\":function(date){return date.tm_year+1900},\"%z\":function(date){var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?\"+\":\"-\")+String(\"0000\"+off).slice(-4)},\"%Z\":function(date){return date.tm_zone},\"%%\":function(){return\"%\"}};pattern=pattern.replace(/%%/g,\"\\0\\0\");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,\"g\"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\\0\\0/g,\"%\");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}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};var readMode=292|73;var writeMode=146;Object.defineProperties(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)}}});FS.FSNode=FSNode;FS.staticInit();Module[\"FS_createPath\"]=FS.createPath;Module[\"FS_createDataFile\"]=FS.createDataFile;Module[\"FS_createPreloadedFile\"]=FS.createPreloadedFile;Module[\"FS_createLazyFile\"]=FS.createLazyFile;Module[\"FS_createDevice\"]=FS.createDevice;Module[\"FS_unlink\"]=FS.unlink;if(ENVIRONMENT_IS_NODE){requireNodeFS();NODEFS.staticInit()}ERRNO_CODES={\"EPERM\":63,\"ENOENT\":44,\"ESRCH\":71,\"EINTR\":27,\"EIO\":29,\"ENXIO\":60,\"E2BIG\":1,\"ENOEXEC\":45,\"EBADF\":8,\"ECHILD\":12,\"EAGAIN\":6,\"EWOULDBLOCK\":6,\"ENOMEM\":48,\"EACCES\":2,\"EFAULT\":21,\"ENOTBLK\":105,\"EBUSY\":10,\"EEXIST\":20,\"EXDEV\":75,\"ENODEV\":43,\"ENOTDIR\":54,\"EISDIR\":31,\"EINVAL\":28,\"ENFILE\":41,\"EMFILE\":33,\"ENOTTY\":59,\"ETXTBSY\":74,\"EFBIG\":22,\"ENOSPC\":51,\"ESPIPE\":70,\"EROFS\":69,\"EMLINK\":34,\"EPIPE\":64,\"EDOM\":18,\"ERANGE\":68,\"ENOMSG\":49,\"EIDRM\":24,\"ECHRNG\":106,\"EL2NSYNC\":156,\"EL3HLT\":107,\"EL3RST\":108,\"ELNRNG\":109,\"EUNATCH\":110,\"ENOCSI\":111,\"EL2HLT\":112,\"EDEADLK\":16,\"ENOLCK\":46,\"EBADE\":113,\"EBADR\":114,\"EXFULL\":115,\"ENOANO\":104,\"EBADRQC\":103,\"EBADSLT\":102,\"EDEADLOCK\":16,\"EBFONT\":101,\"ENOSTR\":100,\"ENODATA\":116,\"ETIME\":117,\"ENOSR\":118,\"ENONET\":119,\"ENOPKG\":120,\"EREMOTE\":121,\"ENOLINK\":47,\"EADV\":122,\"ESRMNT\":123,\"ECOMM\":124,\"EPROTO\":65,\"EMULTIHOP\":36,\"EDOTDOT\":125,\"EBADMSG\":9,\"ENOTUNIQ\":126,\"EBADFD\":127,\"EREMCHG\":128,\"ELIBACC\":129,\"ELIBBAD\":130,\"ELIBSCN\":131,\"ELIBMAX\":132,\"ELIBEXEC\":133,\"ENOSYS\":52,\"ENOTEMPTY\":55,\"ENAMETOOLONG\":37,\"ELOOP\":32,\"EOPNOTSUPP\":138,\"EPFNOSUPPORT\":139,\"ECONNRESET\":15,\"ENOBUFS\":42,\"EAFNOSUPPORT\":5,\"EPROTOTYPE\":67,\"ENOTSOCK\":57,\"ENOPROTOOPT\":50,\"ESHUTDOWN\":140,\"ECONNREFUSED\":14,\"EADDRINUSE\":3,\"ECONNABORTED\":13,\"ENETUNREACH\":40,\"ENETDOWN\":38,\"ETIMEDOUT\":73,\"EHOSTDOWN\":142,\"EHOSTUNREACH\":23,\"EINPROGRESS\":26,\"EALREADY\":7,\"EDESTADDRREQ\":17,\"EMSGSIZE\":35,\"EPROTONOSUPPORT\":66,\"ESOCKTNOSUPPORT\":137,\"EADDRNOTAVAIL\":4,\"ENETRESET\":39,\"EISCONN\":30,\"ENOTCONN\":53,\"ETOOMANYREFS\":141,\"EUSERS\":136,\"EDQUOT\":19,\"ESTALE\":72,\"ENOTSUP\":138,\"ENOMEDIUM\":148,\"EILSEQ\":25,\"EOVERFLOW\":61,\"ECANCELED\":11,\"ENOTRECOVERABLE\":56,\"EOWNERDEAD\":62,\"ESTRPIPE\":135};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}var asmLibraryArg={\"a\":___cxa_allocate_exception,\"b\":___cxa_throw,\"e\":___syscall_fcntl64,\"t\":___syscall_getcwd,\"j\":___syscall_ioctl,\"k\":___syscall_open,\"o\":___syscall_readlink,\"p\":___syscall_stat64,\"c\":_abort,\"l\":_emscripten_memcpy_big,\"d\":_emscripten_resize_heap,\"r\":_environ_get,\"s\":_environ_sizes_get,\"f\":_fd_close,\"q\":_fd_fdstat_get,\"i\":_fd_read,\"m\":_fd_seek,\"h\":_fd_write,\"g\":_getpwnam,\"n\":_strftime_l};var asm=createWasm();var ___wasm_call_ctors=Module[\"___wasm_call_ctors\"]=function(){return(___wasm_call_ctors=Module[\"___wasm_call_ctors\"]=Module[\"asm\"][\"v\"]).apply(null,arguments)};var _main=Module[\"_main\"]=function(){return(_main=Module[\"_main\"]=Module[\"asm\"][\"w\"]).apply(null,arguments)};var _malloc=Module[\"_malloc\"]=function(){return(_malloc=Module[\"_malloc\"]=Module[\"asm\"][\"x\"]).apply(null,arguments)};var _itk_wasm_input_array_alloc=Module[\"_itk_wasm_input_array_alloc\"]=function(){return(_itk_wasm_input_array_alloc=Module[\"_itk_wasm_input_array_alloc\"]=Module[\"asm\"][\"z\"]).apply(null,arguments)};var _itk_wasm_input_json_alloc=Module[\"_itk_wasm_input_json_alloc\"]=function(){return(_itk_wasm_input_json_alloc=Module[\"_itk_wasm_input_json_alloc\"]=Module[\"asm\"][\"A\"]).apply(null,arguments)};var _itk_wasm_output_json_address=Module[\"_itk_wasm_output_json_address\"]=function(){return(_itk_wasm_output_json_address=Module[\"_itk_wasm_output_json_address\"]=Module[\"asm\"][\"B\"]).apply(null,arguments)};var _itk_wasm_output_json_size=Module[\"_itk_wasm_output_json_size\"]=function(){return(_itk_wasm_output_json_size=Module[\"_itk_wasm_output_json_size\"]=Module[\"asm\"][\"C\"]).apply(null,arguments)};var _itk_wasm_output_array_address=Module[\"_itk_wasm_output_array_address\"]=function(){return(_itk_wasm_output_array_address=Module[\"_itk_wasm_output_array_address\"]=Module[\"asm\"][\"D\"]).apply(null,arguments)};var _itk_wasm_output_array_size=Module[\"_itk_wasm_output_array_size\"]=function(){return(_itk_wasm_output_array_size=Module[\"_itk_wasm_output_array_size\"]=Module[\"asm\"][\"E\"]).apply(null,arguments)};var _itk_wasm_free_all=Module[\"_itk_wasm_free_all\"]=function(){return(_itk_wasm_free_all=Module[\"_itk_wasm_free_all\"]=Module[\"asm\"][\"F\"]).apply(null,arguments)};var ___errno_location=Module[\"___errno_location\"]=function(){return(___errno_location=Module[\"___errno_location\"]=Module[\"asm\"][\"G\"]).apply(null,arguments)};var stackSave=Module[\"stackSave\"]=function(){return(stackSave=Module[\"stackSave\"]=Module[\"asm\"][\"H\"]).apply(null,arguments)};var stackRestore=Module[\"stackRestore\"]=function(){return(stackRestore=Module[\"stackRestore\"]=Module[\"asm\"][\"I\"]).apply(null,arguments)};var stackAlloc=Module[\"stackAlloc\"]=function(){return(stackAlloc=Module[\"stackAlloc\"]=Module[\"asm\"][\"J\"]).apply(null,arguments)};Module[\"ccall\"]=ccall;Module[\"cwrap\"]=cwrap;Module[\"writeArrayToMemory\"]=writeArrayToMemory;Module[\"writeAsciiToMemory\"]=writeAsciiToMemory;Module[\"addRunDependency\"]=addRunDependency;Module[\"removeRunDependency\"]=removeRunDependency;Module[\"FS_createPath\"]=FS.createPath;Module[\"FS_createDataFile\"]=FS.createDataFile;Module[\"FS_createPreloadedFile\"]=FS.createPreloadedFile;Module[\"FS_createLazyFile\"]=FS.createLazyFile;Module[\"FS_createDevice\"]=FS.createDevice;Module[\"FS_unlink\"]=FS.unlink;Module[\"callMain\"]=callMain;Module[\"AsciiToString\"]=AsciiToString;var calledRun;function ExitStatus(status){this.name=\"ExitStatus\";this.message=\"Program terminated with exit(\"+status+\")\";this.status=status}var calledMain=false;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args){var entryFunction=Module[\"_main\"];args=args||[];var argc=args.length+1;var argv=stackAlloc((argc+1)*4);HEAP32[argv>>2]=allocateUTF8OnStack(thisProgram);for(var i=1;i<argc;i++){HEAP32[(argv>>2)+i]=allocateUTF8OnStack(args[i-1])}HEAP32[(argv>>2)+argc]=0;try{var ret=entryFunction(argc,argv);exit(ret,true);return ret}catch(e){return handleException(e)}finally{calledMain=true}}function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module[\"calledRun\"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module[\"onRuntimeInitialized\"])Module[\"onRuntimeInitialized\"]();if(shouldRunNow)callMain(args);postRun()}if(Module[\"setStatus\"]){Module[\"setStatus\"](\"Running...\");setTimeout(function(){setTimeout(function(){Module[\"setStatus\"](\"\")},1);doRun()},1)}else{doRun()}}Module[\"run\"]=run;function exit(status,implicit){EXITSTATUS=status;if(keepRuntimeAlive()){}else{exitRuntime()}procExit(status)}function procExit(code){EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module[\"onExit\"])Module[\"onExit\"](code);ABORT=true}quit_(code,new ExitStatus(code))}if(Module[\"preInit\"]){if(typeof Module[\"preInit\"]==\"function\")Module[\"preInit\"]=[Module[\"preInit\"]];while(Module[\"preInit\"].length>0){Module[\"preInit\"].pop()()}}var shouldRunNow=false;if(Module[\"noInitialRun\"])shouldRunNow=false;run();Module.mountContainingDir=function(filePath){if(!ENVIRONMENT_IS_NODE){return}var path=require(\"path\");var containingDir=path.dirname(filePath);if(FS.isDir(containingDir)||containingDir===\"/\"){return}var currentDir=\"/\";var splitContainingDir=containingDir.split(path.sep);for(var ii=1;ii<splitContainingDir.length;ii++){currentDir+=splitContainingDir[ii];if(!FS.analyzePath(currentDir).exists){FS.mkdir(currentDir)}currentDir+=\"/\"}FS.mount(NODEFS,{root:containingDir},currentDir);return currentDir+path.basename(filePath)};Module.unmountContainingDir=function(filePath){if(!ENVIRONMENT_IS_NODE){return}var path=require(\"path\");var containingDir=path.dirname(filePath);FS.unmount(containingDir)};Module.fs_mkdirs=function(dirs){var currentDir=\"/\";var splitDirs=dirs.split(\"/\");for(var ii=1;ii<splitDirs.length;++ii){currentDir+=splitDirs[ii];if(!FS.analyzePath(currentDir).exists){FS.mkdir(currentDir)}currentDir+=\"/\"}};Module.fs_readFile=function(path,opts){return FS.readFile(path,opts)};Module.fs_writeFile=function(path,data,opts){return FS.writeFile(path,data,opts)};Module.fs_unlink=function(path){return FS.unlink(path)};Module.fs_open=function(path,flags,mode){return FS.open(path,flags,mode)};Module.fs_stat=function(path){return FS.stat(path)};Module.fs_read=function(stream,buffer,offset,length,position){return FS.read(stream,buffer,offset,length,position)};Module.fs_close=function(stream){return FS.close(stream)};\n\n\n  return BloscZarr.ready\n}\n);\n})();\nif (typeof exports === 'object' && typeof module === 'object')\n  module.exports = BloscZarr;\nelse if (typeof define === 'function' && define['amd'])\n  define([], function() { return BloscZarr; });\nelse if (typeof exports === 'object')\n  exports[\"BloscZarr\"] = BloscZarr;\n"
  },
  {
    "path": "src/Compression/bloscZarrDecompress.js",
    "content": "import { runPipeline, InterfaceTypes, WorkerPool } from 'itk-wasm'\nimport { getSize } from '../IO/dtypeUtils'\n\nconst cores = navigator.hardwareConcurrency ? navigator.hardwareConcurrency : 4\nconst numberOfWorkers = cores + Math.floor(Math.sqrt(cores))\nconst workerPool = new WorkerPool(numberOfWorkers, runPipeline)\n\n/**\n * Input:\n *\n *   chunkData: An Array of\n *\n *     {\n *       data: chunkArrayBuffer,\n *       metadata: zarrayMetadata\n *     }\n *\n *   objects.\n *\n *\n * Output:\n *\n *   An Array of decompressed ArrayBuffer chunks.\n */\nasync function bloscZarrDecompress(chunkData) {\n  const desiredOutputs = [{ type: InterfaceTypes.BinaryStream }]\n  const taskArgsArray = []\n  let dtype = null\n  for (let index = 0; index < chunkData.length; index++) {\n    const zarrayMetadata = chunkData[index].metadata\n    const compressedChunk = chunkData[index].data\n    dtype = zarrayMetadata.dtype\n    const nElements = zarrayMetadata.chunks.reduce((a, b) => a * b)\n    const elementSize = getSize(dtype)\n    if (!elementSize) throw Error('Unknown dtype in .zarray metadata')\n    const outputSize = nElements * elementSize\n    const inputs = [\n      {\n        type: InterfaceTypes.BinaryStream,\n        data: { data: new Uint8Array(compressedChunk) },\n      },\n    ]\n    const args = [\n      '0',\n      '0',\n      zarrayMetadata.compressor.cname,\n      compressedChunk.byteLength.toString(),\n      '--output-size',\n      outputSize.toString(),\n      '--decompress',\n      '--memory-io',\n    ]\n    taskArgsArray.push(['BloscZarr', args, desiredOutputs, inputs])\n  }\n  const results = await workerPool.runTasks(taskArgsArray).promise\n\n  const decompressedChunks = []\n  for (let index = 0; index < results.length; index++) {\n    // console.log(results[index].stdout)\n    // console.error(results[index].stderr)\n    decompressedChunks.push(results[index].outputs[0].data.data.buffer)\n  }\n  return decompressedChunks\n}\n\nexport default bloscZarrDecompress\n"
  },
  {
    "path": "src/Context/ImageActorContext.js",
    "content": "export const defaultCompare = {\n  method: 'green-magenta', // 'checkerboard', 'cyan-magenta' | 'blend' | 'disabled'\n  imageMix: 0.5, // changes opaqueness of moving vs fixed image. Value of 1 means max opacity for moving image, 0 for fixed image.\n  checkerboard: false, // mixes the 2 images with an alternating pattern.\n  pattern: [4, 4, 4], // when checkerboard, number of \"squares\" across each dimension\n  swapImageOrder: false, // when checkerboard, switches moving/fixed image in each square\n}\n\nclass ImageActorContext {\n  // MultiscaleSpatialImage to be visualized\n  image = null\n\n  // The successfully loaded scale\n  loadedScale = null\n\n  // Automatically adjust the rendered scale\n  isFramerateScalePickingOn = true\n\n  // MultiscaleSpatialImage label image to be visualized\n  labelImage = null\n\n  // MultiscaleSpatialImage label image to be visualized for use with\n  // interactive, manual editing as opposed to stored or algorithmic results\n  editorLabelImage = null\n\n  // Whether the image components are dependent, e.g. RGB, are independent, in\n  // which they are passed through separate color maps\n  // An initial null value will be replaced by heuristics based on the image\n  // component type and number of components.\n  independentComponents = null\n\n  // Enable interpolation on slicing planes\n  interpolationEnabled = true\n\n  // For multi-component images, the selected component index\n  selectedComponent = 0\n\n  // Maximum number of intensity components that can be visualized\n  maxIntensityComponents = 3\n\n  // The index of the last component whose visibility changed\n  lastComponentVisibilityChanged = 0\n\n  // Whether a given image intensity component is visible\n  componentVisibilities = [true]\n\n  // Map of image intensity component to color map names\n  colorMaps = new Map()\n\n  // Map of image intensity component to array of [minValue, maxValue] for\n  // mapping colors\n  colorRanges = new Map()\n\n  // Keep growing component ranges as new parts of the image are loaded\n  // Map of image intensity component to Boolean\n  colorRangeMinAutoAdjust = null\n  colorRangeMaxAutoAdjust = null\n\n  // Map of image intensity component to array of [minBound, maxBound] for\n  // limiting the color range in the UI\n  colorRangeBounds = new Map()\n\n  // Keep growing component bounds as new parts of the image are loaded\n  // Map of image intensity component to Boolean\n  colorRangeBoundsAutoAdjust = null\n\n  // Map of the image intensity component to an object representing the\n  // piecewise function. This object has two properties: range and nodes.\n  // The range property is a [min, max] array of intensity values. The nodes\n  // property is a an array of { x, y, midpoint, sharpness } objects\n  // characterizing a VTK piecewise function\n  piecewiseFunctions = new Map()\n\n  // Not used!\n  // Map of the image intensity component to the array of\n  // { position, width, xBias, yBias } gaussian parameters that define the\n  // piecewise functions\n  piecewiseFunctionGaussians = new Map()\n\n  // Map of x,y point in 0 to 1 range.  Scaled by colorRanges.\n  piecewiseFunctionPoints = new Map()\n\n  // Boolean map by component of whether the points should be auto adjusted\n  // Set to false when the user manually adjusts the points\n  piecewiseFunctionPointsAutoAdjust = null\n\n  // Use gradient-based shadows in the volume rendering\n  shadowEnabled = true\n\n  // Gradient opacity weight in the volume rendering\n  gradientOpacity = 0.5\n\n  // Gradient opacity scale in the volume rendering\n  gradientOpacityScale = 0.5\n\n  // Distance in depth samples for the volume rendering\n  volumeSampleDistance = 0.2\n\n  // Volume rendering blend mode\n  blendMode = 'Composite'\n\n  cinematicParameters = {\n    isCinematicPossible: true, // computed to false if number of components is more than 1\n    scatteringBlend: 0.0,\n    diffuse: 1.2,\n    ambient: 0.6,\n  }\n\n  // Name of the labelImage layer\n  labelImageName = null\n\n  // Blend, 0.0 to 1.0 of the label image into the image\n  labelImageBlend = 0.5\n\n  // Color lookup table name for the label image\n  lookupTable = 'glasbey'\n\n  // Rendering weights assigned to to labels, Map of label value to weight\n  labelImageWeights = new Map()\n\n  labelImageToggleWeight = 0.1\n\n  // String names for the label values\n  labelNames = new Map()\n\n  // Label index selected for changes in the UI, or special 'all' value that\n  // identifies all non-background (index 0) labels\n  selectedLabel = 'all'\n\n  // Cached histogram by component for use by UI when switching selected component\n  histograms = new Map()\n\n  // Option config object for fusing 2 images, i.e. 'checkerboard'. See defaultCompare for object shape.\n  compare = {} // mostly object allows initial update \"diff\" to detect changes and apply parameters\n\n  // Override default left button mouse interactor to use window width/level interactor\n  windowLevelEnabled = false\n}\n\nexport default ImageActorContext\n"
  },
  {
    "path": "src/Context/ImagesMachineContext.js",
    "content": "class ImagesMachineContext {\n  // Actors for rendering images and label images\n  imageRenderingActors = new Map()\n\n  // Context for the image actors\n  actorContext = new Map()\n\n  // Name of the selected image\n  selectedName = null\n\n  // Name of the image whose data needs to be updated\n  updateRenderedName = null\n}\n\nexport default ImagesMachineContext\n"
  },
  {
    "path": "src/Context/LayerActorContext.js",
    "content": "class LayerActorContext {\n  //  One of \"image\", \"labelImage\", \"geometry\", \"pointSet\", or \"widget\"\n  type = 'image'\n\n  // Boolean indicating whether the dataset is visible\n  visible = true\n\n  // img element icon for the layer or null\n  icon = null\n\n  // Boolean indicating whether the dataset bounding box is visible\n  bbox = false\n}\n\nexport default LayerActorContext\n"
  },
  {
    "path": "src/Context/LayersMachineContext.js",
    "content": "class LayersMachineContext {\n  // Actors for providing an interface to the layers\n  layerUIActors = new Map()\n\n  // Context for the layer actors\n  actorContext = new Map()\n\n  // A { name, data } object, queued for creation of the data's actor\n  lastAddedData = null\n}\n\nexport default LayersMachineContext\n"
  },
  {
    "path": "src/Context/MainMachineContext.js",
    "content": "class MainMachineContext {\n  constructor(config) {\n    if (config) {\n      if (typeof config.backgroundColor !== 'undefined') {\n        this.backgroundColor = config.backgroundColor\n      }\n      if (typeof config.units !== 'undefined') {\n        this.units = config.units\n      }\n\n      // Todo: more\n    }\n  }\n\n  getConfig() {\n    const config = {\n      backgroundColor: [...this.backgroundColor],\n      units: this.units,\n    }\n\n    return config\n  }\n\n  // Background color of the renderer\n  backgroundColor = [0.5, 0.5, 0.5]\n\n  // Background colors to step through when clicking the background color\n  // button\n  backgroundColors = [\n    [0.5, 0.5, 0.5],\n    [0, 0, 0],\n    [1, 1, 1],\n  ]\n\n  // Index of the selected background color from the backgroundColors\n  selectedBackgroundColor = 0\n\n  // Is fullscreen mode enabled?\n  fullscreenEnabled = false\n\n  // Are annotations, e.g. pixel values, an orientation widget, displayed?\n  annotationsEnabled = true\n\n  // Continuously rotate the 3D rendering?\n  rotateEnabled = false\n\n  // Visualize the spatial axes on the viewable scene content\n  axesEnabled = false\n\n  // Spatial length units displayed in the scale bar\n  units = ''\n\n  // Cropping planes widget enabled\n  croppingPlanesEnabled = false\n  areCroppingPlanesTouched = false\n\n  // Cropping planes. These typically define a box containing a region of\n  // interest in space. The visualization is cropped outside of these planes.\n  // Each is characterized with: { origin, normal }.\n  //\n  // origin: x,y,z point at a point in the plane\n  // normal: 3-component vector defining the normal to the plane\n  //\n  // An example: An array of six planes. When the planes are axis aligned:\n  // -x, +x, -y, +y, -z, +z\n  croppingPlanes = null\n\n  // In the single view layout, the an X plane, Y plane, Z plane, or volume\n  // rendering.\n  viewMode = 'Volume'\n\n  // Current viewer frames per second\n  fps = null\n\n  // Slicing planes specification\n  slicingPlanes = {\n    x: {\n      min: 0.0,\n      max: 1.0,\n      step: 0.1,\n      scroll: false,\n      scrollDirection: 1,\n      visible: false,\n    },\n    y: {\n      min: 0.0,\n      max: 1.0,\n      step: 0.1,\n      scroll: false,\n      scrollDirection: 1,\n      visible: false,\n    },\n    z: {\n      min: 0.0,\n      max: 1.0,\n      step: 0.1,\n      scroll: false,\n      scrollDirection: 1,\n      visible: false,\n    },\n  }\n\n  // x slice value\n  xSlice = null\n  // y slice value\n  ySlice = null\n  // z slice value\n  zSlice = null\n}\n\nexport default MainMachineContext\n"
  },
  {
    "path": "src/Context/ViewerMachineContext.js",
    "content": "import MainMachineContext from './MainMachineContext'\nimport LayersMachineContext from './LayersMachineContext'\nimport ImagesMachineContext from './ImagesMachineContext'\nimport WidgetsMachineContext from './WidgetsMachineContext'\n\nexport const MAX_CONCURRENCY = 128\n\nconst defaultRenderingViewContainerStyle = {\n  position: 'relative',\n  width: '100%',\n  height: 'auto',\n  //height: '100%',\n  minHeight: '200px',\n  minWidth: '450px',\n  margin: '0',\n  padding: '0',\n  top: '0',\n  left: '0',\n  flex: '1 1 0px',\n  overflow: 'hidden',\n}\n\nclass ViewerMachineContext {\n  constructor(config) {\n    this.id = `itk-vtk-viewer-${performance\n      .now()\n      .toString()\n      .replace('.', '')}`\n    if (\n      config &&\n      (typeof config.viewerConfigVersion === 'undefined' ||\n        parseInt(config.viewerConfigVersion.split('.')[0]) ===\n          parseInt(this.viewerConfigVersion.split('.')[0]))\n    ) {\n      if (typeof config.uiMachineOptions !== 'undefined') {\n        this.uiMachineOptions = config.uiMachineOptions\n      }\n      if (typeof config.xyLowerLeft !== 'undefined') {\n        this.xyLowerLeft = config.xyLowerLeft\n      }\n      if (typeof config.renderingViewContainerStyle !== 'undefined') {\n        this.renderingViewContainerStyle = config.renderingViewContainerStyle\n      }\n      if (typeof config.uiCollapsed !== 'undefined') {\n        this.uiCollapsed = config.uiCollapsed\n      }\n      if (typeof config.maxConcurrency !== 'undefined') {\n        this.maxConcurrency = config.maxConcurrency\n      }\n      this.main = new MainMachineContext(config.main)\n    } else {\n      this.main = new MainMachineContext()\n    }\n\n    // Todo: add config serialization / deserializeation\n    this.layers = new LayersMachineContext()\n    this.images = new ImagesMachineContext()\n    this.widgets = new WidgetsMachineContext()\n  }\n\n  getConfig() {\n    let uiMachineOptions = 'reference'\n    if (this.uiMachineOptions.href) {\n      uiMachineOptions = this.uiMachineOptions\n    }\n    const config = {\n      uiMachineOptions,\n\n      viewerConfigVersion: this.viewerConfigVersion,\n\n      xyLowerLeft: this.xyLowerLeft,\n      renderingViewContainerStyle: { ...this.renderingViewContainerStyle },\n      uiCollapsed: this.uiCollapsed,\n      maxConcurrency: this.maxConcurrency,\n\n      main: this.main.getConfig(),\n    }\n\n    return config\n  }\n\n  // Contains the viewer container div and optionally the debugger\n  rootContainer = null\n\n  // Contains the viewer\n  container = null\n\n  // Version for compatibility check\n  viewerConfigVersion = '0.3'\n\n  // How to render the user interface, Either 'reference' or { href: 'https://url.to/uiMachineOptionsESM.js, export: 'default' }, or a JavaScript object with the ui machine options\n  uiMachineOptions = 'reference'\n\n  // Unique identifier used to identify a viewer in the DOM when multiple are\n  // on a page\n  id = 'itk-vtk-viewer'\n\n  // A 2D viewer versus a 3D viewer\n  use2D = false\n\n  // When viewing the Z slice, the X-Y plane, is the origin in the lower left\n  // or upper left?\n  xyLowerLeft = false\n\n  // Container's (html div's) containing rendering views\n  renderingViewContainers = new Map()\n\n  // Style of the container for the rendering views\n  renderingViewContainerStyle = defaultRenderingViewContainerStyle\n\n  // Is a \"dark mode\" enabled in the user interface?\n  uiDarkMode = false\n\n  // Has the user interface been collapsed, leaving on the interactive\n  // rendering?\n  uiCollapsed = false\n\n  // Has the user set the number of available processors, or will we determine\n  // that dynamically from the client?\n  maxConcurrency = MAX_CONCURRENCY\n\n  // Main machine context\n  main = null\n\n  // Widgets machine context\n  widgets = null\n\n  // Layers machine context\n  layers = null\n\n  // Image machine context\n  images = null\n}\n\nexport default ViewerMachineContext\n"
  },
  {
    "path": "src/Context/WidgetsMachineContext.js",
    "content": "class WidgetsMachineContext {\n  // Whether the distance widget is enabled\n  distanceEnabled = false\n\n  // Distance/length measured by the distance widget\n  distanceValue = 0.0\n}\n\nexport default WidgetsMachineContext\n"
  },
  {
    "path": "src/IO/Analyze/ComputeRanges.worker.js",
    "content": "import registerWebworker from 'webworker-promise/lib/register'\nimport { createRangeHelper } from './createRangeHelper'\n\nconst computeRangesInSplit = ({\n  split,\n  numberOfSplits,\n  values,\n  numberOfComponents,\n}) => {\n  const helpers = [...Array(numberOfComponents)].map(createRangeHelper)\n\n  const start = Math.floor(values.length / numberOfSplits) * split\n  const end =\n    split === numberOfSplits - 1\n      ? values.length\n      : Math.floor(values.length / numberOfSplits) * (split + 1)\n\n  for (let i = start; i < end; i++) {\n    helpers[i % numberOfComponents].add(values[i])\n  }\n\n  return helpers.map(h => h.getRange())\n}\n\nregisterWebworker().operation('computeRanges', computeRangesInSplit)\n"
  },
  {
    "path": "src/IO/Analyze/UpdateHistogram.worker.js",
    "content": "import registerWebworker from 'webworker-promise/lib/register'\n\nregisterWebworker().operation(\n  'updateHistogram',\n  ({\n    values,\n    min,\n    max,\n    numberOfBins,\n    component = 0,\n    numberOfComponents = 1,\n  }) => {\n    const offset = component\n    const step = numberOfComponents\n\n    const delta = max - min\n    const histogram = new Float32Array(numberOfBins)\n    histogram.fill(0)\n    const len = values.length\n    for (let i = offset; i < len; i += step) {\n      const idx = Math.floor(\n        ((numberOfBins - 1) * (Number(values[i]) - min)) / delta\n      )\n      histogram[idx] += 1\n    }\n\n    return Promise.resolve(\n      new registerWebworker.TransferableResponse(histogram, [histogram.buffer])\n    )\n  }\n)\n"
  },
  {
    "path": "src/IO/Analyze/computeHistograms.js",
    "content": "const haveSharedArrayBuffer = typeof window.SharedArrayBuffer === 'function'\nimport webWorkerPromiseWorkerPool from './webWorkerPromiseWorkerPool'\nimport UpdateHistogramWorker from './UpdateHistogram.worker'\n\nconst numberOfWorkers = navigator.hardwareConcurrency\n  ? Math.min(navigator.hardwareConcurrency, 6)\n  : 4\n\nconst updateHistogramWorkerPool = webWorkerPromiseWorkerPool(\n  numberOfWorkers,\n  () => new UpdateHistogramWorker(),\n  'updateHistogram'\n)\n\nconst BIN_COUNT_DEFAULT = 256\n\nexport const computeHistogram = async (\n  values,\n  component,\n  numberOfComponents,\n  [min, max]\n) => {\n  const numberOfSplits = numberOfWorkers\n\n  const isFloatValues =\n    values instanceof Float32Array || values instanceof Float64Array\n  const numberOfBins = isFloatValues\n    ? BIN_COUNT_DEFAULT\n    : // only need a bin for each possible integer value\n      Math.min(max - min + 1, BIN_COUNT_DEFAULT)\n\n  const taskArgs = new Array(numberOfSplits)\n  if (haveSharedArrayBuffer && values.buffer instanceof SharedArrayBuffer) {\n    for (let split = 0; split < numberOfSplits; split++) {\n      taskArgs[split] = [\n        {\n          values,\n          min,\n          max,\n          numberOfBins,\n          component,\n          numberOfComponents,\n        },\n      ]\n    }\n  } else {\n    let arrayStride = Math.floor(values.length / numberOfSplits) || 1\n    arrayStride += arrayStride % numberOfComponents\n    let arrayIndex = 0\n    for (let split = 0; split < numberOfSplits; split++) {\n      const arrayStart = arrayIndex\n      const arrayEnd = Math.min(arrayIndex + arrayStride, values.length - 1)\n      const subArray = values.slice(arrayStart, arrayEnd + 1)\n      taskArgs[split] = [\n        {\n          values: subArray,\n          min,\n          max,\n          numberOfBins,\n          component,\n          numberOfComponents,\n        },\n        [subArray.buffer],\n      ]\n      arrayIndex += arrayStride\n    }\n  }\n\n  const histograms = await updateHistogramWorkerPool.runTasks(taskArgs).promise\n  const histogram = new Float32Array(numberOfBins)\n  histogram.fill(0.0)\n  for (let ii = 0; ii < histograms.length; ii++) {\n    for (let jj = 0; jj < numberOfBins; jj++) {\n      histogram[jj] += histograms[ii].result[jj]\n    }\n  }\n  let maxHistogram = 0.0\n  for (let ii = 0; ii < numberOfBins; ii++) {\n    maxHistogram = Math.max(histogram[ii], maxHistogram)\n  }\n  for (let ii = 0; ii < numberOfBins; ii++) {\n    histogram[ii] /= maxHistogram\n  }\n  return histogram\n}\n"
  },
  {
    "path": "src/IO/Analyze/computeRanges.js",
    "content": "import webWorkerPromiseWorkerPool from './webWorkerPromiseWorkerPool'\nimport { createRangeHelper } from './createRangeHelper'\nimport ComputeRangesWorker from './ComputeRanges.worker'\n\nconst haveSharedArrayBuffer = typeof globalThis.SharedArrayBuffer === 'function'\n\nconst numberOfWorkers = navigator.hardwareConcurrency\n  ? Math.min(navigator.hardwareConcurrency, 8)\n  : 4\n\nconst computeRangeWorkerPool = webWorkerPromiseWorkerPool(\n  numberOfWorkers,\n  () => new ComputeRangesWorker(),\n  'computeRanges'\n)\n\nexport async function computeRanges(values, numberOfComponents = 1) {\n  const numberOfSplits = numberOfWorkers\n\n  const taskArgs = new Array(numberOfSplits)\n  if (haveSharedArrayBuffer && values.buffer instanceof SharedArrayBuffer) {\n    for (let split = 0; split < numberOfSplits; split++) {\n      taskArgs[split] = [\n        {\n          split,\n          numberOfSplits,\n          values,\n          numberOfComponents,\n        },\n      ]\n    }\n  } else {\n    let arrayStride = Math.floor(values.length / numberOfSplits) || 1\n    arrayStride += arrayStride % numberOfComponents\n    let arrayIndex = 0\n    for (let split = 0; split < numberOfSplits; split++) {\n      const arrayStart = arrayIndex\n      const arrayEnd = Math.min(arrayIndex + arrayStride, values.length - 1)\n      const subArray = values.slice(arrayStart, arrayEnd + 1)\n      taskArgs[split] = [\n        {\n          split: 0, // 0 because array already split\n          numberOfSplits: 1,\n          values: subArray,\n          numberOfComponents,\n        },\n        [subArray.buffer],\n      ]\n      arrayIndex += arrayStride\n    }\n  }\n\n  const rangesBySplit = await computeRangeWorkerPool.runTasks(taskArgs).promise\n\n  const helpers = [...Array(numberOfComponents)].map(createRangeHelper)\n  rangesBySplit.forEach(({ result: ranges }) => {\n    ranges.forEach(({ min, max }, compIdx) => {\n      helpers[compIdx].add(min)\n      helpers[compIdx].add(max)\n    })\n  })\n\n  return helpers.map(h => h.getRange())\n}\n"
  },
  {
    "path": "src/IO/Analyze/createRangeHelper.js",
    "content": "export function createRangeHelper() {\n  let min = Number.POSITIVE_INFINITY\n  let max = Number.NEGATIVE_INFINITY\n\n  return {\n    add(value) {\n      if (min > value) {\n        min = value\n      }\n      if (max < value) {\n        max = value\n      }\n    },\n    getRange() {\n      return { min, max }\n    },\n  }\n}\n"
  },
  {
    "path": "src/IO/Analyze/webWorkerPromiseWorkerPool.js",
    "content": "import { WorkerPool } from 'itk-wasm'\n\nimport WebworkerPromise from 'webworker-promise'\n\nfunction webWorkerPromiseWorkerPool(\n  numberOfWorkers,\n  makeWorker,\n  operationName\n) {\n  const createWorker = existingWorker => {\n    const worker = existingWorker ?? makeWorker()\n    const webWorkerPromise = new WebworkerPromise(worker)\n    return { webWorkerPromise, worker }\n  }\n\n  const compute = async (webWorker, ...args) => {\n    const { webWorkerPromise, worker } = createWorker(webWorker)\n    const result = await webWorkerPromise.exec(operationName, ...args)\n    return { result, webWorker: worker }\n  }\n\n  const workerPool = new WorkerPool(numberOfWorkers, compute)\n\n  return workerPool\n}\n\nexport default webWorkerPromiseWorkerPool\n"
  },
  {
    "path": "src/IO/Compare/.gitignore",
    "content": "/emscripten-build/*\n!emscripten-build/Compare*\noutput.png"
  },
  {
    "path": "src/IO/Compare/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\nproject(Compare)\n\nset(CMAKE_CXX_STANDARD 17)\n\nset(io_components)\nif (NOT EMSCRIPTEN AND NOT WASI)\n  set(io_components\n    ITKIOPNG\n    ITKIOMeta\n    ITKIONRRD\n    )\nendif()\nfind_package(ITK REQUIRED\n  COMPONENTS\n    ${io_components}\n    WebAssemblyInterface\n    ITKImageGrid\n    ITKImageFunction\n    GenericLabelInterpolator\n    ITKImageCompare\n  )\ninclude(${ITK_USE_FILE})\n\nadd_executable(Compare Compare.cxx)\ntarget_link_libraries(Compare PUBLIC ${ITK_LIBRARIES})\n\n"
  },
  {
    "path": "src/IO/Compare/Compare.cxx",
    "content": "/*=========================================================================\n *\n *  Copyright NumFOCUS\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *         http://www.apache.org/licenses/LICENSE-2.0.txt\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n *=========================================================================*/\n#include <fstream>\n#include \"itkVectorImage.h\"\n#include \"itkResampleImageFilter.h\"\n#include \"itkLinearInterpolateImageFunction.h\"\n#include \"itkImageRegionSplitterSlowDimension.h\"\n#include \"itkExtractImageFilter.h\"\n#include \"itkRGBPixel.h\"\n#include \"itkRGBAPixel.h\"\n#include \"itkVectorImage.h\"\n#include \"itkVector.h\"\n#include \"itkPoint.h\"\n#include \"itkCovariantVector.h\"\n#include \"itkFixedArray.h\"\n#include \"itkArray.h\"\n#include \"itkVariableLengthVector.h\"\n#include \"itkPipeline.h\"\n#include \"itkInputImage.h\"\n#include \"itkOutputImage.h\"\n#include \"itkOutputTextStream.h\"\n#include \"itkSupportInputImageTypes.h\"\n#include \"itkCheckerBoardImageFilter.h\"\n#include \"itkIntensityWindowingImageFilter.h\"\n#include \"itkCastImageFilter.h\"\n#include \"itkVectorMagnitudeImageFilter.h\"\n#include \"itkRGBToLuminanceImageFilter.h\"\n#include \"itkComposeImageFilter.h\"\n\ntemplate <typename TMovingImage, typename TFixedImage>\nint Compare(itk::wasm::Pipeline &pipeline, const TMovingImage *movingImage, const TFixedImage *fixedImage)\n{\n  using ImageType = TMovingImage;\n  using FixedImageType = TFixedImage;\n\n  pipeline.get_option(\"input-image\")->required()->type_name(\"INPUT_IMAGE\");\n  pipeline.get_option(\"fixed-image\")->required()->type_name(\"INPUT_IMAGE\");\n\n  bool checkerboard;\n  pipeline.add_option(\"-c,--checkerboard\", checkerboard, \"Do checkerboard filter\");\n\n  std::vector<float> range;\n  pipeline.add_option(\"-r,--range\", range, \"Min and max intensity values of output image\")->expected(2)->delimiter(',');\n\n  std::vector<unsigned int> pattern;\n  pipeline.add_option(\"-p,--pattern\", pattern, \"Number of boxes for each dimension\")->expected(2, 3)->delimiter(',');\n\n  // split args\n  unsigned int maxTotalSplits = 1;\n  pipeline.add_option(\"-m,--max-total-splits\", maxTotalSplits, \"Maximum total splits when processed in parallel\");\n\n  unsigned int split = 0;\n  pipeline.add_option(\"-s,--split\", split, \"Current processed split\");\n\n  itk::wasm::OutputTextStream numberOfSplitsStream;\n  auto numberOfSplitsStreamOption = pipeline.add_option(\"--number-of-splits\", numberOfSplitsStream, \"Number of splits\");\n\n  ITK_WASM_PRE_PARSE(pipeline);\n\n  // Resample moving to fixed image\n  using ResampleFilterType = itk::ResampleImageFilter<ImageType, ImageType>;\n  auto resampleFilter = ResampleFilterType::New();\n  resampleFilter->ReleaseDataFlagOn();\n  resampleFilter->SetInput(movingImage);\n  resampleFilter->SetReferenceImage(fixedImage);\n  resampleFilter->UseReferenceImageOn();\n\n  // rescale intensity and cast PixelType of moving to fixed\n  using RescaleFilterType = itk::IntensityWindowingImageFilter<ImageType, FixedImageType>;\n  auto rescaleFilter = RescaleFilterType::New();\n  rescaleFilter->ReleaseDataFlagOn();\n  rescaleFilter->SetInput(resampleFilter->GetOutput());\n  rescaleFilter->SetWindowMinimum(range[0]);\n  rescaleFilter->SetWindowMaximum(range[1]);\n  rescaleFilter->SetOutputMinimum(range[0]);\n  rescaleFilter->SetOutputMaximum(range[1]);\n\n  using RescaleFilterTypeFixed = itk::IntensityWindowingImageFilter<FixedImageType, FixedImageType>;\n  auto rescaleFilterFixed = RescaleFilterTypeFixed::New();\n  rescaleFilterFixed->ReleaseDataFlagOn();\n  rescaleFilterFixed->SetInput(fixedImage);\n  rescaleFilterFixed->SetWindowMinimum(range[0]);\n  rescaleFilterFixed->SetWindowMaximum(range[1]);\n  rescaleFilterFixed->SetOutputMinimum(range[0]);\n  rescaleFilterFixed->SetOutputMaximum(range[1]);\n\n  using PipelineOutputType = itk::Image<itk::Vector<typename FixedImageType::PixelType, 2>, FixedImageType::ImageDimension>;\n  using FilterType = itk::ComposeImageFilter<FixedImageType, PipelineOutputType>;\n  auto compose = FilterType::New();\n  compose->ReleaseDataFlagOn();\n\n  if (checkerboard)\n  {\n    // Checkerboard images\n    using FilterType = itk::CheckerBoardImageFilter<FixedImageType>;\n    auto check0 = FilterType::New();\n    auto check1 = FilterType::New();\n    check0->ReleaseDataFlagOn();\n    check1->ReleaseDataFlagOn();\n\n    check0->SetInput1(rescaleFilterFixed->GetOutput());\n    check0->SetInput2(rescaleFilter->GetOutput());\n\n    check1->SetInput1(rescaleFilter->GetOutput());\n    check1->SetInput2(rescaleFilterFixed->GetOutput());\n\n    const int dims = pattern.size();\n    if (dims > 0)\n    {\n      typename FilterType::PatternArrayType checkerPattern;\n      for (int i = 0; i < dims; ++i)\n      {\n        checkerPattern[i] = pattern[i];\n      }\n\n      check0->SetCheckerPattern(checkerPattern);\n      check1->SetCheckerPattern(checkerPattern);\n    }\n\n    // Without UpdateLargestPossibleRegion there is a runtime error\n    check0->UpdateLargestPossibleRegion();\n    check1->UpdateLargestPossibleRegion();\n\n    compose->SetInput(0, check0->GetOutput());\n    compose->SetInput(1, check1->GetOutput());\n  }\n  else\n  {\n    // blend green-magenta, cyan-red, or cyan-magenta method\n    compose->SetInput(0, rescaleFilterFixed->GetOutput());\n    compose->SetInput(1, rescaleFilter->GetOutput());\n  }\n\n  using OutputImageType = itk::wasm::OutputImage<PipelineOutputType>;\n  OutputImageType outputImage;\n  pipeline.add_option(\"output-image\", outputImage, \"Output image\")->required()->type_name(\"OUTPUT_IMAGE\");\n\n  ITK_WASM_PARSE(pipeline);\n\n  // Split handling\n  using ROIFilterType = itk::ExtractImageFilter<PipelineOutputType, PipelineOutputType>;\n  compose->UpdateOutputInformation();\n  using RegionType = typename PipelineOutputType::RegionType;\n  const RegionType largestRegion(compose->GetOutput()->GetLargestPossibleRegion());\n\n  using SplitterType = itk::ImageRegionSplitterSlowDimension;\n  auto splitter = SplitterType::New();\n  const unsigned int numberOfSplits = splitter->GetNumberOfSplits(largestRegion, maxTotalSplits);\n\n  if (split >= numberOfSplits)\n  {\n    std::cerr << \"Error: requested split: \" << split << \" is outside the number of splits: \" << numberOfSplits << std::endl;\n    return EXIT_FAILURE;\n  }\n\n  if (!numberOfSplitsStreamOption->empty())\n  {\n    numberOfSplitsStream.Get() << numberOfSplits;\n  }\n\n  RegionType requestedRegion(largestRegion);\n  splitter->GetSplit(split, numberOfSplits, requestedRegion);\n  auto roiFilter = ROIFilterType::New();\n  roiFilter->SetExtractionRegion(requestedRegion);\n  roiFilter->SetInput(compose->GetOutput());\n\n  try\n  {\n    roiFilter->Update();\n  }\n  catch (std::exception &error)\n  {\n    std::cerr << \"Error: \" << error.what() << std::endl;\n    return EXIT_FAILURE;\n  }\n\n  outputImage.Set(roiFilter->GetOutput());\n\n  return EXIT_SUCCESS;\n}\n\nusing MagnitudePixelType = float;\n\ntemplate <typename TImage>\nusing OneComponentImage = typename itk::Image<MagnitudePixelType, TImage::ImageDimension>::ConstPointer;\n\ntemplate <typename TImage>\nusing IsRGB = std::disjunction<\n    std::is_same<typename TImage::PixelType, typename itk::RGBPixel<unsigned char>>,\n    std::is_same<typename TImage::PixelType, typename itk::RGBAPixel<unsigned char>>>;\n\ntemplate <typename TImage>\nusing IsOneComponent = std::is_same<typename TImage::PixelType, typename itk::NumericTraits<typename TImage::PixelType>::ValueType>;\n\n// Vector PixelType, use magnitude filter\ntemplate <typename TImage>\ntypename std::enable_if<!IsRGB<TImage>::value && !IsOneComponent<TImage>::value, OneComponentImage<TImage>>::type\nEnsureOneComponent(const TImage *image)\n{\n  using MagnitudeImageType = itk::Image<MagnitudePixelType, TImage::ImageDimension>;\n  using VectorMagnitudeFilterType = itk::VectorMagnitudeImageFilter<TImage, MagnitudeImageType>;\n  auto magnitudeFilter = VectorMagnitudeFilterType::New();\n  magnitudeFilter->SetInput(image);\n  magnitudeFilter->Update();\n  return magnitudeFilter->GetOutput();\n}\n\n// RGB PixelType, use luminance filter\ntemplate <typename TImage>\ntypename std::enable_if<IsRGB<TImage>::value && !IsOneComponent<TImage>::value, OneComponentImage<TImage>>::type\nEnsureOneComponent(const TImage *image)\n{\n  using MagnitudeImageType = itk::Image<MagnitudePixelType, TImage::ImageDimension>;\n  using LuminanceFilter = itk::RGBToLuminanceImageFilter<TImage, MagnitudeImageType>;\n  auto filter = LuminanceFilter::New();\n  filter->SetInput(image);\n  filter->Update();\n  return filter->GetOutput();\n}\n\n// Scalar type, passthrough image\ntemplate <typename TImage>\ntypename std::enable_if<IsOneComponent<TImage>::value, typename TImage::ConstPointer>::type\nEnsureOneComponent(const TImage *image)\n{\n  return typename TImage::ConstPointer(image);\n}\n\ntemplate <typename TImage>\nclass InputImagePipelineFunctor\n{\n\npublic:\n  int operator()(itk::wasm::Pipeline &pipeline)\n  {\n    using ImageType = TImage;\n    using InputImageType = itk::wasm::InputImage<ImageType>;\n    InputImageType inputImage;\n    pipeline.add_option(\"input-image\", inputImage, \"Input image\");\n\n    ITK_WASM_PRE_PARSE(pipeline);\n\n    typename TImage::ConstPointer image = inputImage.Get();\n    parsedImage = image;\n\n    return itk::wasm::SupportInputImageTypes<FixedImagePipelineFunctor,\n                                             uint8_t,\n                                             int8_t,\n                                             uint16_t,\n                                             int16_t,\n                                             uint32_t,\n                                             int32_t,\n                                             uint64_t,\n                                             int64_t,\n                                             float,\n                                             double,\n                                             itk::RGBPixel<uint8_t>,\n                                             itk::RGBAPixel<uint8_t>,\n                                             itk::VariableLengthVector<uint8_t>,\n                                             itk::VariableLengthVector<int8_t>,\n                                             itk::VariableLengthVector<uint16_t>,\n                                             itk::VariableLengthVector<int16_t>,\n                                             itk::VariableLengthVector<uint32_t>,\n                                             itk::VariableLengthVector<int32_t>,\n                                             itk::VariableLengthVector<uint64_t>,\n                                             itk::VariableLengthVector<int64_t>,\n                                             itk::VariableLengthVector<float>,\n                                             itk::VariableLengthVector<double>,\n                                             itk::Vector<float, 2>,\n                                             itk::Vector<double, 2>,\n                                             itk::Vector<float, 3>,\n                                             itk::Vector<double, 3>,\n                                             itk::Vector<uint8_t, 2>,\n                                             itk::Vector<uint8_t, 3>,\n                                             itk::Vector<uint8_t, 3>,\n                                             itk::Vector<uint8_t, 4>,\n                                             itk::Vector<uint8_t, 4>,\n                                             itk::CovariantVector<float, 2>,\n                                             itk::CovariantVector<double, 2>,\n                                             itk::CovariantVector<float, 3>,\n                                             itk::CovariantVector<double, 3>>::template Dimensions<ImageType::ImageDimension>(\"fixed-image\", pipeline);\n  }\n\nprivate:\n  template <typename TFixedImage>\n  class FixedImagePipelineFunctor\n  {\n  public:\n    int operator()(itk::wasm::Pipeline &pipeline)\n    {\n      using FixedImageType = itk::wasm::InputImage<TFixedImage>;\n      FixedImageType fixedImage;\n      pipeline.add_option(\"fixed-image\", fixedImage, \"Fixed image\");\n\n      ITK_WASM_PRE_PARSE(pipeline);\n\n      const TFixedImage *fixed = fixedImage.Get();\n\n      auto movingScalarImage = EnsureOneComponent<TImage>(parsedImage);\n      auto fixedScalarImage = EnsureOneComponent<TFixedImage>(fixed);\n\n      // The images as SmartPointers may be important to avoid silent failure of Compare() (due to cleanup of image memory?)\n      return Compare(pipeline, movingScalarImage.GetPointer(), fixedScalarImage.GetPointer());\n    }\n  };\n\n  static inline const TImage *parsedImage;\n};\n\nint main(int argc, char *argv[])\n{\n  itk::wasm::Pipeline pipeline(\"compare\", \"Combine two images by method\", argc, argv);\n\n  return itk::wasm::SupportInputImageTypes<InputImagePipelineFunctor,\n                                           uint8_t,\n                                           int8_t,\n                                           uint16_t,\n                                           int16_t,\n                                           uint32_t,\n                                           int32_t,\n                                           uint64_t,\n                                           int64_t,\n                                           float,\n                                           double,\n                                           itk::RGBPixel<uint8_t>,\n                                           itk::RGBAPixel<uint8_t>,\n                                           itk::VariableLengthVector<uint8_t>,\n                                           itk::VariableLengthVector<int8_t>,\n                                           itk::VariableLengthVector<uint16_t>,\n                                           itk::VariableLengthVector<int16_t>,\n                                           itk::VariableLengthVector<uint32_t>,\n                                           itk::VariableLengthVector<int32_t>,\n                                           itk::VariableLengthVector<uint64_t>,\n                                           itk::VariableLengthVector<int64_t>,\n                                           itk::VariableLengthVector<float>,\n                                           itk::VariableLengthVector<double>,\n                                           itk::Vector<float, 2>,\n                                           itk::Vector<double, 2>,\n                                           itk::Vector<float, 3>,\n                                           itk::Vector<double, 3>,\n                                           itk::Vector<uint8_t, 2>,\n                                           itk::Vector<uint8_t, 3>,\n                                           itk::Vector<uint8_t, 3>,\n                                           itk::Vector<uint8_t, 4>,\n                                           itk::CovariantVector<float, 2>,\n                                           itk::CovariantVector<double, 2>,\n                                           itk::CovariantVector<float, 3>,\n                                           itk::CovariantVector<double, 3>>::Dimensions<2U, 3U>(\"input-image\", pipeline);\n}\n"
  },
  {
    "path": "src/IO/Compare/createCompareImage.js",
    "content": "import { runWasm } from '../itkWasmUtils.js'\n\nexport async function createCompareImage(\n  movingImage,\n  fixedImage,\n  { minMax, checkerboard, pattern = undefined }\n) {\n  const clampedPattern = pattern\n    ? fixedImage.size.map((s, idx) => Math.min(s, pattern[idx]))\n    : []\n  const args = [\n    '--checkerboard',\n    checkerboard.toString(),\n    '--range',\n    minMax.join(','),\n    '--pattern',\n    clampedPattern.join(','),\n  ]\n\n  const image = await runWasm({\n    pipeline: 'Compare',\n    args,\n    images: [movingImage, fixedImage],\n    maxSplits: 1,\n  })\n  image.ranges = [minMax, minMax]\n\n  return image\n}\n"
  },
  {
    "path": "src/IO/Compare/emscripten-build/Compare.js",
    "content": "var Compare = (() => {\n  var _scriptDir = import.meta.url\n\n  return async function(Compare) {\n    Compare = Compare || {}\n\n    var Module = typeof Compare != 'undefined' ? Compare : {}\n    var readyPromiseResolve, readyPromiseReject\n    Module['ready'] = new Promise(function(resolve, reject) {\n      readyPromiseResolve = resolve\n      readyPromiseReject = reject\n    })\n    var mStdout = null\n    var mStderr = null\n    Module['resetModuleStdout'] = function() {\n      mStdout = ''\n    }\n    Module['resetModuleStderr'] = function() {\n      mStderr = ''\n    }\n    Module['print'] = function(text) {\n      console.log(text)\n      mStdout += text + '\\n'\n    }\n    Module['printErr'] = function(text) {\n      console.error(text)\n      mStderr += text + '\\n'\n    }\n    Module['getModuleStdout'] = function() {\n      return mStdout\n    }\n    Module['getModuleStderr'] = function() {\n      return mStderr\n    }\n    var moduleOverrides = Object.assign({}, Module)\n    var arguments_ = []\n    var thisProgram = './this.program'\n    var quit_ = (status, toThrow) => {\n      throw toThrow\n    }\n    var ENVIRONMENT_IS_WEB = typeof window == 'object'\n    var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'\n    var ENVIRONMENT_IS_NODE =\n      typeof process == 'object' &&\n      typeof process.versions == 'object' &&\n      typeof process.versions.node == 'string'\n    var scriptDirectory = ''\n    function locateFile(path) {\n      if (Module['locateFile']) {\n        return Module['locateFile'](path, scriptDirectory)\n      }\n      return scriptDirectory + path\n    }\n    var read_, readAsync, readBinary, setWindowTitle\n    function logExceptionOnExit(e) {\n      if (e instanceof ExitStatus) return\n      let toLog = e\n      err('exiting due to exception: ' + toLog)\n    }\n    if (ENVIRONMENT_IS_NODE) {\n      const { createRequire: createRequire } = await import('module')\n      var require = createRequire(import.meta.url)\n      var fs = require('fs')\n      var nodePath = require('path')\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = nodePath.dirname(scriptDirectory) + '/'\n      } else {\n        scriptDirectory = require('url').fileURLToPath(\n          new URL('./', import.meta.url)\n        )\n      }\n      read_ = (filename, binary) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        return fs.readFileSync(filename, binary ? undefined : 'utf8')\n      }\n      readBinary = filename => {\n        var ret = read_(filename, true)\n        if (!ret.buffer) {\n          ret = new Uint8Array(ret)\n        }\n        return ret\n      }\n      readAsync = (filename, onload, onerror) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        fs.readFile(filename, function(err, data) {\n          if (err) onerror(err)\n          else onload(data.buffer)\n        })\n      }\n      if (process['argv'].length > 1) {\n        thisProgram = process['argv'][1].replace(/\\\\/g, '/')\n      }\n      arguments_ = process['argv'].slice(2)\n      process['on']('uncaughtException', function(ex) {\n        if (!(ex instanceof ExitStatus)) {\n          throw ex\n        }\n      })\n      process['on']('unhandledRejection', function(reason) {\n        throw reason\n      })\n      quit_ = (status, toThrow) => {\n        if (keepRuntimeAlive()) {\n          process['exitCode'] = status\n          throw toThrow\n        }\n        logExceptionOnExit(toThrow)\n        process['exit'](status)\n      }\n      Module['inspect'] = function() {\n        return '[Emscripten Module object]'\n      }\n    } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = self.location.href\n      } else if (typeof document != 'undefined' && document.currentScript) {\n        scriptDirectory = document.currentScript.src\n      }\n      if (_scriptDir) {\n        scriptDirectory = _scriptDir\n      }\n      if (scriptDirectory.indexOf('blob:') !== 0) {\n        scriptDirectory = scriptDirectory.substr(\n          0,\n          scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1\n        )\n      } else {\n        scriptDirectory = ''\n      }\n      {\n        read_ = url => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, false)\n          xhr.send(null)\n          return xhr.responseText\n        }\n        if (ENVIRONMENT_IS_WORKER) {\n          readBinary = url => {\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            xhr.responseType = 'arraybuffer'\n            xhr.send(null)\n            return new Uint8Array(xhr.response)\n          }\n        }\n        readAsync = (url, onload, onerror) => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, true)\n          xhr.responseType = 'arraybuffer'\n          xhr.onload = () => {\n            if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n              onload(xhr.response)\n              return\n            }\n            onerror()\n          }\n          xhr.onerror = onerror\n          xhr.send(null)\n        }\n      }\n      setWindowTitle = title => (document.title = title)\n    } else {\n    }\n    var out = Module['print'] || console.log.bind(console)\n    var err = Module['printErr'] || console.warn.bind(console)\n    Object.assign(Module, moduleOverrides)\n    moduleOverrides = null\n    if (Module['arguments']) arguments_ = Module['arguments']\n    if (Module['thisProgram']) thisProgram = Module['thisProgram']\n    if (Module['quit']) quit_ = Module['quit']\n    var wasmBinary\n    if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']\n    var noExitRuntime = Module['noExitRuntime'] || true\n    if (typeof WebAssembly != 'object') {\n      abort('no native wasm support detected')\n    }\n    var wasmMemory\n    var ABORT = false\n    var EXITSTATUS\n    function assert(condition, text) {\n      if (!condition) {\n        abort(text)\n      }\n    }\n    var UTF8Decoder =\n      typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined\n    function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {\n      var endIdx = idx + maxBytesToRead\n      var endPtr = idx\n      while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr\n      if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {\n        return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr))\n      }\n      var str = ''\n      while (idx < endPtr) {\n        var u0 = heapOrArray[idx++]\n        if (!(u0 & 128)) {\n          str += String.fromCharCode(u0)\n          continue\n        }\n        var u1 = heapOrArray[idx++] & 63\n        if ((u0 & 224) == 192) {\n          str += String.fromCharCode(((u0 & 31) << 6) | u1)\n          continue\n        }\n        var u2 = heapOrArray[idx++] & 63\n        if ((u0 & 240) == 224) {\n          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2\n        } else {\n          u0 =\n            ((u0 & 7) << 18) |\n            (u1 << 12) |\n            (u2 << 6) |\n            (heapOrArray[idx++] & 63)\n        }\n        if (u0 < 65536) {\n          str += String.fromCharCode(u0)\n        } else {\n          var ch = u0 - 65536\n          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023))\n        }\n      }\n      return str\n    }\n    function UTF8ToString(ptr, maxBytesToRead) {\n      return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''\n    }\n    function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {\n      if (!(maxBytesToWrite > 0)) return 0\n      var startIdx = outIdx\n      var endIdx = outIdx + maxBytesToWrite - 1\n      for (var i = 0; i < str.length; ++i) {\n        var u = str.charCodeAt(i)\n        if (u >= 55296 && u <= 57343) {\n          var u1 = str.charCodeAt(++i)\n          u = (65536 + ((u & 1023) << 10)) | (u1 & 1023)\n        }\n        if (u <= 127) {\n          if (outIdx >= endIdx) break\n          heap[outIdx++] = u\n        } else if (u <= 2047) {\n          if (outIdx + 1 >= endIdx) break\n          heap[outIdx++] = 192 | (u >> 6)\n          heap[outIdx++] = 128 | (u & 63)\n        } else if (u <= 65535) {\n          if (outIdx + 2 >= endIdx) break\n          heap[outIdx++] = 224 | (u >> 12)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        } else {\n          if (outIdx + 3 >= endIdx) break\n          heap[outIdx++] = 240 | (u >> 18)\n          heap[outIdx++] = 128 | ((u >> 12) & 63)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        }\n      }\n      heap[outIdx] = 0\n      return outIdx - startIdx\n    }\n    function stringToUTF8(str, outPtr, maxBytesToWrite) {\n      return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite)\n    }\n    function lengthBytesUTF8(str) {\n      var len = 0\n      for (var i = 0; i < str.length; ++i) {\n        var c = str.charCodeAt(i)\n        if (c <= 127) {\n          len++\n        } else if (c <= 2047) {\n          len += 2\n        } else if (c >= 55296 && c <= 57343) {\n          len += 4\n          ++i\n        } else {\n          len += 3\n        }\n      }\n      return len\n    }\n    var buffer,\n      HEAP8,\n      HEAPU8,\n      HEAP16,\n      HEAPU16,\n      HEAP32,\n      HEAPU32,\n      HEAPF32,\n      HEAPF64\n    function updateGlobalBufferAndViews(buf) {\n      buffer = buf\n      Module['HEAP8'] = HEAP8 = new Int8Array(buf)\n      Module['HEAP16'] = HEAP16 = new Int16Array(buf)\n      Module['HEAP32'] = HEAP32 = new Int32Array(buf)\n      Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf)\n      Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf)\n      Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf)\n      Module['HEAPF32'] = HEAPF32 = new Float32Array(buf)\n      Module['HEAPF64'] = HEAPF64 = new Float64Array(buf)\n    }\n    var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216\n    var wasmTable\n    var __ATPRERUN__ = []\n    var __ATINIT__ = []\n    var __ATMAIN__ = []\n    var __ATPOSTRUN__ = []\n    var runtimeInitialized = false\n    function keepRuntimeAlive() {\n      return noExitRuntime\n    }\n    function preRun() {\n      if (Module['preRun']) {\n        if (typeof Module['preRun'] == 'function')\n          Module['preRun'] = [Module['preRun']]\n        while (Module['preRun'].length) {\n          addOnPreRun(Module['preRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPRERUN__)\n    }\n    function initRuntime() {\n      runtimeInitialized = true\n      if (!Module['noFSInit'] && !FS.init.initialized) FS.init()\n      FS.ignorePermissions = false\n      TTY.init()\n      callRuntimeCallbacks(__ATINIT__)\n    }\n    function preMain() {\n      callRuntimeCallbacks(__ATMAIN__)\n    }\n    function postRun() {\n      if (Module['postRun']) {\n        if (typeof Module['postRun'] == 'function')\n          Module['postRun'] = [Module['postRun']]\n        while (Module['postRun'].length) {\n          addOnPostRun(Module['postRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPOSTRUN__)\n    }\n    function addOnPreRun(cb) {\n      __ATPRERUN__.unshift(cb)\n    }\n    function addOnInit(cb) {\n      __ATINIT__.unshift(cb)\n    }\n    function addOnPostRun(cb) {\n      __ATPOSTRUN__.unshift(cb)\n    }\n    var runDependencies = 0\n    var runDependencyWatcher = null\n    var dependenciesFulfilled = null\n    function getUniqueRunDependency(id) {\n      return id\n    }\n    function addRunDependency(id) {\n      runDependencies++\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n    }\n    function removeRunDependency(id) {\n      runDependencies--\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n      if (runDependencies == 0) {\n        if (runDependencyWatcher !== null) {\n          clearInterval(runDependencyWatcher)\n          runDependencyWatcher = null\n        }\n        if (dependenciesFulfilled) {\n          var callback = dependenciesFulfilled\n          dependenciesFulfilled = null\n          callback()\n        }\n      }\n    }\n    function abort(what) {\n      if (Module['onAbort']) {\n        Module['onAbort'](what)\n      }\n      what = 'Aborted(' + what + ')'\n      err(what)\n      ABORT = true\n      EXITSTATUS = 1\n      what += '. Build with -sASSERTIONS for more info.'\n      var e = new WebAssembly.RuntimeError(what)\n      readyPromiseReject(e)\n      throw e\n    }\n    var dataURIPrefix = 'data:application/octet-stream;base64,'\n    function isDataURI(filename) {\n      return filename.startsWith(dataURIPrefix)\n    }\n    function isFileURI(filename) {\n      return filename.startsWith('file://')\n    }\n    var wasmBinaryFile\n    if (Module['locateFile']) {\n      wasmBinaryFile = 'Compare.wasm'\n      if (!isDataURI(wasmBinaryFile)) {\n        wasmBinaryFile = locateFile(wasmBinaryFile)\n      }\n    } else {\n      wasmBinaryFile = new URL('Compare.wasm', import.meta.url).href\n    }\n    function getBinary(file) {\n      try {\n        if (file == wasmBinaryFile && wasmBinary) {\n          return new Uint8Array(wasmBinary)\n        }\n        if (readBinary) {\n          return readBinary(file)\n        }\n        throw 'both async and sync fetching of the wasm failed'\n      } catch (err) {\n        abort(err)\n      }\n    }\n    function getBinaryPromise() {\n      if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {\n        if (typeof fetch == 'function' && !isFileURI(wasmBinaryFile)) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' })\n            .then(function(response) {\n              if (!response['ok']) {\n                throw \"failed to load wasm binary file at '\" +\n                  wasmBinaryFile +\n                  \"'\"\n              }\n              return response['arrayBuffer']()\n            })\n            .catch(function() {\n              return getBinary(wasmBinaryFile)\n            })\n        } else {\n          if (readAsync) {\n            return new Promise(function(resolve, reject) {\n              readAsync(\n                wasmBinaryFile,\n                function(response) {\n                  resolve(new Uint8Array(response))\n                },\n                reject\n              )\n            })\n          }\n        }\n      }\n      return Promise.resolve().then(function() {\n        return getBinary(wasmBinaryFile)\n      })\n    }\n    function createWasm() {\n      var info = { a: asmLibraryArg }\n      function receiveInstance(instance, module) {\n        var exports = instance.exports\n        Module['asm'] = exports\n        wasmMemory = Module['asm']['s']\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        wasmTable = Module['asm']['D']\n        addOnInit(Module['asm']['t'])\n        removeRunDependency('wasm-instantiate')\n      }\n      addRunDependency('wasm-instantiate')\n      function receiveInstantiationResult(result) {\n        receiveInstance(result['instance'])\n      }\n      function instantiateArrayBuffer(receiver) {\n        return getBinaryPromise()\n          .then(function(binary) {\n            return WebAssembly.instantiate(binary, info)\n          })\n          .then(function(instance) {\n            return instance\n          })\n          .then(receiver, function(reason) {\n            err('failed to asynchronously prepare wasm: ' + reason)\n            abort(reason)\n          })\n      }\n      function instantiateAsync() {\n        if (\n          !wasmBinary &&\n          typeof WebAssembly.instantiateStreaming == 'function' &&\n          !isDataURI(wasmBinaryFile) &&\n          !isFileURI(wasmBinaryFile) &&\n          !ENVIRONMENT_IS_NODE &&\n          typeof fetch == 'function'\n        ) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(\n            function(response) {\n              var result = WebAssembly.instantiateStreaming(response, info)\n              return result.then(receiveInstantiationResult, function(reason) {\n                err('wasm streaming compile failed: ' + reason)\n                err('falling back to ArrayBuffer instantiation')\n                return instantiateArrayBuffer(receiveInstantiationResult)\n              })\n            }\n          )\n        } else {\n          return instantiateArrayBuffer(receiveInstantiationResult)\n        }\n      }\n      if (Module['instantiateWasm']) {\n        try {\n          var exports = Module['instantiateWasm'](info, receiveInstance)\n          return exports\n        } catch (e) {\n          err('Module.instantiateWasm callback failed with error: ' + e)\n          readyPromiseReject(e)\n        }\n      }\n      instantiateAsync().catch(readyPromiseReject)\n      return {}\n    }\n    var tempDouble\n    var tempI64\n    function ExitStatus(status) {\n      this.name = 'ExitStatus'\n      this.message = 'Program terminated with exit(' + status + ')'\n      this.status = status\n    }\n    function callRuntimeCallbacks(callbacks) {\n      while (callbacks.length > 0) {\n        callbacks.shift()(Module)\n      }\n    }\n    function ExceptionInfo(excPtr) {\n      this.excPtr = excPtr\n      this.ptr = excPtr - 24\n      this.set_type = function(type) {\n        HEAPU32[(this.ptr + 4) >> 2] = type\n      }\n      this.get_type = function() {\n        return HEAPU32[(this.ptr + 4) >> 2]\n      }\n      this.set_destructor = function(destructor) {\n        HEAPU32[(this.ptr + 8) >> 2] = destructor\n      }\n      this.get_destructor = function() {\n        return HEAPU32[(this.ptr + 8) >> 2]\n      }\n      this.set_refcount = function(refcount) {\n        HEAP32[this.ptr >> 2] = refcount\n      }\n      this.set_caught = function(caught) {\n        caught = caught ? 1 : 0\n        HEAP8[(this.ptr + 12) >> 0] = caught\n      }\n      this.get_caught = function() {\n        return HEAP8[(this.ptr + 12) >> 0] != 0\n      }\n      this.set_rethrown = function(rethrown) {\n        rethrown = rethrown ? 1 : 0\n        HEAP8[(this.ptr + 13) >> 0] = rethrown\n      }\n      this.get_rethrown = function() {\n        return HEAP8[(this.ptr + 13) >> 0] != 0\n      }\n      this.init = function(type, destructor) {\n        this.set_adjusted_ptr(0)\n        this.set_type(type)\n        this.set_destructor(destructor)\n        this.set_refcount(0)\n        this.set_caught(false)\n        this.set_rethrown(false)\n      }\n      this.add_ref = function() {\n        var value = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = value + 1\n      }\n      this.release_ref = function() {\n        var prev = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = prev - 1\n        return prev === 1\n      }\n      this.set_adjusted_ptr = function(adjustedPtr) {\n        HEAPU32[(this.ptr + 16) >> 2] = adjustedPtr\n      }\n      this.get_adjusted_ptr = function() {\n        return HEAPU32[(this.ptr + 16) >> 2]\n      }\n      this.get_exception_ptr = function() {\n        var isPointer = ___cxa_is_pointer_type(this.get_type())\n        if (isPointer) {\n          return HEAPU32[this.excPtr >> 2]\n        }\n        var adjusted = this.get_adjusted_ptr()\n        if (adjusted !== 0) return adjusted\n        return this.excPtr\n      }\n    }\n    var exceptionLast = 0\n    var uncaughtExceptionCount = 0\n    function ___cxa_throw(ptr, type, destructor) {\n      var info = new ExceptionInfo(ptr)\n      info.init(type, destructor)\n      exceptionLast = ptr\n      uncaughtExceptionCount++\n      throw ptr\n    }\n    function setErrNo(value) {\n      HEAP32[___errno_location() >> 2] = value\n      return value\n    }\n    var PATH = {\n      isAbs: path => path.charAt(0) === '/',\n      splitPath: filename => {\n        var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/\n        return splitPathRe.exec(filename).slice(1)\n      },\n      normalizeArray: (parts, allowAboveRoot) => {\n        var up = 0\n        for (var i = parts.length - 1; i >= 0; i--) {\n          var last = parts[i]\n          if (last === '.') {\n            parts.splice(i, 1)\n          } else if (last === '..') {\n            parts.splice(i, 1)\n            up++\n          } else if (up) {\n            parts.splice(i, 1)\n            up--\n          }\n        }\n        if (allowAboveRoot) {\n          for (; up; up--) {\n            parts.unshift('..')\n          }\n        }\n        return parts\n      },\n      normalize: path => {\n        var isAbsolute = PATH.isAbs(path),\n          trailingSlash = path.substr(-1) === '/'\n        path = PATH.normalizeArray(\n          path.split('/').filter(p => !!p),\n          !isAbsolute\n        ).join('/')\n        if (!path && !isAbsolute) {\n          path = '.'\n        }\n        if (path && trailingSlash) {\n          path += '/'\n        }\n        return (isAbsolute ? '/' : '') + path\n      },\n      dirname: path => {\n        var result = PATH.splitPath(path),\n          root = result[0],\n          dir = result[1]\n        if (!root && !dir) {\n          return '.'\n        }\n        if (dir) {\n          dir = dir.substr(0, dir.length - 1)\n        }\n        return root + dir\n      },\n      basename: path => {\n        if (path === '/') return '/'\n        path = PATH.normalize(path)\n        path = path.replace(/\\/$/, '')\n        var lastSlash = path.lastIndexOf('/')\n        if (lastSlash === -1) return path\n        return path.substr(lastSlash + 1)\n      },\n      join: function() {\n        var paths = Array.prototype.slice.call(arguments)\n        return PATH.normalize(paths.join('/'))\n      },\n      join2: (l, r) => {\n        return PATH.normalize(l + '/' + r)\n      },\n    }\n    function getRandomDevice() {\n      if (\n        typeof crypto == 'object' &&\n        typeof crypto['getRandomValues'] == 'function'\n      ) {\n        var randomBuffer = new Uint8Array(1)\n        return () => {\n          crypto.getRandomValues(randomBuffer)\n          return randomBuffer[0]\n        }\n      } else if (ENVIRONMENT_IS_NODE) {\n        try {\n          var crypto_module = require('crypto')\n          return () => crypto_module['randomBytes'](1)[0]\n        } catch (e) {}\n      }\n      return () => abort('randomDevice')\n    }\n    var PATH_FS = {\n      resolve: function() {\n        var resolvedPath = '',\n          resolvedAbsolute = false\n        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n          var path = i >= 0 ? arguments[i] : FS.cwd()\n          if (typeof path != 'string') {\n            throw new TypeError('Arguments to path.resolve must be strings')\n          } else if (!path) {\n            return ''\n          }\n          resolvedPath = path + '/' + resolvedPath\n          resolvedAbsolute = PATH.isAbs(path)\n        }\n        resolvedPath = PATH.normalizeArray(\n          resolvedPath.split('/').filter(p => !!p),\n          !resolvedAbsolute\n        ).join('/')\n        return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'\n      },\n      relative: (from, to) => {\n        from = PATH_FS.resolve(from).substr(1)\n        to = PATH_FS.resolve(to).substr(1)\n        function trim(arr) {\n          var start = 0\n          for (; start < arr.length; start++) {\n            if (arr[start] !== '') break\n          }\n          var end = arr.length - 1\n          for (; end >= 0; end--) {\n            if (arr[end] !== '') break\n          }\n          if (start > end) return []\n          return arr.slice(start, end - start + 1)\n        }\n        var fromParts = trim(from.split('/'))\n        var toParts = trim(to.split('/'))\n        var length = Math.min(fromParts.length, toParts.length)\n        var samePartsLength = length\n        for (var i = 0; i < length; i++) {\n          if (fromParts[i] !== toParts[i]) {\n            samePartsLength = i\n            break\n          }\n        }\n        var outputParts = []\n        for (var i = samePartsLength; i < fromParts.length; i++) {\n          outputParts.push('..')\n        }\n        outputParts = outputParts.concat(toParts.slice(samePartsLength))\n        return outputParts.join('/')\n      },\n    }\n    function intArrayFromString(stringy, dontAddNull, length) {\n      var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1\n      var u8array = new Array(len)\n      var numBytesWritten = stringToUTF8Array(\n        stringy,\n        u8array,\n        0,\n        u8array.length\n      )\n      if (dontAddNull) u8array.length = numBytesWritten\n      return u8array\n    }\n    var TTY = {\n      ttys: [],\n      init: function() {},\n      shutdown: function() {},\n      register: function(dev, ops) {\n        TTY.ttys[dev] = { input: [], output: [], ops: ops }\n        FS.registerDevice(dev, TTY.stream_ops)\n      },\n      stream_ops: {\n        open: function(stream) {\n          var tty = TTY.ttys[stream.node.rdev]\n          if (!tty) {\n            throw new FS.ErrnoError(43)\n          }\n          stream.tty = tty\n          stream.seekable = false\n        },\n        close: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        fsync: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        read: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.get_char) {\n            throw new FS.ErrnoError(60)\n          }\n          var bytesRead = 0\n          for (var i = 0; i < length; i++) {\n            var result\n            try {\n              result = stream.tty.ops.get_char(stream.tty)\n            } catch (e) {\n              throw new FS.ErrnoError(29)\n            }\n            if (result === undefined && bytesRead === 0) {\n              throw new FS.ErrnoError(6)\n            }\n            if (result === null || result === undefined) break\n            bytesRead++\n            buffer[offset + i] = result\n          }\n          if (bytesRead) {\n            stream.node.timestamp = Date.now()\n          }\n          return bytesRead\n        },\n        write: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.put_char) {\n            throw new FS.ErrnoError(60)\n          }\n          try {\n            for (var i = 0; i < length; i++) {\n              stream.tty.ops.put_char(stream.tty, buffer[offset + i])\n            }\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n          if (length) {\n            stream.node.timestamp = Date.now()\n          }\n          return i\n        },\n      },\n      default_tty_ops: {\n        get_char: function(tty) {\n          if (!tty.input.length) {\n            var result = null\n            if (ENVIRONMENT_IS_NODE) {\n              var BUFSIZE = 256\n              var buf = Buffer.alloc(BUFSIZE)\n              var bytesRead = 0\n              try {\n                bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, -1)\n              } catch (e) {\n                if (e.toString().includes('EOF')) bytesRead = 0\n                else throw e\n              }\n              if (bytesRead > 0) {\n                result = buf.slice(0, bytesRead).toString('utf-8')\n              } else {\n                result = null\n              }\n            } else if (\n              typeof window != 'undefined' &&\n              typeof window.prompt == 'function'\n            ) {\n              result = window.prompt('Input: ')\n              if (result !== null) {\n                result += '\\n'\n              }\n            } else if (typeof readline == 'function') {\n              result = readline()\n              if (result !== null) {\n                result += '\\n'\n              }\n            }\n            if (!result) {\n              return null\n            }\n            tty.input = intArrayFromString(result, true)\n          }\n          return tty.input.shift()\n        },\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n      default_tty1_ops: {\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n    }\n    function mmapAlloc(size) {\n      abort()\n    }\n    var MEMFS = {\n      ops_table: null,\n      mount: function(mount) {\n        return MEMFS.createNode(null, '/', 16384 | 511, 0)\n      },\n      createNode: function(parent, name, mode, dev) {\n        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n          throw new FS.ErrnoError(63)\n        }\n        if (!MEMFS.ops_table) {\n          MEMFS.ops_table = {\n            dir: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                lookup: MEMFS.node_ops.lookup,\n                mknod: MEMFS.node_ops.mknod,\n                rename: MEMFS.node_ops.rename,\n                unlink: MEMFS.node_ops.unlink,\n                rmdir: MEMFS.node_ops.rmdir,\n                readdir: MEMFS.node_ops.readdir,\n                symlink: MEMFS.node_ops.symlink,\n              },\n              stream: { llseek: MEMFS.stream_ops.llseek },\n            },\n            file: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: {\n                llseek: MEMFS.stream_ops.llseek,\n                read: MEMFS.stream_ops.read,\n                write: MEMFS.stream_ops.write,\n                allocate: MEMFS.stream_ops.allocate,\n                mmap: MEMFS.stream_ops.mmap,\n                msync: MEMFS.stream_ops.msync,\n              },\n            },\n            link: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                readlink: MEMFS.node_ops.readlink,\n              },\n              stream: {},\n            },\n            chrdev: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: FS.chrdev_stream_ops,\n            },\n          }\n        }\n        var node = FS.createNode(parent, name, mode, dev)\n        if (FS.isDir(node.mode)) {\n          node.node_ops = MEMFS.ops_table.dir.node\n          node.stream_ops = MEMFS.ops_table.dir.stream\n          node.contents = {}\n        } else if (FS.isFile(node.mode)) {\n          node.node_ops = MEMFS.ops_table.file.node\n          node.stream_ops = MEMFS.ops_table.file.stream\n          node.usedBytes = 0\n          node.contents = null\n        } else if (FS.isLink(node.mode)) {\n          node.node_ops = MEMFS.ops_table.link.node\n          node.stream_ops = MEMFS.ops_table.link.stream\n        } else if (FS.isChrdev(node.mode)) {\n          node.node_ops = MEMFS.ops_table.chrdev.node\n          node.stream_ops = MEMFS.ops_table.chrdev.stream\n        }\n        node.timestamp = Date.now()\n        if (parent) {\n          parent.contents[name] = node\n          parent.timestamp = node.timestamp\n        }\n        return node\n      },\n      getFileDataAsTypedArray: function(node) {\n        if (!node.contents) return new Uint8Array(0)\n        if (node.contents.subarray)\n          return node.contents.subarray(0, node.usedBytes)\n        return new Uint8Array(node.contents)\n      },\n      expandFileStorage: function(node, newCapacity) {\n        var prevCapacity = node.contents ? node.contents.length : 0\n        if (prevCapacity >= newCapacity) return\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024\n        newCapacity = Math.max(\n          newCapacity,\n          (prevCapacity *\n            (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>>\n            0\n        )\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256)\n        var oldContents = node.contents\n        node.contents = new Uint8Array(newCapacity)\n        if (node.usedBytes > 0)\n          node.contents.set(oldContents.subarray(0, node.usedBytes), 0)\n      },\n      resizeFileStorage: function(node, newSize) {\n        if (node.usedBytes == newSize) return\n        if (newSize == 0) {\n          node.contents = null\n          node.usedBytes = 0\n        } else {\n          var oldContents = node.contents\n          node.contents = new Uint8Array(newSize)\n          if (oldContents) {\n            node.contents.set(\n              oldContents.subarray(0, Math.min(newSize, node.usedBytes))\n            )\n          }\n          node.usedBytes = newSize\n        }\n      },\n      node_ops: {\n        getattr: function(node) {\n          var attr = {}\n          attr.dev = FS.isChrdev(node.mode) ? node.id : 1\n          attr.ino = node.id\n          attr.mode = node.mode\n          attr.nlink = 1\n          attr.uid = 0\n          attr.gid = 0\n          attr.rdev = node.rdev\n          if (FS.isDir(node.mode)) {\n            attr.size = 4096\n          } else if (FS.isFile(node.mode)) {\n            attr.size = node.usedBytes\n          } else if (FS.isLink(node.mode)) {\n            attr.size = node.link.length\n          } else {\n            attr.size = 0\n          }\n          attr.atime = new Date(node.timestamp)\n          attr.mtime = new Date(node.timestamp)\n          attr.ctime = new Date(node.timestamp)\n          attr.blksize = 4096\n          attr.blocks = Math.ceil(attr.size / attr.blksize)\n          return attr\n        },\n        setattr: function(node, attr) {\n          if (attr.mode !== undefined) {\n            node.mode = attr.mode\n          }\n          if (attr.timestamp !== undefined) {\n            node.timestamp = attr.timestamp\n          }\n          if (attr.size !== undefined) {\n            MEMFS.resizeFileStorage(node, attr.size)\n          }\n        },\n        lookup: function(parent, name) {\n          throw FS.genericErrors[44]\n        },\n        mknod: function(parent, name, mode, dev) {\n          return MEMFS.createNode(parent, name, mode, dev)\n        },\n        rename: function(old_node, new_dir, new_name) {\n          if (FS.isDir(old_node.mode)) {\n            var new_node\n            try {\n              new_node = FS.lookupNode(new_dir, new_name)\n            } catch (e) {}\n            if (new_node) {\n              for (var i in new_node.contents) {\n                throw new FS.ErrnoError(55)\n              }\n            }\n          }\n          delete old_node.parent.contents[old_node.name]\n          old_node.parent.timestamp = Date.now()\n          old_node.name = new_name\n          new_dir.contents[new_name] = old_node\n          new_dir.timestamp = old_node.parent.timestamp\n          old_node.parent = new_dir\n        },\n        unlink: function(parent, name) {\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        rmdir: function(parent, name) {\n          var node = FS.lookupNode(parent, name)\n          for (var i in node.contents) {\n            throw new FS.ErrnoError(55)\n          }\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        readdir: function(node) {\n          var entries = ['.', '..']\n          for (var key in node.contents) {\n            if (!node.contents.hasOwnProperty(key)) {\n              continue\n            }\n            entries.push(key)\n          }\n          return entries\n        },\n        symlink: function(parent, newname, oldpath) {\n          var node = MEMFS.createNode(parent, newname, 511 | 40960, 0)\n          node.link = oldpath\n          return node\n        },\n        readlink: function(node) {\n          if (!FS.isLink(node.mode)) {\n            throw new FS.ErrnoError(28)\n          }\n          return node.link\n        },\n      },\n      stream_ops: {\n        read: function(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= stream.node.usedBytes) return 0\n          var size = Math.min(stream.node.usedBytes - position, length)\n          if (size > 8 && contents.subarray) {\n            buffer.set(contents.subarray(position, position + size), offset)\n          } else {\n            for (var i = 0; i < size; i++)\n              buffer[offset + i] = contents[position + i]\n          }\n          return size\n        },\n        write: function(stream, buffer, offset, length, position, canOwn) {\n          if (buffer.buffer === HEAP8.buffer) {\n            canOwn = false\n          }\n          if (!length) return 0\n          var node = stream.node\n          node.timestamp = Date.now()\n          if (buffer.subarray && (!node.contents || node.contents.subarray)) {\n            if (canOwn) {\n              node.contents = buffer.subarray(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (node.usedBytes === 0 && position === 0) {\n              node.contents = buffer.slice(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (position + length <= node.usedBytes) {\n              node.contents.set(\n                buffer.subarray(offset, offset + length),\n                position\n              )\n              return length\n            }\n          }\n          MEMFS.expandFileStorage(node, position + length)\n          if (node.contents.subarray && buffer.subarray) {\n            node.contents.set(\n              buffer.subarray(offset, offset + length),\n              position\n            )\n          } else {\n            for (var i = 0; i < length; i++) {\n              node.contents[position + i] = buffer[offset + i]\n            }\n          }\n          node.usedBytes = Math.max(node.usedBytes, position + length)\n          return length\n        },\n        llseek: function(stream, offset, whence) {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              position += stream.node.usedBytes\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        allocate: function(stream, offset, length) {\n          MEMFS.expandFileStorage(stream.node, offset + length)\n          stream.node.usedBytes = Math.max(\n            stream.node.usedBytes,\n            offset + length\n          )\n        },\n        mmap: function(stream, length, position, prot, flags) {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr\n          var allocated\n          var contents = stream.node.contents\n          if (!(flags & 2) && contents.buffer === buffer) {\n            allocated = false\n            ptr = contents.byteOffset\n          } else {\n            if (position > 0 || position + length < contents.length) {\n              if (contents.subarray) {\n                contents = contents.subarray(position, position + length)\n              } else {\n                contents = Array.prototype.slice.call(\n                  contents,\n                  position,\n                  position + length\n                )\n              }\n            }\n            allocated = true\n            ptr = mmapAlloc(length)\n            if (!ptr) {\n              throw new FS.ErrnoError(48)\n            }\n            HEAP8.set(contents, ptr)\n          }\n          return { ptr: ptr, allocated: allocated }\n        },\n        msync: function(stream, buffer, offset, length, mmapFlags) {\n          MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    function asyncLoad(url, onload, onerror, noRunDep) {\n      var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''\n      readAsync(\n        url,\n        arrayBuffer => {\n          assert(\n            arrayBuffer,\n            'Loading data file \"' + url + '\" failed (no arrayBuffer).'\n          )\n          onload(new Uint8Array(arrayBuffer))\n          if (dep) removeRunDependency(dep)\n        },\n        event => {\n          if (onerror) {\n            onerror()\n          } else {\n            throw 'Loading data file \"' + url + '\" failed.'\n          }\n        }\n      )\n      if (dep) addRunDependency(dep)\n    }\n    var ERRNO_CODES = {}\n    var NODEFS = {\n      isWindows: false,\n      staticInit: () => {\n        NODEFS.isWindows = !!process.platform.match(/^win/)\n        var flags = process['binding']('constants')\n        if (flags['fs']) {\n          flags = flags['fs']\n        }\n        NODEFS.flagsForNodeMap = {\n          1024: flags['O_APPEND'],\n          64: flags['O_CREAT'],\n          128: flags['O_EXCL'],\n          256: flags['O_NOCTTY'],\n          0: flags['O_RDONLY'],\n          2: flags['O_RDWR'],\n          4096: flags['O_SYNC'],\n          512: flags['O_TRUNC'],\n          1: flags['O_WRONLY'],\n          131072: flags['O_NOFOLLOW'],\n        }\n      },\n      convertNodeCode: e => {\n        var code = e.code\n        return ERRNO_CODES[code]\n      },\n      mount: mount => {\n        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0)\n      },\n      createNode: (parent, name, mode, dev) => {\n        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = FS.createNode(parent, name, mode)\n        node.node_ops = NODEFS.node_ops\n        node.stream_ops = NODEFS.stream_ops\n        return node\n      },\n      getMode: path => {\n        var stat\n        try {\n          stat = fs.lstatSync(path)\n          if (NODEFS.isWindows) {\n            stat.mode = stat.mode | ((stat.mode & 292) >> 2)\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n        }\n        return stat.mode\n      },\n      realPath: node => {\n        var parts = []\n        while (node.parent !== node) {\n          parts.push(node.name)\n          node = node.parent\n        }\n        parts.push(node.mount.opts.root)\n        parts.reverse()\n        return PATH.join.apply(null, parts)\n      },\n      flagsForNode: flags => {\n        flags &= ~2097152\n        flags &= ~2048\n        flags &= ~32768\n        flags &= ~524288\n        flags &= ~65536\n        var newFlags = 0\n        for (var k in NODEFS.flagsForNodeMap) {\n          if (flags & k) {\n            newFlags |= NODEFS.flagsForNodeMap[k]\n            flags ^= k\n          }\n        }\n        if (flags) {\n          throw new FS.ErrnoError(28)\n        }\n        return newFlags\n      },\n      node_ops: {\n        getattr: node => {\n          var path = NODEFS.realPath(node)\n          var stat\n          try {\n            stat = fs.lstatSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          if (NODEFS.isWindows && !stat.blksize) {\n            stat.blksize = 4096\n          }\n          if (NODEFS.isWindows && !stat.blocks) {\n            stat.blocks = ((stat.size + stat.blksize - 1) / stat.blksize) | 0\n          }\n          return {\n            dev: stat.dev,\n            ino: stat.ino,\n            mode: stat.mode,\n            nlink: stat.nlink,\n            uid: stat.uid,\n            gid: stat.gid,\n            rdev: stat.rdev,\n            size: stat.size,\n            atime: stat.atime,\n            mtime: stat.mtime,\n            ctime: stat.ctime,\n            blksize: stat.blksize,\n            blocks: stat.blocks,\n          }\n        },\n        setattr: (node, attr) => {\n          var path = NODEFS.realPath(node)\n          try {\n            if (attr.mode !== undefined) {\n              fs.chmodSync(path, attr.mode)\n              node.mode = attr.mode\n            }\n            if (attr.timestamp !== undefined) {\n              var date = new Date(attr.timestamp)\n              fs.utimesSync(path, date, date)\n            }\n            if (attr.size !== undefined) {\n              fs.truncateSync(path, attr.size)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        lookup: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          var mode = NODEFS.getMode(path)\n          return NODEFS.createNode(parent, name, mode)\n        },\n        mknod: (parent, name, mode, dev) => {\n          var node = NODEFS.createNode(parent, name, mode, dev)\n          var path = NODEFS.realPath(node)\n          try {\n            if (FS.isDir(node.mode)) {\n              fs.mkdirSync(path, node.mode)\n            } else {\n              fs.writeFileSync(path, '', { mode: node.mode })\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          return node\n        },\n        rename: (oldNode, newDir, newName) => {\n          var oldPath = NODEFS.realPath(oldNode)\n          var newPath = PATH.join2(NODEFS.realPath(newDir), newName)\n          try {\n            fs.renameSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          oldNode.name = newName\n        },\n        unlink: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.unlinkSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        rmdir: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.rmdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readdir: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            return fs.readdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        symlink: (parent, newName, oldPath) => {\n          var newPath = PATH.join2(NODEFS.realPath(parent), newName)\n          try {\n            fs.symlinkSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readlink: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            path = fs.readlinkSync(path)\n            path = nodePath.relative(\n              nodePath.resolve(node.mount.opts.root),\n              path\n            )\n            return path\n          } catch (e) {\n            if (!e.code) throw e\n            if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28)\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n      },\n      stream_ops: {\n        open: stream => {\n          var path = NODEFS.realPath(stream.node)\n          try {\n            if (FS.isFile(stream.node.mode)) {\n              stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags))\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        close: stream => {\n          try {\n            if (FS.isFile(stream.node.mode) && stream.nfd) {\n              fs.closeSync(stream.nfd)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        read: (stream, buffer, offset, length, position) => {\n          if (length === 0) return 0\n          try {\n            return fs.readSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        write: (stream, buffer, offset, length, position) => {\n          try {\n            return fs.writeSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        llseek: (stream, offset, whence) => {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              try {\n                var stat = fs.fstatSync(stream.nfd)\n                position += stat.size\n              } catch (e) {\n                throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n              }\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        mmap: (stream, length, position, prot, flags) => {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr = mmapAlloc(length)\n          NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        },\n        msync: (stream, buffer, offset, length, mmapFlags) => {\n          NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    var FS = {\n      root: null,\n      mounts: [],\n      devices: {},\n      streams: [],\n      nextInode: 1,\n      nameTable: null,\n      currentPath: '/',\n      initialized: false,\n      ignorePermissions: true,\n      ErrnoError: null,\n      genericErrors: {},\n      filesystems: null,\n      syncFSRequests: 0,\n      lookupPath: (path, opts = {}) => {\n        path = PATH_FS.resolve(path)\n        if (!path) return { path: '', node: null }\n        var defaults = { follow_mount: true, recurse_count: 0 }\n        opts = Object.assign(defaults, opts)\n        if (opts.recurse_count > 8) {\n          throw new FS.ErrnoError(32)\n        }\n        var parts = path.split('/').filter(p => !!p)\n        var current = FS.root\n        var current_path = '/'\n        for (var i = 0; i < parts.length; i++) {\n          var islast = i === parts.length - 1\n          if (islast && opts.parent) {\n            break\n          }\n          current = FS.lookupNode(current, parts[i])\n          current_path = PATH.join2(current_path, parts[i])\n          if (FS.isMountpoint(current)) {\n            if (!islast || (islast && opts.follow_mount)) {\n              current = current.mounted.root\n            }\n          }\n          if (!islast || opts.follow) {\n            var count = 0\n            while (FS.isLink(current.mode)) {\n              var link = FS.readlink(current_path)\n              current_path = PATH_FS.resolve(PATH.dirname(current_path), link)\n              var lookup = FS.lookupPath(current_path, {\n                recurse_count: opts.recurse_count + 1,\n              })\n              current = lookup.node\n              if (count++ > 40) {\n                throw new FS.ErrnoError(32)\n              }\n            }\n          }\n        }\n        return { path: current_path, node: current }\n      },\n      getPath: node => {\n        var path\n        while (true) {\n          if (FS.isRoot(node)) {\n            var mount = node.mount.mountpoint\n            if (!path) return mount\n            return mount[mount.length - 1] !== '/'\n              ? mount + '/' + path\n              : mount + path\n          }\n          path = path ? node.name + '/' + path : node.name\n          node = node.parent\n        }\n      },\n      hashName: (parentid, name) => {\n        var hash = 0\n        for (var i = 0; i < name.length; i++) {\n          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0\n        }\n        return ((parentid + hash) >>> 0) % FS.nameTable.length\n      },\n      hashAddNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        node.name_next = FS.nameTable[hash]\n        FS.nameTable[hash] = node\n      },\n      hashRemoveNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        if (FS.nameTable[hash] === node) {\n          FS.nameTable[hash] = node.name_next\n        } else {\n          var current = FS.nameTable[hash]\n          while (current) {\n            if (current.name_next === node) {\n              current.name_next = node.name_next\n              break\n            }\n            current = current.name_next\n          }\n        }\n      },\n      lookupNode: (parent, name) => {\n        var errCode = FS.mayLookup(parent)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode, parent)\n        }\n        var hash = FS.hashName(parent.id, name)\n        for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n          var nodeName = node.name\n          if (node.parent.id === parent.id && nodeName === name) {\n            return node\n          }\n        }\n        return FS.lookup(parent, name)\n      },\n      createNode: (parent, name, mode, rdev) => {\n        var node = new FS.FSNode(parent, name, mode, rdev)\n        FS.hashAddNode(node)\n        return node\n      },\n      destroyNode: node => {\n        FS.hashRemoveNode(node)\n      },\n      isRoot: node => {\n        return node === node.parent\n      },\n      isMountpoint: node => {\n        return !!node.mounted\n      },\n      isFile: mode => {\n        return (mode & 61440) === 32768\n      },\n      isDir: mode => {\n        return (mode & 61440) === 16384\n      },\n      isLink: mode => {\n        return (mode & 61440) === 40960\n      },\n      isChrdev: mode => {\n        return (mode & 61440) === 8192\n      },\n      isBlkdev: mode => {\n        return (mode & 61440) === 24576\n      },\n      isFIFO: mode => {\n        return (mode & 61440) === 4096\n      },\n      isSocket: mode => {\n        return (mode & 49152) === 49152\n      },\n      flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 },\n      modeStringToFlags: str => {\n        var flags = FS.flagModes[str]\n        if (typeof flags == 'undefined') {\n          throw new Error('Unknown file open mode: ' + str)\n        }\n        return flags\n      },\n      flagsToPermissionString: flag => {\n        var perms = ['r', 'w', 'rw'][flag & 3]\n        if (flag & 512) {\n          perms += 'w'\n        }\n        return perms\n      },\n      nodePermissions: (node, perms) => {\n        if (FS.ignorePermissions) {\n          return 0\n        }\n        if (perms.includes('r') && !(node.mode & 292)) {\n          return 2\n        } else if (perms.includes('w') && !(node.mode & 146)) {\n          return 2\n        } else if (perms.includes('x') && !(node.mode & 73)) {\n          return 2\n        }\n        return 0\n      },\n      mayLookup: dir => {\n        var errCode = FS.nodePermissions(dir, 'x')\n        if (errCode) return errCode\n        if (!dir.node_ops.lookup) return 2\n        return 0\n      },\n      mayCreate: (dir, name) => {\n        try {\n          var node = FS.lookupNode(dir, name)\n          return 20\n        } catch (e) {}\n        return FS.nodePermissions(dir, 'wx')\n      },\n      mayDelete: (dir, name, isdir) => {\n        var node\n        try {\n          node = FS.lookupNode(dir, name)\n        } catch (e) {\n          return e.errno\n        }\n        var errCode = FS.nodePermissions(dir, 'wx')\n        if (errCode) {\n          return errCode\n        }\n        if (isdir) {\n          if (!FS.isDir(node.mode)) {\n            return 54\n          }\n          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n            return 10\n          }\n        } else {\n          if (FS.isDir(node.mode)) {\n            return 31\n          }\n        }\n        return 0\n      },\n      mayOpen: (node, flags) => {\n        if (!node) {\n          return 44\n        }\n        if (FS.isLink(node.mode)) {\n          return 32\n        } else if (FS.isDir(node.mode)) {\n          if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) {\n            return 31\n          }\n        }\n        return FS.nodePermissions(node, FS.flagsToPermissionString(flags))\n      },\n      MAX_OPEN_FDS: 4096,\n      nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => {\n        for (var fd = fd_start; fd <= fd_end; fd++) {\n          if (!FS.streams[fd]) {\n            return fd\n          }\n        }\n        throw new FS.ErrnoError(33)\n      },\n      getStream: fd => FS.streams[fd],\n      createStream: (stream, fd_start, fd_end) => {\n        if (!FS.FSStream) {\n          FS.FSStream = function() {\n            this.shared = {}\n          }\n          FS.FSStream.prototype = {}\n          Object.defineProperties(FS.FSStream.prototype, {\n            object: {\n              get: function() {\n                return this.node\n              },\n              set: function(val) {\n                this.node = val\n              },\n            },\n            isRead: {\n              get: function() {\n                return (this.flags & 2097155) !== 1\n              },\n            },\n            isWrite: {\n              get: function() {\n                return (this.flags & 2097155) !== 0\n              },\n            },\n            isAppend: {\n              get: function() {\n                return this.flags & 1024\n              },\n            },\n            flags: {\n              get: function() {\n                return this.shared.flags\n              },\n              set: function(val) {\n                this.shared.flags = val\n              },\n            },\n            position: {\n              get: function() {\n                return this.shared.position\n              },\n              set: function(val) {\n                this.shared.position = val\n              },\n            },\n          })\n        }\n        stream = Object.assign(new FS.FSStream(), stream)\n        var fd = FS.nextfd(fd_start, fd_end)\n        stream.fd = fd\n        FS.streams[fd] = stream\n        return stream\n      },\n      closeStream: fd => {\n        FS.streams[fd] = null\n      },\n      chrdev_stream_ops: {\n        open: stream => {\n          var device = FS.getDevice(stream.node.rdev)\n          stream.stream_ops = device.stream_ops\n          if (stream.stream_ops.open) {\n            stream.stream_ops.open(stream)\n          }\n        },\n        llseek: () => {\n          throw new FS.ErrnoError(70)\n        },\n      },\n      major: dev => dev >> 8,\n      minor: dev => dev & 255,\n      makedev: (ma, mi) => (ma << 8) | mi,\n      registerDevice: (dev, ops) => {\n        FS.devices[dev] = { stream_ops: ops }\n      },\n      getDevice: dev => FS.devices[dev],\n      getMounts: mount => {\n        var mounts = []\n        var check = [mount]\n        while (check.length) {\n          var m = check.pop()\n          mounts.push(m)\n          check.push.apply(check, m.mounts)\n        }\n        return mounts\n      },\n      syncfs: (populate, callback) => {\n        if (typeof populate == 'function') {\n          callback = populate\n          populate = false\n        }\n        FS.syncFSRequests++\n        if (FS.syncFSRequests > 1) {\n          err(\n            'warning: ' +\n              FS.syncFSRequests +\n              ' FS.syncfs operations in flight at once, probably just doing extra work'\n          )\n        }\n        var mounts = FS.getMounts(FS.root.mount)\n        var completed = 0\n        function doCallback(errCode) {\n          FS.syncFSRequests--\n          return callback(errCode)\n        }\n        function done(errCode) {\n          if (errCode) {\n            if (!done.errored) {\n              done.errored = true\n              return doCallback(errCode)\n            }\n            return\n          }\n          if (++completed >= mounts.length) {\n            doCallback(null)\n          }\n        }\n        mounts.forEach(mount => {\n          if (!mount.type.syncfs) {\n            return done(null)\n          }\n          mount.type.syncfs(mount, populate, done)\n        })\n      },\n      mount: (type, opts, mountpoint) => {\n        var root = mountpoint === '/'\n        var pseudo = !mountpoint\n        var node\n        if (root && FS.root) {\n          throw new FS.ErrnoError(10)\n        } else if (!root && !pseudo) {\n          var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n          mountpoint = lookup.path\n          node = lookup.node\n          if (FS.isMountpoint(node)) {\n            throw new FS.ErrnoError(10)\n          }\n          if (!FS.isDir(node.mode)) {\n            throw new FS.ErrnoError(54)\n          }\n        }\n        var mount = {\n          type: type,\n          opts: opts,\n          mountpoint: mountpoint,\n          mounts: [],\n        }\n        var mountRoot = type.mount(mount)\n        mountRoot.mount = mount\n        mount.root = mountRoot\n        if (root) {\n          FS.root = mountRoot\n        } else if (node) {\n          node.mounted = mount\n          if (node.mount) {\n            node.mount.mounts.push(mount)\n          }\n        }\n        return mountRoot\n      },\n      unmount: mountpoint => {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n        if (!FS.isMountpoint(lookup.node)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = lookup.node\n        var mount = node.mounted\n        var mounts = FS.getMounts(mount)\n        Object.keys(FS.nameTable).forEach(hash => {\n          var current = FS.nameTable[hash]\n          while (current) {\n            var next = current.name_next\n            if (mounts.includes(current.mount)) {\n              FS.destroyNode(current)\n            }\n            current = next\n          }\n        })\n        node.mounted = null\n        var idx = node.mount.mounts.indexOf(mount)\n        node.mount.mounts.splice(idx, 1)\n      },\n      lookup: (parent, name) => {\n        return parent.node_ops.lookup(parent, name)\n      },\n      mknod: (path, mode, dev) => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        if (!name || name === '.' || name === '..') {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.mayCreate(parent, name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.mknod) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.mknod(parent, name, mode, dev)\n      },\n      create: (path, mode) => {\n        mode = mode !== undefined ? mode : 438\n        mode &= 4095\n        mode |= 32768\n        return FS.mknod(path, mode, 0)\n      },\n      mkdir: (path, mode) => {\n        mode = mode !== undefined ? mode : 511\n        mode &= 511 | 512\n        mode |= 16384\n        return FS.mknod(path, mode, 0)\n      },\n      mkdirTree: (path, mode) => {\n        var dirs = path.split('/')\n        var d = ''\n        for (var i = 0; i < dirs.length; ++i) {\n          if (!dirs[i]) continue\n          d += '/' + dirs[i]\n          try {\n            FS.mkdir(d, mode)\n          } catch (e) {\n            if (e.errno != 20) throw e\n          }\n        }\n      },\n      mkdev: (path, mode, dev) => {\n        if (typeof dev == 'undefined') {\n          dev = mode\n          mode = 438\n        }\n        mode |= 8192\n        return FS.mknod(path, mode, dev)\n      },\n      symlink: (oldpath, newpath) => {\n        if (!PATH_FS.resolve(oldpath)) {\n          throw new FS.ErrnoError(44)\n        }\n        var lookup = FS.lookupPath(newpath, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var newname = PATH.basename(newpath)\n        var errCode = FS.mayCreate(parent, newname)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.symlink) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.symlink(parent, newname, oldpath)\n      },\n      rename: (old_path, new_path) => {\n        var old_dirname = PATH.dirname(old_path)\n        var new_dirname = PATH.dirname(new_path)\n        var old_name = PATH.basename(old_path)\n        var new_name = PATH.basename(new_path)\n        var lookup, old_dir, new_dir\n        lookup = FS.lookupPath(old_path, { parent: true })\n        old_dir = lookup.node\n        lookup = FS.lookupPath(new_path, { parent: true })\n        new_dir = lookup.node\n        if (!old_dir || !new_dir) throw new FS.ErrnoError(44)\n        if (old_dir.mount !== new_dir.mount) {\n          throw new FS.ErrnoError(75)\n        }\n        var old_node = FS.lookupNode(old_dir, old_name)\n        var relative = PATH_FS.relative(old_path, new_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(28)\n        }\n        relative = PATH_FS.relative(new_path, old_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(55)\n        }\n        var new_node\n        try {\n          new_node = FS.lookupNode(new_dir, new_name)\n        } catch (e) {}\n        if (old_node === new_node) {\n          return\n        }\n        var isdir = FS.isDir(old_node.mode)\n        var errCode = FS.mayDelete(old_dir, old_name, isdir)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        errCode = new_node\n          ? FS.mayDelete(new_dir, new_name, isdir)\n          : FS.mayCreate(new_dir, new_name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!old_dir.node_ops.rename) {\n          throw new FS.ErrnoError(63)\n        }\n        if (\n          FS.isMountpoint(old_node) ||\n          (new_node && FS.isMountpoint(new_node))\n        ) {\n          throw new FS.ErrnoError(10)\n        }\n        if (new_dir !== old_dir) {\n          errCode = FS.nodePermissions(old_dir, 'w')\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        FS.hashRemoveNode(old_node)\n        try {\n          old_dir.node_ops.rename(old_node, new_dir, new_name)\n        } catch (e) {\n          throw e\n        } finally {\n          FS.hashAddNode(old_node)\n        }\n      },\n      rmdir: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, true)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.rmdir) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.rmdir(parent, name)\n        FS.destroyNode(node)\n      },\n      readdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        if (!node.node_ops.readdir) {\n          throw new FS.ErrnoError(54)\n        }\n        return node.node_ops.readdir(node)\n      },\n      unlink: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, false)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.unlink) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.unlink(parent, name)\n        FS.destroyNode(node)\n      },\n      readlink: path => {\n        var lookup = FS.lookupPath(path)\n        var link = lookup.node\n        if (!link) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!link.node_ops.readlink) {\n          throw new FS.ErrnoError(28)\n        }\n        return PATH_FS.resolve(\n          FS.getPath(link.parent),\n          link.node_ops.readlink(link)\n        )\n      },\n      stat: (path, dontFollow) => {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow })\n        var node = lookup.node\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!node.node_ops.getattr) {\n          throw new FS.ErrnoError(63)\n        }\n        return node.node_ops.getattr(node)\n      },\n      lstat: path => {\n        return FS.stat(path, true)\n      },\n      chmod: (path, mode, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, {\n          mode: (mode & 4095) | (node.mode & ~4095),\n          timestamp: Date.now(),\n        })\n      },\n      lchmod: (path, mode) => {\n        FS.chmod(path, mode, true)\n      },\n      fchmod: (fd, mode) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chmod(stream.node, mode)\n      },\n      chown: (path, uid, gid, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, { timestamp: Date.now() })\n      },\n      lchown: (path, uid, gid) => {\n        FS.chown(path, uid, gid, true)\n      },\n      fchown: (fd, uid, gid) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chown(stream.node, uid, gid)\n      },\n      truncate: (path, len) => {\n        if (len < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: true })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!FS.isFile(node.mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.nodePermissions(node, 'w')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        node.node_ops.setattr(node, { size: len, timestamp: Date.now() })\n      },\n      ftruncate: (fd, len) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(28)\n        }\n        FS.truncate(stream.node, len)\n      },\n      utime: (path, atime, mtime) => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) })\n      },\n      open: (path, flags, mode) => {\n        if (path === '') {\n          throw new FS.ErrnoError(44)\n        }\n        flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags\n        mode = typeof mode == 'undefined' ? 438 : mode\n        if (flags & 64) {\n          mode = (mode & 4095) | 32768\n        } else {\n          mode = 0\n        }\n        var node\n        if (typeof path == 'object') {\n          node = path\n        } else {\n          path = PATH.normalize(path)\n          try {\n            var lookup = FS.lookupPath(path, { follow: !(flags & 131072) })\n            node = lookup.node\n          } catch (e) {}\n        }\n        var created = false\n        if (flags & 64) {\n          if (node) {\n            if (flags & 128) {\n              throw new FS.ErrnoError(20)\n            }\n          } else {\n            node = FS.mknod(path, mode, 0)\n            created = true\n          }\n        }\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (FS.isChrdev(node.mode)) {\n          flags &= ~512\n        }\n        if (flags & 65536 && !FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        if (!created) {\n          var errCode = FS.mayOpen(node, flags)\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        if (flags & 512 && !created) {\n          FS.truncate(node, 0)\n        }\n        flags &= ~(128 | 512 | 131072)\n        var stream = FS.createStream({\n          node: node,\n          path: FS.getPath(node),\n          flags: flags,\n          seekable: true,\n          position: 0,\n          stream_ops: node.stream_ops,\n          ungotten: [],\n          error: false,\n        })\n        if (stream.stream_ops.open) {\n          stream.stream_ops.open(stream)\n        }\n        if (Module['logReadFiles'] && !(flags & 1)) {\n          if (!FS.readFiles) FS.readFiles = {}\n          if (!(path in FS.readFiles)) {\n            FS.readFiles[path] = 1\n          }\n        }\n        return stream\n      },\n      close: stream => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (stream.getdents) stream.getdents = null\n        try {\n          if (stream.stream_ops.close) {\n            stream.stream_ops.close(stream)\n          }\n        } catch (e) {\n          throw e\n        } finally {\n          FS.closeStream(stream.fd)\n        }\n        stream.fd = null\n      },\n      isClosed: stream => {\n        return stream.fd === null\n      },\n      llseek: (stream, offset, whence) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!stream.seekable || !stream.stream_ops.llseek) {\n          throw new FS.ErrnoError(70)\n        }\n        if (whence != 0 && whence != 1 && whence != 2) {\n          throw new FS.ErrnoError(28)\n        }\n        stream.position = stream.stream_ops.llseek(stream, offset, whence)\n        stream.ungotten = []\n        return stream.position\n      },\n      read: (stream, buffer, offset, length, position) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.read) {\n          throw new FS.ErrnoError(28)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesRead = stream.stream_ops.read(\n          stream,\n          buffer,\n          offset,\n          length,\n          position\n        )\n        if (!seeking) stream.position += bytesRead\n        return bytesRead\n      },\n      write: (stream, buffer, offset, length, position, canOwn) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.write) {\n          throw new FS.ErrnoError(28)\n        }\n        if (stream.seekable && stream.flags & 1024) {\n          FS.llseek(stream, 0, 2)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesWritten = stream.stream_ops.write(\n          stream,\n          buffer,\n          offset,\n          length,\n          position,\n          canOwn\n        )\n        if (!seeking) stream.position += bytesWritten\n        return bytesWritten\n      },\n      allocate: (stream, offset, length) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (offset < 0 || length <= 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (!stream.stream_ops.allocate) {\n          throw new FS.ErrnoError(138)\n        }\n        stream.stream_ops.allocate(stream, offset, length)\n      },\n      mmap: (stream, length, position, prot, flags) => {\n        if (\n          (prot & 2) !== 0 &&\n          (flags & 2) === 0 &&\n          (stream.flags & 2097155) !== 2\n        ) {\n          throw new FS.ErrnoError(2)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(2)\n        }\n        if (!stream.stream_ops.mmap) {\n          throw new FS.ErrnoError(43)\n        }\n        return stream.stream_ops.mmap(stream, length, position, prot, flags)\n      },\n      msync: (stream, buffer, offset, length, mmapFlags) => {\n        if (!stream.stream_ops.msync) {\n          return 0\n        }\n        return stream.stream_ops.msync(\n          stream,\n          buffer,\n          offset,\n          length,\n          mmapFlags\n        )\n      },\n      munmap: stream => 0,\n      ioctl: (stream, cmd, arg) => {\n        if (!stream.stream_ops.ioctl) {\n          throw new FS.ErrnoError(59)\n        }\n        return stream.stream_ops.ioctl(stream, cmd, arg)\n      },\n      readFile: (path, opts = {}) => {\n        opts.flags = opts.flags || 0\n        opts.encoding = opts.encoding || 'binary'\n        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {\n          throw new Error('Invalid encoding type \"' + opts.encoding + '\"')\n        }\n        var ret\n        var stream = FS.open(path, opts.flags)\n        var stat = FS.stat(path)\n        var length = stat.size\n        var buf = new Uint8Array(length)\n        FS.read(stream, buf, 0, length, 0)\n        if (opts.encoding === 'utf8') {\n          ret = UTF8ArrayToString(buf, 0)\n        } else if (opts.encoding === 'binary') {\n          ret = buf\n        }\n        FS.close(stream)\n        return ret\n      },\n      writeFile: (path, data, opts = {}) => {\n        opts.flags = opts.flags || 577\n        var stream = FS.open(path, opts.flags, opts.mode)\n        if (typeof data == 'string') {\n          var buf = new Uint8Array(lengthBytesUTF8(data) + 1)\n          var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length)\n          FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn)\n        } else if (ArrayBuffer.isView(data)) {\n          FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn)\n        } else {\n          throw new Error('Unsupported data type')\n        }\n        FS.close(stream)\n      },\n      cwd: () => FS.currentPath,\n      chdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        if (lookup.node === null) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!FS.isDir(lookup.node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        var errCode = FS.nodePermissions(lookup.node, 'x')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        FS.currentPath = lookup.path\n      },\n      createDefaultDirectories: () => {\n        FS.mkdir('/tmp')\n        FS.mkdir('/home')\n        FS.mkdir('/home/web_user')\n      },\n      createDefaultDevices: () => {\n        FS.mkdir('/dev')\n        FS.registerDevice(FS.makedev(1, 3), {\n          read: () => 0,\n          write: (stream, buffer, offset, length, pos) => length,\n        })\n        FS.mkdev('/dev/null', FS.makedev(1, 3))\n        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops)\n        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops)\n        FS.mkdev('/dev/tty', FS.makedev(5, 0))\n        FS.mkdev('/dev/tty1', FS.makedev(6, 0))\n        var random_device = getRandomDevice()\n        FS.createDevice('/dev', 'random', random_device)\n        FS.createDevice('/dev', 'urandom', random_device)\n        FS.mkdir('/dev/shm')\n        FS.mkdir('/dev/shm/tmp')\n      },\n      createSpecialDirectories: () => {\n        FS.mkdir('/proc')\n        var proc_self = FS.mkdir('/proc/self')\n        FS.mkdir('/proc/self/fd')\n        FS.mount(\n          {\n            mount: () => {\n              var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73)\n              node.node_ops = {\n                lookup: (parent, name) => {\n                  var fd = +name\n                  var stream = FS.getStream(fd)\n                  if (!stream) throw new FS.ErrnoError(8)\n                  var ret = {\n                    parent: null,\n                    mount: { mountpoint: 'fake' },\n                    node_ops: { readlink: () => stream.path },\n                  }\n                  ret.parent = ret\n                  return ret\n                },\n              }\n              return node\n            },\n          },\n          {},\n          '/proc/self/fd'\n        )\n      },\n      createStandardStreams: () => {\n        if (Module['stdin']) {\n          FS.createDevice('/dev', 'stdin', Module['stdin'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdin')\n        }\n        if (Module['stdout']) {\n          FS.createDevice('/dev', 'stdout', null, Module['stdout'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdout')\n        }\n        if (Module['stderr']) {\n          FS.createDevice('/dev', 'stderr', null, Module['stderr'])\n        } else {\n          FS.symlink('/dev/tty1', '/dev/stderr')\n        }\n        var stdin = FS.open('/dev/stdin', 0)\n        var stdout = FS.open('/dev/stdout', 1)\n        var stderr = FS.open('/dev/stderr', 1)\n      },\n      ensureErrnoError: () => {\n        if (FS.ErrnoError) return\n        FS.ErrnoError = function ErrnoError(errno, node) {\n          this.node = node\n          this.setErrno = function(errno) {\n            this.errno = errno\n          }\n          this.setErrno(errno)\n          this.message = 'FS error'\n        }\n        FS.ErrnoError.prototype = new Error()\n        FS.ErrnoError.prototype.constructor = FS.ErrnoError\n        ;[44].forEach(code => {\n          FS.genericErrors[code] = new FS.ErrnoError(code)\n          FS.genericErrors[code].stack = '<generic error, no stack>'\n        })\n      },\n      staticInit: () => {\n        FS.ensureErrnoError()\n        FS.nameTable = new Array(4096)\n        FS.mount(MEMFS, {}, '/')\n        FS.createDefaultDirectories()\n        FS.createDefaultDevices()\n        FS.createSpecialDirectories()\n        FS.filesystems = { MEMFS: MEMFS, NODEFS: NODEFS }\n      },\n      init: (input, output, error) => {\n        FS.init.initialized = true\n        FS.ensureErrnoError()\n        Module['stdin'] = input || Module['stdin']\n        Module['stdout'] = output || Module['stdout']\n        Module['stderr'] = error || Module['stderr']\n        FS.createStandardStreams()\n      },\n      quit: () => {\n        FS.init.initialized = false\n        for (var i = 0; i < FS.streams.length; i++) {\n          var stream = FS.streams[i]\n          if (!stream) {\n            continue\n          }\n          FS.close(stream)\n        }\n      },\n      getMode: (canRead, canWrite) => {\n        var mode = 0\n        if (canRead) mode |= 292 | 73\n        if (canWrite) mode |= 146\n        return mode\n      },\n      findObject: (path, dontResolveLastLink) => {\n        var ret = FS.analyzePath(path, dontResolveLastLink)\n        if (!ret.exists) {\n          return null\n        }\n        return ret.object\n      },\n      analyzePath: (path, dontResolveLastLink) => {\n        try {\n          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          path = lookup.path\n        } catch (e) {}\n        var ret = {\n          isRoot: false,\n          exists: false,\n          error: 0,\n          name: null,\n          path: null,\n          object: null,\n          parentExists: false,\n          parentPath: null,\n          parentObject: null,\n        }\n        try {\n          var lookup = FS.lookupPath(path, { parent: true })\n          ret.parentExists = true\n          ret.parentPath = lookup.path\n          ret.parentObject = lookup.node\n          ret.name = PATH.basename(path)\n          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          ret.exists = true\n          ret.path = lookup.path\n          ret.object = lookup.node\n          ret.name = lookup.node.name\n          ret.isRoot = lookup.path === '/'\n        } catch (e) {\n          ret.error = e.errno\n        }\n        return ret\n      },\n      createPath: (parent, path, canRead, canWrite) => {\n        parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n        var parts = path.split('/').reverse()\n        while (parts.length) {\n          var part = parts.pop()\n          if (!part) continue\n          var current = PATH.join2(parent, part)\n          try {\n            FS.mkdir(current)\n          } catch (e) {}\n          parent = current\n        }\n        return current\n      },\n      createFile: (parent, name, properties, canRead, canWrite) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(canRead, canWrite)\n        return FS.create(path, mode)\n      },\n      createDataFile: (parent, name, data, canRead, canWrite, canOwn) => {\n        var path = name\n        if (parent) {\n          parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n          path = name ? PATH.join2(parent, name) : parent\n        }\n        var mode = FS.getMode(canRead, canWrite)\n        var node = FS.create(path, mode)\n        if (data) {\n          if (typeof data == 'string') {\n            var arr = new Array(data.length)\n            for (var i = 0, len = data.length; i < len; ++i)\n              arr[i] = data.charCodeAt(i)\n            data = arr\n          }\n          FS.chmod(node, mode | 146)\n          var stream = FS.open(node, 577)\n          FS.write(stream, data, 0, data.length, 0, canOwn)\n          FS.close(stream)\n          FS.chmod(node, mode)\n        }\n        return node\n      },\n      createDevice: (parent, name, input, output) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(!!input, !!output)\n        if (!FS.createDevice.major) FS.createDevice.major = 64\n        var dev = FS.makedev(FS.createDevice.major++, 0)\n        FS.registerDevice(dev, {\n          open: stream => {\n            stream.seekable = false\n          },\n          close: stream => {\n            if (output && output.buffer && output.buffer.length) {\n              output(10)\n            }\n          },\n          read: (stream, buffer, offset, length, pos) => {\n            var bytesRead = 0\n            for (var i = 0; i < length; i++) {\n              var result\n              try {\n                result = input()\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n              if (result === undefined && bytesRead === 0) {\n                throw new FS.ErrnoError(6)\n              }\n              if (result === null || result === undefined) break\n              bytesRead++\n              buffer[offset + i] = result\n            }\n            if (bytesRead) {\n              stream.node.timestamp = Date.now()\n            }\n            return bytesRead\n          },\n          write: (stream, buffer, offset, length, pos) => {\n            for (var i = 0; i < length; i++) {\n              try {\n                output(buffer[offset + i])\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n            }\n            if (length) {\n              stream.node.timestamp = Date.now()\n            }\n            return i\n          },\n        })\n        return FS.mkdev(path, mode, dev)\n      },\n      forceLoadFile: obj => {\n        if (obj.isDevice || obj.isFolder || obj.link || obj.contents)\n          return true\n        if (typeof XMLHttpRequest != 'undefined') {\n          throw new Error(\n            'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.'\n          )\n        } else if (read_) {\n          try {\n            obj.contents = intArrayFromString(read_(obj.url), true)\n            obj.usedBytes = obj.contents.length\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n        } else {\n          throw new Error('Cannot load without read() or XMLHttpRequest.')\n        }\n      },\n      createLazyFile: (parent, name, url, canRead, canWrite) => {\n        function LazyUint8Array() {\n          this.lengthKnown = false\n          this.chunks = []\n        }\n        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n          if (idx > this.length - 1 || idx < 0) {\n            return undefined\n          }\n          var chunkOffset = idx % this.chunkSize\n          var chunkNum = (idx / this.chunkSize) | 0\n          return this.getter(chunkNum)[chunkOffset]\n        }\n        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(\n          getter\n        ) {\n          this.getter = getter\n        }\n        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n          var xhr = new XMLHttpRequest()\n          xhr.open('HEAD', url, false)\n          xhr.send(null)\n          if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n            throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n          var datalength = Number(xhr.getResponseHeader('Content-length'))\n          var header\n          var hasByteServing =\n            (header = xhr.getResponseHeader('Accept-Ranges')) &&\n            header === 'bytes'\n          var usesGzip =\n            (header = xhr.getResponseHeader('Content-Encoding')) &&\n            header === 'gzip'\n          var chunkSize = 1024 * 1024\n          if (!hasByteServing) chunkSize = datalength\n          var doXHR = (from, to) => {\n            if (from > to)\n              throw new Error(\n                'invalid range (' +\n                  from +\n                  ', ' +\n                  to +\n                  ') or no bytes requested!'\n              )\n            if (to > datalength - 1)\n              throw new Error(\n                'only ' + datalength + ' bytes available! programmer error!'\n              )\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            if (datalength !== chunkSize)\n              xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to)\n            xhr.responseType = 'arraybuffer'\n            if (xhr.overrideMimeType) {\n              xhr.overrideMimeType('text/plain; charset=x-user-defined')\n            }\n            xhr.send(null)\n            if (\n              !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)\n            )\n              throw new Error(\n                \"Couldn't load \" + url + '. Status: ' + xhr.status\n              )\n            if (xhr.response !== undefined) {\n              return new Uint8Array(xhr.response || [])\n            }\n            return intArrayFromString(xhr.responseText || '', true)\n          }\n          var lazyArray = this\n          lazyArray.setDataGetter(chunkNum => {\n            var start = chunkNum * chunkSize\n            var end = (chunkNum + 1) * chunkSize - 1\n            end = Math.min(end, datalength - 1)\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined') {\n              lazyArray.chunks[chunkNum] = doXHR(start, end)\n            }\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined')\n              throw new Error('doXHR failed!')\n            return lazyArray.chunks[chunkNum]\n          })\n          if (usesGzip || !datalength) {\n            chunkSize = datalength = 1\n            datalength = this.getter(0).length\n            chunkSize = datalength\n            out(\n              'LazyFiles on gzip forces download of the whole file when length is accessed'\n            )\n          }\n          this._length = datalength\n          this._chunkSize = chunkSize\n          this.lengthKnown = true\n        }\n        if (typeof XMLHttpRequest != 'undefined') {\n          if (!ENVIRONMENT_IS_WORKER)\n            throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'\n          var lazyArray = new LazyUint8Array()\n          Object.defineProperties(lazyArray, {\n            length: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._length\n              },\n            },\n            chunkSize: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._chunkSize\n              },\n            },\n          })\n          var properties = { isDevice: false, contents: lazyArray }\n        } else {\n          var properties = { isDevice: false, url: url }\n        }\n        var node = FS.createFile(parent, name, properties, canRead, canWrite)\n        if (properties.contents) {\n          node.contents = properties.contents\n        } else if (properties.url) {\n          node.contents = null\n          node.url = properties.url\n        }\n        Object.defineProperties(node, {\n          usedBytes: {\n            get: function() {\n              return this.contents.length\n            },\n          },\n        })\n        var stream_ops = {}\n        var keys = Object.keys(node.stream_ops)\n        keys.forEach(key => {\n          var fn = node.stream_ops[key]\n          stream_ops[key] = function forceLoadLazyFile() {\n            FS.forceLoadFile(node)\n            return fn.apply(null, arguments)\n          }\n        })\n        function writeChunks(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= contents.length) return 0\n          var size = Math.min(contents.length - position, length)\n          if (contents.slice) {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents[position + i]\n            }\n          } else {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents.get(position + i)\n            }\n          }\n          return size\n        }\n        stream_ops.read = (stream, buffer, offset, length, position) => {\n          FS.forceLoadFile(node)\n          return writeChunks(stream, buffer, offset, length, position)\n        }\n        stream_ops.mmap = (stream, length, position, prot, flags) => {\n          FS.forceLoadFile(node)\n          var ptr = mmapAlloc(length)\n          if (!ptr) {\n            throw new FS.ErrnoError(48)\n          }\n          writeChunks(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        }\n        node.stream_ops = stream_ops\n        return node\n      },\n      createPreloadedFile: (\n        parent,\n        name,\n        url,\n        canRead,\n        canWrite,\n        onload,\n        onerror,\n        dontCreateFile,\n        canOwn,\n        preFinish\n      ) => {\n        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent\n        var dep = getUniqueRunDependency('cp ' + fullname)\n        function processData(byteArray) {\n          function finish(byteArray) {\n            if (preFinish) preFinish()\n            if (!dontCreateFile) {\n              FS.createDataFile(\n                parent,\n                name,\n                byteArray,\n                canRead,\n                canWrite,\n                canOwn\n              )\n            }\n            if (onload) onload()\n            removeRunDependency(dep)\n          }\n          if (\n            Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => {\n              if (onerror) onerror()\n              removeRunDependency(dep)\n            })\n          ) {\n            return\n          }\n          finish(byteArray)\n        }\n        addRunDependency(dep)\n        if (typeof url == 'string') {\n          asyncLoad(url, byteArray => processData(byteArray), onerror)\n        } else {\n          processData(url)\n        }\n      },\n      indexedDB: () => {\n        return (\n          window.indexedDB ||\n          window.mozIndexedDB ||\n          window.webkitIndexedDB ||\n          window.msIndexedDB\n        )\n      },\n      DB_NAME: () => {\n        return 'EM_FS_' + window.location.pathname\n      },\n      DB_VERSION: 20,\n      DB_STORE_NAME: 'FILE_DATA',\n      saveFilesToDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = () => {\n          out('creating db')\n          var db = openRequest.result\n          db.createObjectStore(FS.DB_STORE_NAME)\n        }\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite')\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var putRequest = files.put(\n              FS.analyzePath(path).object.contents,\n              path\n            )\n            putRequest.onsuccess = () => {\n              ok++\n              if (ok + fail == total) finish()\n            }\n            putRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n      loadFilesFromDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = onerror\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          try {\n            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly')\n          } catch (e) {\n            onerror(e)\n            return\n          }\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var getRequest = files.get(path)\n            getRequest.onsuccess = () => {\n              if (FS.analyzePath(path).exists) {\n                FS.unlink(path)\n              }\n              FS.createDataFile(\n                PATH.dirname(path),\n                PATH.basename(path),\n                getRequest.result,\n                true,\n                true,\n                true\n              )\n              ok++\n              if (ok + fail == total) finish()\n            }\n            getRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n    }\n    var SYSCALLS = {\n      DEFAULT_POLLMASK: 5,\n      calculateAt: function(dirfd, path, allowEmpty) {\n        if (PATH.isAbs(path)) {\n          return path\n        }\n        var dir\n        if (dirfd === -100) {\n          dir = FS.cwd()\n        } else {\n          var dirstream = SYSCALLS.getStreamFromFD(dirfd)\n          dir = dirstream.path\n        }\n        if (path.length == 0) {\n          if (!allowEmpty) {\n            throw new FS.ErrnoError(44)\n          }\n          return dir\n        }\n        return PATH.join2(dir, path)\n      },\n      doStat: function(func, path, buf) {\n        try {\n          var stat = func(path)\n        } catch (e) {\n          if (\n            e &&\n            e.node &&\n            PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))\n          ) {\n            return -54\n          }\n          throw e\n        }\n        HEAP32[buf >> 2] = stat.dev\n        HEAP32[(buf + 8) >> 2] = stat.ino\n        HEAP32[(buf + 12) >> 2] = stat.mode\n        HEAPU32[(buf + 16) >> 2] = stat.nlink\n        HEAP32[(buf + 20) >> 2] = stat.uid\n        HEAP32[(buf + 24) >> 2] = stat.gid\n        HEAP32[(buf + 28) >> 2] = stat.rdev\n        ;(tempI64 = [\n          stat.size >>> 0,\n          ((tempDouble = stat.size),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 40) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 44) >> 2] = tempI64[1])\n        HEAP32[(buf + 48) >> 2] = 4096\n        HEAP32[(buf + 52) >> 2] = stat.blocks\n        var atime = stat.atime.getTime()\n        var mtime = stat.mtime.getTime()\n        var ctime = stat.ctime.getTime()\n        ;(tempI64 = [\n          Math.floor(atime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(atime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 56) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 60) >> 2] = tempI64[1])\n        HEAPU32[(buf + 64) >> 2] = (atime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(mtime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(mtime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 72) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 76) >> 2] = tempI64[1])\n        HEAPU32[(buf + 80) >> 2] = (mtime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(ctime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(ctime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 88) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 92) >> 2] = tempI64[1])\n        HEAPU32[(buf + 96) >> 2] = (ctime % 1e3) * 1e3\n        ;(tempI64 = [\n          stat.ino >>> 0,\n          ((tempDouble = stat.ino),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 104) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 108) >> 2] = tempI64[1])\n        return 0\n      },\n      doMsync: function(addr, stream, len, flags, offset) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (flags & 2) {\n          return 0\n        }\n        var buffer = HEAPU8.slice(addr, addr + len)\n        FS.msync(stream, buffer, offset, len, flags)\n      },\n      varargs: undefined,\n      get: function() {\n        SYSCALLS.varargs += 4\n        var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]\n        return ret\n      },\n      getStr: function(ptr) {\n        var ret = UTF8ToString(ptr)\n        return ret\n      },\n      getStreamFromFD: function(fd) {\n        var stream = FS.getStream(fd)\n        if (!stream) throw new FS.ErrnoError(8)\n        return stream\n      },\n    }\n    function ___syscall_fcntl64(fd, cmd, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (cmd) {\n          case 0: {\n            var arg = SYSCALLS.get()\n            if (arg < 0) {\n              return -28\n            }\n            var newStream\n            newStream = FS.createStream(stream, arg)\n            return newStream.fd\n          }\n          case 1:\n          case 2:\n            return 0\n          case 3:\n            return stream.flags\n          case 4: {\n            var arg = SYSCALLS.get()\n            stream.flags |= arg\n            return 0\n          }\n          case 5: {\n            var arg = SYSCALLS.get()\n            var offset = 0\n            HEAP16[(arg + offset) >> 1] = 2\n            return 0\n          }\n          case 6:\n          case 7:\n            return 0\n          case 16:\n          case 8:\n            return -28\n          case 9:\n            setErrNo(28)\n            return -1\n          default: {\n            return -28\n          }\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_getcwd(buf, size) {\n      try {\n        if (size === 0) return -28\n        var cwd = FS.cwd()\n        var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1\n        if (size < cwdLengthInBytes) return -68\n        stringToUTF8(cwd, buf, size)\n        return cwdLengthInBytes\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_ioctl(fd, op, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (op) {\n          case 21509:\n          case 21505: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21510:\n          case 21511:\n          case 21512:\n          case 21506:\n          case 21507:\n          case 21508: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21519: {\n            if (!stream.tty) return -59\n            var argp = SYSCALLS.get()\n            HEAP32[argp >> 2] = 0\n            return 0\n          }\n          case 21520: {\n            if (!stream.tty) return -59\n            return -28\n          }\n          case 21531: {\n            var argp = SYSCALLS.get()\n            return FS.ioctl(stream, op, argp)\n          }\n          case 21523: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21524: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          default:\n            return -28\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_openat(dirfd, path, flags, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        var mode = varargs ? SYSCALLS.get() : 0\n        return FS.open(path, flags, mode).fd\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_readlinkat(dirfd, path, buf, bufsize) {\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        if (bufsize <= 0) return -28\n        var ret = FS.readlink(path)\n        var len = Math.min(bufsize, lengthBytesUTF8(ret))\n        var endChar = HEAP8[buf + len]\n        stringToUTF8(ret, buf, bufsize + 1)\n        HEAP8[buf + len] = endChar\n        return len\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_stat64(path, buf) {\n      try {\n        path = SYSCALLS.getStr(path)\n        return SYSCALLS.doStat(FS.stat, path, buf)\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function _abort() {\n      abort('')\n    }\n    function _emscripten_memcpy_big(dest, src, num) {\n      HEAPU8.copyWithin(dest, src, src + num)\n    }\n    function getHeapMax() {\n      return 2147483648\n    }\n    function emscripten_realloc_buffer(size) {\n      try {\n        wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16)\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        return 1\n      } catch (e) {}\n    }\n    function _emscripten_resize_heap(requestedSize) {\n      var oldSize = HEAPU8.length\n      requestedSize = requestedSize >>> 0\n      var maxHeapSize = getHeapMax()\n      if (requestedSize > maxHeapSize) {\n        return false\n      }\n      let alignUp = (x, multiple) =>\n        x + ((multiple - (x % multiple)) % multiple)\n      for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {\n        var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown)\n        overGrownHeapSize = Math.min(\n          overGrownHeapSize,\n          requestedSize + 100663296\n        )\n        var newSize = Math.min(\n          maxHeapSize,\n          alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)\n        )\n        var replacement = emscripten_realloc_buffer(newSize)\n        if (replacement) {\n          return true\n        }\n      }\n      return false\n    }\n    var ENV = {}\n    function getExecutableName() {\n      return thisProgram || './this.program'\n    }\n    function getEnvStrings() {\n      if (!getEnvStrings.strings) {\n        var lang =\n          (\n            (typeof navigator == 'object' &&\n              navigator.languages &&\n              navigator.languages[0]) ||\n            'C'\n          ).replace('-', '_') + '.UTF-8'\n        var env = {\n          USER: 'web_user',\n          LOGNAME: 'web_user',\n          PATH: '/',\n          PWD: '/',\n          HOME: '/home/web_user',\n          LANG: lang,\n          _: getExecutableName(),\n        }\n        for (var x in ENV) {\n          if (ENV[x] === undefined) delete env[x]\n          else env[x] = ENV[x]\n        }\n        var strings = []\n        for (var x in env) {\n          strings.push(x + '=' + env[x])\n        }\n        getEnvStrings.strings = strings\n      }\n      return getEnvStrings.strings\n    }\n    function writeAsciiToMemory(str, buffer, dontAddNull) {\n      for (var i = 0; i < str.length; ++i) {\n        HEAP8[buffer++ >> 0] = str.charCodeAt(i)\n      }\n      if (!dontAddNull) HEAP8[buffer >> 0] = 0\n    }\n    function _environ_get(__environ, environ_buf) {\n      var bufSize = 0\n      getEnvStrings().forEach(function(string, i) {\n        var ptr = environ_buf + bufSize\n        HEAPU32[(__environ + i * 4) >> 2] = ptr\n        writeAsciiToMemory(string, ptr)\n        bufSize += string.length + 1\n      })\n      return 0\n    }\n    function _environ_sizes_get(penviron_count, penviron_buf_size) {\n      var strings = getEnvStrings()\n      HEAPU32[penviron_count >> 2] = strings.length\n      var bufSize = 0\n      strings.forEach(function(string) {\n        bufSize += string.length + 1\n      })\n      HEAPU32[penviron_buf_size >> 2] = bufSize\n      return 0\n    }\n    function _proc_exit(code) {\n      EXITSTATUS = code\n      if (!keepRuntimeAlive()) {\n        if (Module['onExit']) Module['onExit'](code)\n        ABORT = true\n      }\n      quit_(code, new ExitStatus(code))\n    }\n    function exitJS(status, implicit) {\n      EXITSTATUS = status\n      _proc_exit(status)\n    }\n    var _exit = exitJS\n    function _fd_close(fd) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.close(stream)\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doReadv(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.read(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n        if (curr < len) break\n      }\n      return ret\n    }\n    function _fd_read(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doReadv(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function convertI32PairToI53Checked(lo, hi) {\n      return (hi + 2097152) >>> 0 < 4194305 - !!lo\n        ? (lo >>> 0) + hi * 4294967296\n        : NaN\n    }\n    function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {\n      try {\n        var offset = convertI32PairToI53Checked(offset_low, offset_high)\n        if (isNaN(offset)) return 61\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.llseek(stream, offset, whence)\n        ;(tempI64 = [\n          stream.position >>> 0,\n          ((tempDouble = stream.position),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[newOffset >> 2] = tempI64[0]),\n          (HEAP32[(newOffset + 4) >> 2] = tempI64[1])\n        if (stream.getdents && offset === 0 && whence === 0)\n          stream.getdents = null\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doWritev(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.write(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n      }\n      return ret\n    }\n    function _fd_write(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doWritev(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function __isLeapYear(year) {\n      return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n    }\n    function __arraySum(array, index) {\n      var sum = 0\n      for (var i = 0; i <= index; sum += array[i++]) {}\n      return sum\n    }\n    var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    function __addDays(date, days) {\n      var newDate = new Date(date.getTime())\n      while (days > 0) {\n        var leap = __isLeapYear(newDate.getFullYear())\n        var currentMonth = newDate.getMonth()\n        var daysInCurrentMonth = (leap\n          ? __MONTH_DAYS_LEAP\n          : __MONTH_DAYS_REGULAR)[currentMonth]\n        if (days > daysInCurrentMonth - newDate.getDate()) {\n          days -= daysInCurrentMonth - newDate.getDate() + 1\n          newDate.setDate(1)\n          if (currentMonth < 11) {\n            newDate.setMonth(currentMonth + 1)\n          } else {\n            newDate.setMonth(0)\n            newDate.setFullYear(newDate.getFullYear() + 1)\n          }\n        } else {\n          newDate.setDate(newDate.getDate() + days)\n          return newDate\n        }\n      }\n      return newDate\n    }\n    function writeArrayToMemory(array, buffer) {\n      HEAP8.set(array, buffer)\n    }\n    function _strftime(s, maxsize, format, tm) {\n      var tm_zone = HEAP32[(tm + 40) >> 2]\n      var date = {\n        tm_sec: HEAP32[tm >> 2],\n        tm_min: HEAP32[(tm + 4) >> 2],\n        tm_hour: HEAP32[(tm + 8) >> 2],\n        tm_mday: HEAP32[(tm + 12) >> 2],\n        tm_mon: HEAP32[(tm + 16) >> 2],\n        tm_year: HEAP32[(tm + 20) >> 2],\n        tm_wday: HEAP32[(tm + 24) >> 2],\n        tm_yday: HEAP32[(tm + 28) >> 2],\n        tm_isdst: HEAP32[(tm + 32) >> 2],\n        tm_gmtoff: HEAP32[(tm + 36) >> 2],\n        tm_zone: tm_zone ? UTF8ToString(tm_zone) : '',\n      }\n      var pattern = UTF8ToString(format)\n      var EXPANSION_RULES_1 = {\n        '%c': '%a %b %d %H:%M:%S %Y',\n        '%D': '%m/%d/%y',\n        '%F': '%Y-%m-%d',\n        '%h': '%b',\n        '%r': '%I:%M:%S %p',\n        '%R': '%H:%M',\n        '%T': '%H:%M:%S',\n        '%x': '%m/%d/%y',\n        '%X': '%H:%M:%S',\n        '%Ec': '%c',\n        '%EC': '%C',\n        '%Ex': '%m/%d/%y',\n        '%EX': '%H:%M:%S',\n        '%Ey': '%y',\n        '%EY': '%Y',\n        '%Od': '%d',\n        '%Oe': '%e',\n        '%OH': '%H',\n        '%OI': '%I',\n        '%Om': '%m',\n        '%OM': '%M',\n        '%OS': '%S',\n        '%Ou': '%u',\n        '%OU': '%U',\n        '%OV': '%V',\n        '%Ow': '%w',\n        '%OW': '%W',\n        '%Oy': '%y',\n      }\n      for (var rule in EXPANSION_RULES_1) {\n        pattern = pattern.replace(\n          new RegExp(rule, 'g'),\n          EXPANSION_RULES_1[rule]\n        )\n      }\n      var WEEKDAYS = [\n        'Sunday',\n        'Monday',\n        'Tuesday',\n        'Wednesday',\n        'Thursday',\n        'Friday',\n        'Saturday',\n      ]\n      var MONTHS = [\n        'January',\n        'February',\n        'March',\n        'April',\n        'May',\n        'June',\n        'July',\n        'August',\n        'September',\n        'October',\n        'November',\n        'December',\n      ]\n      function leadingSomething(value, digits, character) {\n        var str = typeof value == 'number' ? value.toString() : value || ''\n        while (str.length < digits) {\n          str = character[0] + str\n        }\n        return str\n      }\n      function leadingNulls(value, digits) {\n        return leadingSomething(value, digits, '0')\n      }\n      function compareByDay(date1, date2) {\n        function sgn(value) {\n          return value < 0 ? -1 : value > 0 ? 1 : 0\n        }\n        var compare\n        if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) {\n          if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) {\n            compare = sgn(date1.getDate() - date2.getDate())\n          }\n        }\n        return compare\n      }\n      function getFirstWeekStartDate(janFourth) {\n        switch (janFourth.getDay()) {\n          case 0:\n            return new Date(janFourth.getFullYear() - 1, 11, 29)\n          case 1:\n            return janFourth\n          case 2:\n            return new Date(janFourth.getFullYear(), 0, 3)\n          case 3:\n            return new Date(janFourth.getFullYear(), 0, 2)\n          case 4:\n            return new Date(janFourth.getFullYear(), 0, 1)\n          case 5:\n            return new Date(janFourth.getFullYear() - 1, 11, 31)\n          case 6:\n            return new Date(janFourth.getFullYear() - 1, 11, 30)\n        }\n      }\n      function getWeekBasedYear(date) {\n        var thisDate = __addDays(\n          new Date(date.tm_year + 1900, 0, 1),\n          date.tm_yday\n        )\n        var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4)\n        var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4)\n        var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear)\n        var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear)\n        if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {\n          if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {\n            return thisDate.getFullYear() + 1\n          }\n          return thisDate.getFullYear()\n        }\n        return thisDate.getFullYear() - 1\n      }\n      var EXPANSION_RULES_2 = {\n        '%a': function(date) {\n          return WEEKDAYS[date.tm_wday].substring(0, 3)\n        },\n        '%A': function(date) {\n          return WEEKDAYS[date.tm_wday]\n        },\n        '%b': function(date) {\n          return MONTHS[date.tm_mon].substring(0, 3)\n        },\n        '%B': function(date) {\n          return MONTHS[date.tm_mon]\n        },\n        '%C': function(date) {\n          var year = date.tm_year + 1900\n          return leadingNulls((year / 100) | 0, 2)\n        },\n        '%d': function(date) {\n          return leadingNulls(date.tm_mday, 2)\n        },\n        '%e': function(date) {\n          return leadingSomething(date.tm_mday, 2, ' ')\n        },\n        '%g': function(date) {\n          return getWeekBasedYear(date)\n            .toString()\n            .substring(2)\n        },\n        '%G': function(date) {\n          return getWeekBasedYear(date)\n        },\n        '%H': function(date) {\n          return leadingNulls(date.tm_hour, 2)\n        },\n        '%I': function(date) {\n          var twelveHour = date.tm_hour\n          if (twelveHour == 0) twelveHour = 12\n          else if (twelveHour > 12) twelveHour -= 12\n          return leadingNulls(twelveHour, 2)\n        },\n        '%j': function(date) {\n          return leadingNulls(\n            date.tm_mday +\n              __arraySum(\n                __isLeapYear(date.tm_year + 1900)\n                  ? __MONTH_DAYS_LEAP\n                  : __MONTH_DAYS_REGULAR,\n                date.tm_mon - 1\n              ),\n            3\n          )\n        },\n        '%m': function(date) {\n          return leadingNulls(date.tm_mon + 1, 2)\n        },\n        '%M': function(date) {\n          return leadingNulls(date.tm_min, 2)\n        },\n        '%n': function() {\n          return '\\n'\n        },\n        '%p': function(date) {\n          if (date.tm_hour >= 0 && date.tm_hour < 12) {\n            return 'AM'\n          }\n          return 'PM'\n        },\n        '%S': function(date) {\n          return leadingNulls(date.tm_sec, 2)\n        },\n        '%t': function() {\n          return '\\t'\n        },\n        '%u': function(date) {\n          return date.tm_wday || 7\n        },\n        '%U': function(date) {\n          var days = date.tm_yday + 7 - date.tm_wday\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%V': function(date) {\n          var val = Math.floor(\n            (date.tm_yday + 7 - ((date.tm_wday + 6) % 7)) / 7\n          )\n          if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) {\n            val++\n          }\n          if (!val) {\n            val = 52\n            var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7\n            if (\n              dec31 == 4 ||\n              (dec31 == 5 && __isLeapYear((date.tm_year % 400) - 1))\n            ) {\n              val++\n            }\n          } else if (val == 53) {\n            var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7\n            if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) val = 1\n          }\n          return leadingNulls(val, 2)\n        },\n        '%w': function(date) {\n          return date.tm_wday\n        },\n        '%W': function(date) {\n          var days = date.tm_yday + 7 - ((date.tm_wday + 6) % 7)\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%y': function(date) {\n          return (date.tm_year + 1900).toString().substring(2)\n        },\n        '%Y': function(date) {\n          return date.tm_year + 1900\n        },\n        '%z': function(date) {\n          var off = date.tm_gmtoff\n          var ahead = off >= 0\n          off = Math.abs(off) / 60\n          off = (off / 60) * 100 + (off % 60)\n          return (ahead ? '+' : '-') + String('0000' + off).slice(-4)\n        },\n        '%Z': function(date) {\n          return date.tm_zone\n        },\n        '%%': function() {\n          return '%'\n        },\n      }\n      pattern = pattern.replace(/%%/g, '\\0\\0')\n      for (var rule in EXPANSION_RULES_2) {\n        if (pattern.includes(rule)) {\n          pattern = pattern.replace(\n            new RegExp(rule, 'g'),\n            EXPANSION_RULES_2[rule](date)\n          )\n        }\n      }\n      pattern = pattern.replace(/\\0\\0/g, '%')\n      var bytes = intArrayFromString(pattern, false)\n      if (bytes.length > maxsize) {\n        return 0\n      }\n      writeArrayToMemory(bytes, s)\n      return bytes.length - 1\n    }\n    function _strftime_l(s, maxsize, format, tm, loc) {\n      return _strftime(s, maxsize, format, tm)\n    }\n    function handleException(e) {\n      if (e instanceof ExitStatus || e == 'unwind') {\n        return EXITSTATUS\n      }\n      quit_(1, e)\n    }\n    function allocateUTF8OnStack(str) {\n      var size = lengthBytesUTF8(str) + 1\n      var ret = stackAlloc(size)\n      stringToUTF8Array(str, HEAP8, ret, size)\n      return ret\n    }\n    function getCFunc(ident) {\n      var func = Module['_' + ident]\n      return func\n    }\n    function ccall(ident, returnType, argTypes, args, opts) {\n      var toC = {\n        string: str => {\n          var ret = 0\n          if (str !== null && str !== undefined && str !== 0) {\n            var len = (str.length << 2) + 1\n            ret = stackAlloc(len)\n            stringToUTF8(str, ret, len)\n          }\n          return ret\n        },\n        array: arr => {\n          var ret = stackAlloc(arr.length)\n          writeArrayToMemory(arr, ret)\n          return ret\n        },\n      }\n      function convertReturnValue(ret) {\n        if (returnType === 'string') {\n          return UTF8ToString(ret)\n        }\n        if (returnType === 'boolean') return Boolean(ret)\n        return ret\n      }\n      var func = getCFunc(ident)\n      var cArgs = []\n      var stack = 0\n      if (args) {\n        for (var i = 0; i < args.length; i++) {\n          var converter = toC[argTypes[i]]\n          if (converter) {\n            if (stack === 0) stack = stackSave()\n            cArgs[i] = converter(args[i])\n          } else {\n            cArgs[i] = args[i]\n          }\n        }\n      }\n      var ret = func.apply(null, cArgs)\n      function onDone(ret) {\n        if (stack !== 0) stackRestore(stack)\n        return convertReturnValue(ret)\n      }\n      ret = onDone(ret)\n      return ret\n    }\n    function cwrap(ident, returnType, argTypes, opts) {\n      argTypes = argTypes || []\n      var numericArgs = argTypes.every(\n        type => type === 'number' || type === 'boolean'\n      )\n      var numericRet = returnType !== 'string'\n      if (numericRet && numericArgs && !opts) {\n        return getCFunc(ident)\n      }\n      return function() {\n        return ccall(ident, returnType, argTypes, arguments, opts)\n      }\n    }\n    function AsciiToString(ptr) {\n      var str = ''\n      while (1) {\n        var ch = HEAPU8[ptr++ >> 0]\n        if (!ch) return str\n        str += String.fromCharCode(ch)\n      }\n    }\n    var FSNode = function(parent, name, mode, rdev) {\n      if (!parent) {\n        parent = this\n      }\n      this.parent = parent\n      this.mount = parent.mount\n      this.mounted = null\n      this.id = FS.nextInode++\n      this.name = name\n      this.mode = mode\n      this.node_ops = {}\n      this.stream_ops = {}\n      this.rdev = rdev\n    }\n    var readMode = 292 | 73\n    var writeMode = 146\n    Object.defineProperties(FSNode.prototype, {\n      read: {\n        get: function() {\n          return (this.mode & readMode) === readMode\n        },\n        set: function(val) {\n          val ? (this.mode |= readMode) : (this.mode &= ~readMode)\n        },\n      },\n      write: {\n        get: function() {\n          return (this.mode & writeMode) === writeMode\n        },\n        set: function(val) {\n          val ? (this.mode |= writeMode) : (this.mode &= ~writeMode)\n        },\n      },\n      isFolder: {\n        get: function() {\n          return FS.isDir(this.mode)\n        },\n      },\n      isDevice: {\n        get: function() {\n          return FS.isChrdev(this.mode)\n        },\n      },\n    })\n    FS.FSNode = FSNode\n    FS.staticInit()\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_unlink'] = FS.unlink\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    if (ENVIRONMENT_IS_NODE) {\n      NODEFS.staticInit()\n    }\n    ERRNO_CODES = {\n      EPERM: 63,\n      ENOENT: 44,\n      ESRCH: 71,\n      EINTR: 27,\n      EIO: 29,\n      ENXIO: 60,\n      E2BIG: 1,\n      ENOEXEC: 45,\n      EBADF: 8,\n      ECHILD: 12,\n      EAGAIN: 6,\n      EWOULDBLOCK: 6,\n      ENOMEM: 48,\n      EACCES: 2,\n      EFAULT: 21,\n      ENOTBLK: 105,\n      EBUSY: 10,\n      EEXIST: 20,\n      EXDEV: 75,\n      ENODEV: 43,\n      ENOTDIR: 54,\n      EISDIR: 31,\n      EINVAL: 28,\n      ENFILE: 41,\n      EMFILE: 33,\n      ENOTTY: 59,\n      ETXTBSY: 74,\n      EFBIG: 22,\n      ENOSPC: 51,\n      ESPIPE: 70,\n      EROFS: 69,\n      EMLINK: 34,\n      EPIPE: 64,\n      EDOM: 18,\n      ERANGE: 68,\n      ENOMSG: 49,\n      EIDRM: 24,\n      ECHRNG: 106,\n      EL2NSYNC: 156,\n      EL3HLT: 107,\n      EL3RST: 108,\n      ELNRNG: 109,\n      EUNATCH: 110,\n      ENOCSI: 111,\n      EL2HLT: 112,\n      EDEADLK: 16,\n      ENOLCK: 46,\n      EBADE: 113,\n      EBADR: 114,\n      EXFULL: 115,\n      ENOANO: 104,\n      EBADRQC: 103,\n      EBADSLT: 102,\n      EDEADLOCK: 16,\n      EBFONT: 101,\n      ENOSTR: 100,\n      ENODATA: 116,\n      ETIME: 117,\n      ENOSR: 118,\n      ENONET: 119,\n      ENOPKG: 120,\n      EREMOTE: 121,\n      ENOLINK: 47,\n      EADV: 122,\n      ESRMNT: 123,\n      ECOMM: 124,\n      EPROTO: 65,\n      EMULTIHOP: 36,\n      EDOTDOT: 125,\n      EBADMSG: 9,\n      ENOTUNIQ: 126,\n      EBADFD: 127,\n      EREMCHG: 128,\n      ELIBACC: 129,\n      ELIBBAD: 130,\n      ELIBSCN: 131,\n      ELIBMAX: 132,\n      ELIBEXEC: 133,\n      ENOSYS: 52,\n      ENOTEMPTY: 55,\n      ENAMETOOLONG: 37,\n      ELOOP: 32,\n      EOPNOTSUPP: 138,\n      EPFNOSUPPORT: 139,\n      ECONNRESET: 15,\n      ENOBUFS: 42,\n      EAFNOSUPPORT: 5,\n      EPROTOTYPE: 67,\n      ENOTSOCK: 57,\n      ENOPROTOOPT: 50,\n      ESHUTDOWN: 140,\n      ECONNREFUSED: 14,\n      EADDRINUSE: 3,\n      ECONNABORTED: 13,\n      ENETUNREACH: 40,\n      ENETDOWN: 38,\n      ETIMEDOUT: 73,\n      EHOSTDOWN: 142,\n      EHOSTUNREACH: 23,\n      EINPROGRESS: 26,\n      EALREADY: 7,\n      EDESTADDRREQ: 17,\n      EMSGSIZE: 35,\n      EPROTONOSUPPORT: 66,\n      ESOCKTNOSUPPORT: 137,\n      EADDRNOTAVAIL: 4,\n      ENETRESET: 39,\n      EISCONN: 30,\n      ENOTCONN: 53,\n      ETOOMANYREFS: 141,\n      EUSERS: 136,\n      EDQUOT: 19,\n      ESTALE: 72,\n      ENOTSUP: 138,\n      ENOMEDIUM: 148,\n      EILSEQ: 25,\n      EOVERFLOW: 61,\n      ECANCELED: 11,\n      ENOTRECOVERABLE: 56,\n      EOWNERDEAD: 62,\n      ESTRPIPE: 135,\n    }\n    var asmLibraryArg = {\n      b: ___cxa_throw,\n      d: ___syscall_fcntl64,\n      r: ___syscall_getcwd,\n      i: ___syscall_ioctl,\n      j: ___syscall_openat,\n      n: ___syscall_readlinkat,\n      o: ___syscall_stat64,\n      c: _abort,\n      f: _emscripten_memcpy_big,\n      m: _emscripten_resize_heap,\n      p: _environ_get,\n      q: _environ_sizes_get,\n      a: _exit,\n      e: _fd_close,\n      h: _fd_read,\n      k: _fd_seek,\n      g: _fd_write,\n      l: _strftime_l,\n    }\n    var asm = createWasm()\n    var ___wasm_call_ctors = (Module['___wasm_call_ctors'] = function() {\n      return (___wasm_call_ctors = Module['___wasm_call_ctors'] =\n        Module['asm']['t']).apply(null, arguments)\n    })\n    var _main = (Module['_main'] = function() {\n      return (_main = Module['_main'] = Module['asm']['u']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___errno_location = (Module['___errno_location'] = function() {\n      return (___errno_location = Module['___errno_location'] =\n        Module['asm']['v']).apply(null, arguments)\n    })\n    var _itk_wasm_input_array_alloc = (Module[\n      '_itk_wasm_input_array_alloc'\n    ] = function() {\n      return (_itk_wasm_input_array_alloc = Module[\n        '_itk_wasm_input_array_alloc'\n      ] = Module['asm']['w']).apply(null, arguments)\n    })\n    var _itk_wasm_input_json_alloc = (Module[\n      '_itk_wasm_input_json_alloc'\n    ] = function() {\n      return (_itk_wasm_input_json_alloc = Module[\n        '_itk_wasm_input_json_alloc'\n      ] = Module['asm']['x']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_address = (Module[\n      '_itk_wasm_output_json_address'\n    ] = function() {\n      return (_itk_wasm_output_json_address = Module[\n        '_itk_wasm_output_json_address'\n      ] = Module['asm']['y']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_size = (Module[\n      '_itk_wasm_output_json_size'\n    ] = function() {\n      return (_itk_wasm_output_json_size = Module[\n        '_itk_wasm_output_json_size'\n      ] = Module['asm']['z']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_address = (Module[\n      '_itk_wasm_output_array_address'\n    ] = function() {\n      return (_itk_wasm_output_array_address = Module[\n        '_itk_wasm_output_array_address'\n      ] = Module['asm']['A']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_size = (Module[\n      '_itk_wasm_output_array_size'\n    ] = function() {\n      return (_itk_wasm_output_array_size = Module[\n        '_itk_wasm_output_array_size'\n      ] = Module['asm']['B']).apply(null, arguments)\n    })\n    var _itk_wasm_free_all = (Module['_itk_wasm_free_all'] = function() {\n      return (_itk_wasm_free_all = Module['_itk_wasm_free_all'] =\n        Module['asm']['C']).apply(null, arguments)\n    })\n    var stackSave = (Module['stackSave'] = function() {\n      return (stackSave = Module['stackSave'] = Module['asm']['E']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackRestore = (Module['stackRestore'] = function() {\n      return (stackRestore = Module['stackRestore'] = Module['asm']['F']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackAlloc = (Module['stackAlloc'] = function() {\n      return (stackAlloc = Module['stackAlloc'] = Module['asm']['G']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___cxa_is_pointer_type = (Module[\n      '___cxa_is_pointer_type'\n    ] = function() {\n      return (___cxa_is_pointer_type = Module['___cxa_is_pointer_type'] =\n        Module['asm']['H']).apply(null, arguments)\n    })\n    Module['addRunDependency'] = addRunDependency\n    Module['removeRunDependency'] = removeRunDependency\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    Module['FS_unlink'] = FS.unlink\n    Module['callMain'] = callMain\n    Module['ccall'] = ccall\n    Module['cwrap'] = cwrap\n    Module['AsciiToString'] = AsciiToString\n    Module['writeArrayToMemory'] = writeArrayToMemory\n    Module['writeAsciiToMemory'] = writeAsciiToMemory\n    var calledRun\n    dependenciesFulfilled = function runCaller() {\n      if (!calledRun) run()\n      if (!calledRun) dependenciesFulfilled = runCaller\n    }\n    function callMain(args) {\n      var entryFunction = Module['_main']\n      args = args || []\n      args.unshift(thisProgram)\n      var argc = args.length\n      var argv = stackAlloc((argc + 1) * 4)\n      var argv_ptr = argv >> 2\n      args.forEach(arg => {\n        HEAP32[argv_ptr++] = allocateUTF8OnStack(arg)\n      })\n      HEAP32[argv_ptr] = 0\n      try {\n        var ret = entryFunction(argc, argv)\n        exitJS(ret, true)\n        return ret\n      } catch (e) {\n        return handleException(e)\n      }\n    }\n    function run(args) {\n      args = args || arguments_\n      if (runDependencies > 0) {\n        return\n      }\n      preRun()\n      if (runDependencies > 0) {\n        return\n      }\n      function doRun() {\n        if (calledRun) return\n        calledRun = true\n        Module['calledRun'] = true\n        if (ABORT) return\n        initRuntime()\n        preMain()\n        readyPromiseResolve(Module)\n        if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']()\n        if (shouldRunNow) callMain(args)\n        postRun()\n      }\n      if (Module['setStatus']) {\n        Module['setStatus']('Running...')\n        setTimeout(function() {\n          setTimeout(function() {\n            Module['setStatus']('')\n          }, 1)\n          doRun()\n        }, 1)\n      } else {\n        doRun()\n      }\n    }\n    if (Module['preInit']) {\n      if (typeof Module['preInit'] == 'function')\n        Module['preInit'] = [Module['preInit']]\n      while (Module['preInit'].length > 0) {\n        Module['preInit'].pop()()\n      }\n    }\n    var shouldRunNow = false\n    if (Module['noInitialRun']) shouldRunNow = false\n    run()\n    Module.mountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      if (FS.isDir(containingDir) || containingDir === '/') {\n        return\n      }\n      var currentDir = '/'\n      var splitContainingDir = containingDir.split(path.sep)\n      for (var ii = 1; ii < splitContainingDir.length; ii++) {\n        currentDir += splitContainingDir[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n      FS.mount(NODEFS, { root: containingDir }, currentDir)\n      return currentDir + path.basename(filePath)\n    }\n    Module.unmountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      FS.unmount(containingDir)\n    }\n    Module.fs_mkdirs = function(dirs) {\n      var currentDir = '/'\n      var splitDirs = dirs.split('/')\n      for (var ii = 1; ii < splitDirs.length; ++ii) {\n        currentDir += splitDirs[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n    }\n    Module.fs_readFile = function(path, opts) {\n      return FS.readFile(path, opts)\n    }\n    Module.fs_writeFile = function(path, data, opts) {\n      return FS.writeFile(path, data, opts)\n    }\n    Module.fs_unlink = function(path) {\n      return FS.unlink(path)\n    }\n    Module.fs_open = function(path, flags, mode) {\n      return FS.open(path, flags, mode)\n    }\n    Module.fs_stat = function(path) {\n      return FS.stat(path)\n    }\n    Module.fs_read = function(stream, buffer, offset, length, position) {\n      return FS.read(stream, buffer, offset, length, position)\n    }\n    Module.fs_close = function(stream) {\n      return FS.close(stream)\n    }\n\n    return Compare.ready\n  }\n})()\nexport default Compare\n"
  },
  {
    "path": "src/IO/Compare/emscripten-build/Compare.umd.js",
    "content": "var Compare = (() => {\n  var _scriptDir =\n    typeof document !== 'undefined' && document.currentScript\n      ? document.currentScript.src\n      : undefined\n  if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename\n  return function(Compare) {\n    Compare = Compare || {}\n\n    var Module = typeof Compare != 'undefined' ? Compare : {}\n    var readyPromiseResolve, readyPromiseReject\n    Module['ready'] = new Promise(function(resolve, reject) {\n      readyPromiseResolve = resolve\n      readyPromiseReject = reject\n    })\n    var mStdout = null\n    var mStderr = null\n    Module['resetModuleStdout'] = function() {\n      mStdout = ''\n    }\n    Module['resetModuleStderr'] = function() {\n      mStderr = ''\n    }\n    Module['print'] = function(text) {\n      console.log(text)\n      mStdout += text + '\\n'\n    }\n    Module['printErr'] = function(text) {\n      console.error(text)\n      mStderr += text + '\\n'\n    }\n    Module['getModuleStdout'] = function() {\n      return mStdout\n    }\n    Module['getModuleStderr'] = function() {\n      return mStderr\n    }\n    var moduleOverrides = Object.assign({}, Module)\n    var arguments_ = []\n    var thisProgram = './this.program'\n    var quit_ = (status, toThrow) => {\n      throw toThrow\n    }\n    var ENVIRONMENT_IS_WEB = typeof window == 'object'\n    var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'\n    var ENVIRONMENT_IS_NODE =\n      typeof process == 'object' &&\n      typeof process.versions == 'object' &&\n      typeof process.versions.node == 'string'\n    var scriptDirectory = ''\n    function locateFile(path) {\n      if (Module['locateFile']) {\n        return Module['locateFile'](path, scriptDirectory)\n      }\n      return scriptDirectory + path\n    }\n    var read_, readAsync, readBinary, setWindowTitle\n    function logExceptionOnExit(e) {\n      if (e instanceof ExitStatus) return\n      let toLog = e\n      err('exiting due to exception: ' + toLog)\n    }\n    if (ENVIRONMENT_IS_NODE) {\n      var fs = require('fs')\n      var nodePath = require('path')\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = nodePath.dirname(scriptDirectory) + '/'\n      } else {\n        scriptDirectory = __dirname + '/'\n      }\n      read_ = (filename, binary) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        return fs.readFileSync(filename, binary ? undefined : 'utf8')\n      }\n      readBinary = filename => {\n        var ret = read_(filename, true)\n        if (!ret.buffer) {\n          ret = new Uint8Array(ret)\n        }\n        return ret\n      }\n      readAsync = (filename, onload, onerror) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        fs.readFile(filename, function(err, data) {\n          if (err) onerror(err)\n          else onload(data.buffer)\n        })\n      }\n      if (process['argv'].length > 1) {\n        thisProgram = process['argv'][1].replace(/\\\\/g, '/')\n      }\n      arguments_ = process['argv'].slice(2)\n      process['on']('uncaughtException', function(ex) {\n        if (!(ex instanceof ExitStatus)) {\n          throw ex\n        }\n      })\n      process['on']('unhandledRejection', function(reason) {\n        throw reason\n      })\n      quit_ = (status, toThrow) => {\n        if (keepRuntimeAlive()) {\n          process['exitCode'] = status\n          throw toThrow\n        }\n        logExceptionOnExit(toThrow)\n        process['exit'](status)\n      }\n      Module['inspect'] = function() {\n        return '[Emscripten Module object]'\n      }\n    } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = self.location.href\n      } else if (typeof document != 'undefined' && document.currentScript) {\n        scriptDirectory = document.currentScript.src\n      }\n      if (_scriptDir) {\n        scriptDirectory = _scriptDir\n      }\n      if (scriptDirectory.indexOf('blob:') !== 0) {\n        scriptDirectory = scriptDirectory.substr(\n          0,\n          scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1\n        )\n      } else {\n        scriptDirectory = ''\n      }\n      {\n        read_ = url => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, false)\n          xhr.send(null)\n          return xhr.responseText\n        }\n        if (ENVIRONMENT_IS_WORKER) {\n          readBinary = url => {\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            xhr.responseType = 'arraybuffer'\n            xhr.send(null)\n            return new Uint8Array(xhr.response)\n          }\n        }\n        readAsync = (url, onload, onerror) => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, true)\n          xhr.responseType = 'arraybuffer'\n          xhr.onload = () => {\n            if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n              onload(xhr.response)\n              return\n            }\n            onerror()\n          }\n          xhr.onerror = onerror\n          xhr.send(null)\n        }\n      }\n      setWindowTitle = title => (document.title = title)\n    } else {\n    }\n    var out = Module['print'] || console.log.bind(console)\n    var err = Module['printErr'] || console.warn.bind(console)\n    Object.assign(Module, moduleOverrides)\n    moduleOverrides = null\n    if (Module['arguments']) arguments_ = Module['arguments']\n    if (Module['thisProgram']) thisProgram = Module['thisProgram']\n    if (Module['quit']) quit_ = Module['quit']\n    var wasmBinary\n    if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']\n    var noExitRuntime = Module['noExitRuntime'] || true\n    if (typeof WebAssembly != 'object') {\n      abort('no native wasm support detected')\n    }\n    var wasmMemory\n    var ABORT = false\n    var EXITSTATUS\n    function assert(condition, text) {\n      if (!condition) {\n        abort(text)\n      }\n    }\n    var UTF8Decoder =\n      typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined\n    function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {\n      var endIdx = idx + maxBytesToRead\n      var endPtr = idx\n      while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr\n      if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {\n        return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr))\n      }\n      var str = ''\n      while (idx < endPtr) {\n        var u0 = heapOrArray[idx++]\n        if (!(u0 & 128)) {\n          str += String.fromCharCode(u0)\n          continue\n        }\n        var u1 = heapOrArray[idx++] & 63\n        if ((u0 & 224) == 192) {\n          str += String.fromCharCode(((u0 & 31) << 6) | u1)\n          continue\n        }\n        var u2 = heapOrArray[idx++] & 63\n        if ((u0 & 240) == 224) {\n          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2\n        } else {\n          u0 =\n            ((u0 & 7) << 18) |\n            (u1 << 12) |\n            (u2 << 6) |\n            (heapOrArray[idx++] & 63)\n        }\n        if (u0 < 65536) {\n          str += String.fromCharCode(u0)\n        } else {\n          var ch = u0 - 65536\n          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023))\n        }\n      }\n      return str\n    }\n    function UTF8ToString(ptr, maxBytesToRead) {\n      return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''\n    }\n    function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {\n      if (!(maxBytesToWrite > 0)) return 0\n      var startIdx = outIdx\n      var endIdx = outIdx + maxBytesToWrite - 1\n      for (var i = 0; i < str.length; ++i) {\n        var u = str.charCodeAt(i)\n        if (u >= 55296 && u <= 57343) {\n          var u1 = str.charCodeAt(++i)\n          u = (65536 + ((u & 1023) << 10)) | (u1 & 1023)\n        }\n        if (u <= 127) {\n          if (outIdx >= endIdx) break\n          heap[outIdx++] = u\n        } else if (u <= 2047) {\n          if (outIdx + 1 >= endIdx) break\n          heap[outIdx++] = 192 | (u >> 6)\n          heap[outIdx++] = 128 | (u & 63)\n        } else if (u <= 65535) {\n          if (outIdx + 2 >= endIdx) break\n          heap[outIdx++] = 224 | (u >> 12)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        } else {\n          if (outIdx + 3 >= endIdx) break\n          heap[outIdx++] = 240 | (u >> 18)\n          heap[outIdx++] = 128 | ((u >> 12) & 63)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        }\n      }\n      heap[outIdx] = 0\n      return outIdx - startIdx\n    }\n    function stringToUTF8(str, outPtr, maxBytesToWrite) {\n      return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite)\n    }\n    function lengthBytesUTF8(str) {\n      var len = 0\n      for (var i = 0; i < str.length; ++i) {\n        var c = str.charCodeAt(i)\n        if (c <= 127) {\n          len++\n        } else if (c <= 2047) {\n          len += 2\n        } else if (c >= 55296 && c <= 57343) {\n          len += 4\n          ++i\n        } else {\n          len += 3\n        }\n      }\n      return len\n    }\n    var buffer,\n      HEAP8,\n      HEAPU8,\n      HEAP16,\n      HEAPU16,\n      HEAP32,\n      HEAPU32,\n      HEAPF32,\n      HEAPF64\n    function updateGlobalBufferAndViews(buf) {\n      buffer = buf\n      Module['HEAP8'] = HEAP8 = new Int8Array(buf)\n      Module['HEAP16'] = HEAP16 = new Int16Array(buf)\n      Module['HEAP32'] = HEAP32 = new Int32Array(buf)\n      Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf)\n      Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf)\n      Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf)\n      Module['HEAPF32'] = HEAPF32 = new Float32Array(buf)\n      Module['HEAPF64'] = HEAPF64 = new Float64Array(buf)\n    }\n    var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216\n    var wasmTable\n    var __ATPRERUN__ = []\n    var __ATINIT__ = []\n    var __ATMAIN__ = []\n    var __ATPOSTRUN__ = []\n    var runtimeInitialized = false\n    function keepRuntimeAlive() {\n      return noExitRuntime\n    }\n    function preRun() {\n      if (Module['preRun']) {\n        if (typeof Module['preRun'] == 'function')\n          Module['preRun'] = [Module['preRun']]\n        while (Module['preRun'].length) {\n          addOnPreRun(Module['preRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPRERUN__)\n    }\n    function initRuntime() {\n      runtimeInitialized = true\n      if (!Module['noFSInit'] && !FS.init.initialized) FS.init()\n      FS.ignorePermissions = false\n      TTY.init()\n      callRuntimeCallbacks(__ATINIT__)\n    }\n    function preMain() {\n      callRuntimeCallbacks(__ATMAIN__)\n    }\n    function postRun() {\n      if (Module['postRun']) {\n        if (typeof Module['postRun'] == 'function')\n          Module['postRun'] = [Module['postRun']]\n        while (Module['postRun'].length) {\n          addOnPostRun(Module['postRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPOSTRUN__)\n    }\n    function addOnPreRun(cb) {\n      __ATPRERUN__.unshift(cb)\n    }\n    function addOnInit(cb) {\n      __ATINIT__.unshift(cb)\n    }\n    function addOnPostRun(cb) {\n      __ATPOSTRUN__.unshift(cb)\n    }\n    var runDependencies = 0\n    var runDependencyWatcher = null\n    var dependenciesFulfilled = null\n    function getUniqueRunDependency(id) {\n      return id\n    }\n    function addRunDependency(id) {\n      runDependencies++\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n    }\n    function removeRunDependency(id) {\n      runDependencies--\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n      if (runDependencies == 0) {\n        if (runDependencyWatcher !== null) {\n          clearInterval(runDependencyWatcher)\n          runDependencyWatcher = null\n        }\n        if (dependenciesFulfilled) {\n          var callback = dependenciesFulfilled\n          dependenciesFulfilled = null\n          callback()\n        }\n      }\n    }\n    function abort(what) {\n      if (Module['onAbort']) {\n        Module['onAbort'](what)\n      }\n      what = 'Aborted(' + what + ')'\n      err(what)\n      ABORT = true\n      EXITSTATUS = 1\n      what += '. Build with -sASSERTIONS for more info.'\n      var e = new WebAssembly.RuntimeError(what)\n      readyPromiseReject(e)\n      throw e\n    }\n    var dataURIPrefix = 'data:application/octet-stream;base64,'\n    function isDataURI(filename) {\n      return filename.startsWith(dataURIPrefix)\n    }\n    function isFileURI(filename) {\n      return filename.startsWith('file://')\n    }\n    var wasmBinaryFile\n    wasmBinaryFile = 'Compare.umd.wasm'\n    if (!isDataURI(wasmBinaryFile)) {\n      wasmBinaryFile = locateFile(wasmBinaryFile)\n    }\n    function getBinary(file) {\n      try {\n        if (file == wasmBinaryFile && wasmBinary) {\n          return new Uint8Array(wasmBinary)\n        }\n        if (readBinary) {\n          return readBinary(file)\n        }\n        throw 'both async and sync fetching of the wasm failed'\n      } catch (err) {\n        abort(err)\n      }\n    }\n    function getBinaryPromise() {\n      if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {\n        if (typeof fetch == 'function' && !isFileURI(wasmBinaryFile)) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' })\n            .then(function(response) {\n              if (!response['ok']) {\n                throw \"failed to load wasm binary file at '\" +\n                  wasmBinaryFile +\n                  \"'\"\n              }\n              return response['arrayBuffer']()\n            })\n            .catch(function() {\n              return getBinary(wasmBinaryFile)\n            })\n        } else {\n          if (readAsync) {\n            return new Promise(function(resolve, reject) {\n              readAsync(\n                wasmBinaryFile,\n                function(response) {\n                  resolve(new Uint8Array(response))\n                },\n                reject\n              )\n            })\n          }\n        }\n      }\n      return Promise.resolve().then(function() {\n        return getBinary(wasmBinaryFile)\n      })\n    }\n    function createWasm() {\n      var info = { a: asmLibraryArg }\n      function receiveInstance(instance, module) {\n        var exports = instance.exports\n        Module['asm'] = exports\n        wasmMemory = Module['asm']['s']\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        wasmTable = Module['asm']['D']\n        addOnInit(Module['asm']['t'])\n        removeRunDependency('wasm-instantiate')\n      }\n      addRunDependency('wasm-instantiate')\n      function receiveInstantiationResult(result) {\n        receiveInstance(result['instance'])\n      }\n      function instantiateArrayBuffer(receiver) {\n        return getBinaryPromise()\n          .then(function(binary) {\n            return WebAssembly.instantiate(binary, info)\n          })\n          .then(function(instance) {\n            return instance\n          })\n          .then(receiver, function(reason) {\n            err('failed to asynchronously prepare wasm: ' + reason)\n            abort(reason)\n          })\n      }\n      function instantiateAsync() {\n        if (\n          !wasmBinary &&\n          typeof WebAssembly.instantiateStreaming == 'function' &&\n          !isDataURI(wasmBinaryFile) &&\n          !isFileURI(wasmBinaryFile) &&\n          !ENVIRONMENT_IS_NODE &&\n          typeof fetch == 'function'\n        ) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(\n            function(response) {\n              var result = WebAssembly.instantiateStreaming(response, info)\n              return result.then(receiveInstantiationResult, function(reason) {\n                err('wasm streaming compile failed: ' + reason)\n                err('falling back to ArrayBuffer instantiation')\n                return instantiateArrayBuffer(receiveInstantiationResult)\n              })\n            }\n          )\n        } else {\n          return instantiateArrayBuffer(receiveInstantiationResult)\n        }\n      }\n      if (Module['instantiateWasm']) {\n        try {\n          var exports = Module['instantiateWasm'](info, receiveInstance)\n          return exports\n        } catch (e) {\n          err('Module.instantiateWasm callback failed with error: ' + e)\n          readyPromiseReject(e)\n        }\n      }\n      instantiateAsync().catch(readyPromiseReject)\n      return {}\n    }\n    var tempDouble\n    var tempI64\n    function ExitStatus(status) {\n      this.name = 'ExitStatus'\n      this.message = 'Program terminated with exit(' + status + ')'\n      this.status = status\n    }\n    function callRuntimeCallbacks(callbacks) {\n      while (callbacks.length > 0) {\n        callbacks.shift()(Module)\n      }\n    }\n    function ExceptionInfo(excPtr) {\n      this.excPtr = excPtr\n      this.ptr = excPtr - 24\n      this.set_type = function(type) {\n        HEAPU32[(this.ptr + 4) >> 2] = type\n      }\n      this.get_type = function() {\n        return HEAPU32[(this.ptr + 4) >> 2]\n      }\n      this.set_destructor = function(destructor) {\n        HEAPU32[(this.ptr + 8) >> 2] = destructor\n      }\n      this.get_destructor = function() {\n        return HEAPU32[(this.ptr + 8) >> 2]\n      }\n      this.set_refcount = function(refcount) {\n        HEAP32[this.ptr >> 2] = refcount\n      }\n      this.set_caught = function(caught) {\n        caught = caught ? 1 : 0\n        HEAP8[(this.ptr + 12) >> 0] = caught\n      }\n      this.get_caught = function() {\n        return HEAP8[(this.ptr + 12) >> 0] != 0\n      }\n      this.set_rethrown = function(rethrown) {\n        rethrown = rethrown ? 1 : 0\n        HEAP8[(this.ptr + 13) >> 0] = rethrown\n      }\n      this.get_rethrown = function() {\n        return HEAP8[(this.ptr + 13) >> 0] != 0\n      }\n      this.init = function(type, destructor) {\n        this.set_adjusted_ptr(0)\n        this.set_type(type)\n        this.set_destructor(destructor)\n        this.set_refcount(0)\n        this.set_caught(false)\n        this.set_rethrown(false)\n      }\n      this.add_ref = function() {\n        var value = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = value + 1\n      }\n      this.release_ref = function() {\n        var prev = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = prev - 1\n        return prev === 1\n      }\n      this.set_adjusted_ptr = function(adjustedPtr) {\n        HEAPU32[(this.ptr + 16) >> 2] = adjustedPtr\n      }\n      this.get_adjusted_ptr = function() {\n        return HEAPU32[(this.ptr + 16) >> 2]\n      }\n      this.get_exception_ptr = function() {\n        var isPointer = ___cxa_is_pointer_type(this.get_type())\n        if (isPointer) {\n          return HEAPU32[this.excPtr >> 2]\n        }\n        var adjusted = this.get_adjusted_ptr()\n        if (adjusted !== 0) return adjusted\n        return this.excPtr\n      }\n    }\n    var exceptionLast = 0\n    var uncaughtExceptionCount = 0\n    function ___cxa_throw(ptr, type, destructor) {\n      var info = new ExceptionInfo(ptr)\n      info.init(type, destructor)\n      exceptionLast = ptr\n      uncaughtExceptionCount++\n      throw ptr\n    }\n    function setErrNo(value) {\n      HEAP32[___errno_location() >> 2] = value\n      return value\n    }\n    var PATH = {\n      isAbs: path => path.charAt(0) === '/',\n      splitPath: filename => {\n        var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/\n        return splitPathRe.exec(filename).slice(1)\n      },\n      normalizeArray: (parts, allowAboveRoot) => {\n        var up = 0\n        for (var i = parts.length - 1; i >= 0; i--) {\n          var last = parts[i]\n          if (last === '.') {\n            parts.splice(i, 1)\n          } else if (last === '..') {\n            parts.splice(i, 1)\n            up++\n          } else if (up) {\n            parts.splice(i, 1)\n            up--\n          }\n        }\n        if (allowAboveRoot) {\n          for (; up; up--) {\n            parts.unshift('..')\n          }\n        }\n        return parts\n      },\n      normalize: path => {\n        var isAbsolute = PATH.isAbs(path),\n          trailingSlash = path.substr(-1) === '/'\n        path = PATH.normalizeArray(\n          path.split('/').filter(p => !!p),\n          !isAbsolute\n        ).join('/')\n        if (!path && !isAbsolute) {\n          path = '.'\n        }\n        if (path && trailingSlash) {\n          path += '/'\n        }\n        return (isAbsolute ? '/' : '') + path\n      },\n      dirname: path => {\n        var result = PATH.splitPath(path),\n          root = result[0],\n          dir = result[1]\n        if (!root && !dir) {\n          return '.'\n        }\n        if (dir) {\n          dir = dir.substr(0, dir.length - 1)\n        }\n        return root + dir\n      },\n      basename: path => {\n        if (path === '/') return '/'\n        path = PATH.normalize(path)\n        path = path.replace(/\\/$/, '')\n        var lastSlash = path.lastIndexOf('/')\n        if (lastSlash === -1) return path\n        return path.substr(lastSlash + 1)\n      },\n      join: function() {\n        var paths = Array.prototype.slice.call(arguments)\n        return PATH.normalize(paths.join('/'))\n      },\n      join2: (l, r) => {\n        return PATH.normalize(l + '/' + r)\n      },\n    }\n    function getRandomDevice() {\n      if (\n        typeof crypto == 'object' &&\n        typeof crypto['getRandomValues'] == 'function'\n      ) {\n        var randomBuffer = new Uint8Array(1)\n        return () => {\n          crypto.getRandomValues(randomBuffer)\n          return randomBuffer[0]\n        }\n      } else if (ENVIRONMENT_IS_NODE) {\n        try {\n          var crypto_module = require('crypto')\n          return () => crypto_module['randomBytes'](1)[0]\n        } catch (e) {}\n      }\n      return () => abort('randomDevice')\n    }\n    var PATH_FS = {\n      resolve: function() {\n        var resolvedPath = '',\n          resolvedAbsolute = false\n        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n          var path = i >= 0 ? arguments[i] : FS.cwd()\n          if (typeof path != 'string') {\n            throw new TypeError('Arguments to path.resolve must be strings')\n          } else if (!path) {\n            return ''\n          }\n          resolvedPath = path + '/' + resolvedPath\n          resolvedAbsolute = PATH.isAbs(path)\n        }\n        resolvedPath = PATH.normalizeArray(\n          resolvedPath.split('/').filter(p => !!p),\n          !resolvedAbsolute\n        ).join('/')\n        return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'\n      },\n      relative: (from, to) => {\n        from = PATH_FS.resolve(from).substr(1)\n        to = PATH_FS.resolve(to).substr(1)\n        function trim(arr) {\n          var start = 0\n          for (; start < arr.length; start++) {\n            if (arr[start] !== '') break\n          }\n          var end = arr.length - 1\n          for (; end >= 0; end--) {\n            if (arr[end] !== '') break\n          }\n          if (start > end) return []\n          return arr.slice(start, end - start + 1)\n        }\n        var fromParts = trim(from.split('/'))\n        var toParts = trim(to.split('/'))\n        var length = Math.min(fromParts.length, toParts.length)\n        var samePartsLength = length\n        for (var i = 0; i < length; i++) {\n          if (fromParts[i] !== toParts[i]) {\n            samePartsLength = i\n            break\n          }\n        }\n        var outputParts = []\n        for (var i = samePartsLength; i < fromParts.length; i++) {\n          outputParts.push('..')\n        }\n        outputParts = outputParts.concat(toParts.slice(samePartsLength))\n        return outputParts.join('/')\n      },\n    }\n    function intArrayFromString(stringy, dontAddNull, length) {\n      var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1\n      var u8array = new Array(len)\n      var numBytesWritten = stringToUTF8Array(\n        stringy,\n        u8array,\n        0,\n        u8array.length\n      )\n      if (dontAddNull) u8array.length = numBytesWritten\n      return u8array\n    }\n    var TTY = {\n      ttys: [],\n      init: function() {},\n      shutdown: function() {},\n      register: function(dev, ops) {\n        TTY.ttys[dev] = { input: [], output: [], ops: ops }\n        FS.registerDevice(dev, TTY.stream_ops)\n      },\n      stream_ops: {\n        open: function(stream) {\n          var tty = TTY.ttys[stream.node.rdev]\n          if (!tty) {\n            throw new FS.ErrnoError(43)\n          }\n          stream.tty = tty\n          stream.seekable = false\n        },\n        close: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        fsync: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        read: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.get_char) {\n            throw new FS.ErrnoError(60)\n          }\n          var bytesRead = 0\n          for (var i = 0; i < length; i++) {\n            var result\n            try {\n              result = stream.tty.ops.get_char(stream.tty)\n            } catch (e) {\n              throw new FS.ErrnoError(29)\n            }\n            if (result === undefined && bytesRead === 0) {\n              throw new FS.ErrnoError(6)\n            }\n            if (result === null || result === undefined) break\n            bytesRead++\n            buffer[offset + i] = result\n          }\n          if (bytesRead) {\n            stream.node.timestamp = Date.now()\n          }\n          return bytesRead\n        },\n        write: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.put_char) {\n            throw new FS.ErrnoError(60)\n          }\n          try {\n            for (var i = 0; i < length; i++) {\n              stream.tty.ops.put_char(stream.tty, buffer[offset + i])\n            }\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n          if (length) {\n            stream.node.timestamp = Date.now()\n          }\n          return i\n        },\n      },\n      default_tty_ops: {\n        get_char: function(tty) {\n          if (!tty.input.length) {\n            var result = null\n            if (ENVIRONMENT_IS_NODE) {\n              var BUFSIZE = 256\n              var buf = Buffer.alloc(BUFSIZE)\n              var bytesRead = 0\n              try {\n                bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, -1)\n              } catch (e) {\n                if (e.toString().includes('EOF')) bytesRead = 0\n                else throw e\n              }\n              if (bytesRead > 0) {\n                result = buf.slice(0, bytesRead).toString('utf-8')\n              } else {\n                result = null\n              }\n            } else if (\n              typeof window != 'undefined' &&\n              typeof window.prompt == 'function'\n            ) {\n              result = window.prompt('Input: ')\n              if (result !== null) {\n                result += '\\n'\n              }\n            } else if (typeof readline == 'function') {\n              result = readline()\n              if (result !== null) {\n                result += '\\n'\n              }\n            }\n            if (!result) {\n              return null\n            }\n            tty.input = intArrayFromString(result, true)\n          }\n          return tty.input.shift()\n        },\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n      default_tty1_ops: {\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n    }\n    function mmapAlloc(size) {\n      abort()\n    }\n    var MEMFS = {\n      ops_table: null,\n      mount: function(mount) {\n        return MEMFS.createNode(null, '/', 16384 | 511, 0)\n      },\n      createNode: function(parent, name, mode, dev) {\n        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n          throw new FS.ErrnoError(63)\n        }\n        if (!MEMFS.ops_table) {\n          MEMFS.ops_table = {\n            dir: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                lookup: MEMFS.node_ops.lookup,\n                mknod: MEMFS.node_ops.mknod,\n                rename: MEMFS.node_ops.rename,\n                unlink: MEMFS.node_ops.unlink,\n                rmdir: MEMFS.node_ops.rmdir,\n                readdir: MEMFS.node_ops.readdir,\n                symlink: MEMFS.node_ops.symlink,\n              },\n              stream: { llseek: MEMFS.stream_ops.llseek },\n            },\n            file: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: {\n                llseek: MEMFS.stream_ops.llseek,\n                read: MEMFS.stream_ops.read,\n                write: MEMFS.stream_ops.write,\n                allocate: MEMFS.stream_ops.allocate,\n                mmap: MEMFS.stream_ops.mmap,\n                msync: MEMFS.stream_ops.msync,\n              },\n            },\n            link: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                readlink: MEMFS.node_ops.readlink,\n              },\n              stream: {},\n            },\n            chrdev: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: FS.chrdev_stream_ops,\n            },\n          }\n        }\n        var node = FS.createNode(parent, name, mode, dev)\n        if (FS.isDir(node.mode)) {\n          node.node_ops = MEMFS.ops_table.dir.node\n          node.stream_ops = MEMFS.ops_table.dir.stream\n          node.contents = {}\n        } else if (FS.isFile(node.mode)) {\n          node.node_ops = MEMFS.ops_table.file.node\n          node.stream_ops = MEMFS.ops_table.file.stream\n          node.usedBytes = 0\n          node.contents = null\n        } else if (FS.isLink(node.mode)) {\n          node.node_ops = MEMFS.ops_table.link.node\n          node.stream_ops = MEMFS.ops_table.link.stream\n        } else if (FS.isChrdev(node.mode)) {\n          node.node_ops = MEMFS.ops_table.chrdev.node\n          node.stream_ops = MEMFS.ops_table.chrdev.stream\n        }\n        node.timestamp = Date.now()\n        if (parent) {\n          parent.contents[name] = node\n          parent.timestamp = node.timestamp\n        }\n        return node\n      },\n      getFileDataAsTypedArray: function(node) {\n        if (!node.contents) return new Uint8Array(0)\n        if (node.contents.subarray)\n          return node.contents.subarray(0, node.usedBytes)\n        return new Uint8Array(node.contents)\n      },\n      expandFileStorage: function(node, newCapacity) {\n        var prevCapacity = node.contents ? node.contents.length : 0\n        if (prevCapacity >= newCapacity) return\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024\n        newCapacity = Math.max(\n          newCapacity,\n          (prevCapacity *\n            (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>>\n            0\n        )\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256)\n        var oldContents = node.contents\n        node.contents = new Uint8Array(newCapacity)\n        if (node.usedBytes > 0)\n          node.contents.set(oldContents.subarray(0, node.usedBytes), 0)\n      },\n      resizeFileStorage: function(node, newSize) {\n        if (node.usedBytes == newSize) return\n        if (newSize == 0) {\n          node.contents = null\n          node.usedBytes = 0\n        } else {\n          var oldContents = node.contents\n          node.contents = new Uint8Array(newSize)\n          if (oldContents) {\n            node.contents.set(\n              oldContents.subarray(0, Math.min(newSize, node.usedBytes))\n            )\n          }\n          node.usedBytes = newSize\n        }\n      },\n      node_ops: {\n        getattr: function(node) {\n          var attr = {}\n          attr.dev = FS.isChrdev(node.mode) ? node.id : 1\n          attr.ino = node.id\n          attr.mode = node.mode\n          attr.nlink = 1\n          attr.uid = 0\n          attr.gid = 0\n          attr.rdev = node.rdev\n          if (FS.isDir(node.mode)) {\n            attr.size = 4096\n          } else if (FS.isFile(node.mode)) {\n            attr.size = node.usedBytes\n          } else if (FS.isLink(node.mode)) {\n            attr.size = node.link.length\n          } else {\n            attr.size = 0\n          }\n          attr.atime = new Date(node.timestamp)\n          attr.mtime = new Date(node.timestamp)\n          attr.ctime = new Date(node.timestamp)\n          attr.blksize = 4096\n          attr.blocks = Math.ceil(attr.size / attr.blksize)\n          return attr\n        },\n        setattr: function(node, attr) {\n          if (attr.mode !== undefined) {\n            node.mode = attr.mode\n          }\n          if (attr.timestamp !== undefined) {\n            node.timestamp = attr.timestamp\n          }\n          if (attr.size !== undefined) {\n            MEMFS.resizeFileStorage(node, attr.size)\n          }\n        },\n        lookup: function(parent, name) {\n          throw FS.genericErrors[44]\n        },\n        mknod: function(parent, name, mode, dev) {\n          return MEMFS.createNode(parent, name, mode, dev)\n        },\n        rename: function(old_node, new_dir, new_name) {\n          if (FS.isDir(old_node.mode)) {\n            var new_node\n            try {\n              new_node = FS.lookupNode(new_dir, new_name)\n            } catch (e) {}\n            if (new_node) {\n              for (var i in new_node.contents) {\n                throw new FS.ErrnoError(55)\n              }\n            }\n          }\n          delete old_node.parent.contents[old_node.name]\n          old_node.parent.timestamp = Date.now()\n          old_node.name = new_name\n          new_dir.contents[new_name] = old_node\n          new_dir.timestamp = old_node.parent.timestamp\n          old_node.parent = new_dir\n        },\n        unlink: function(parent, name) {\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        rmdir: function(parent, name) {\n          var node = FS.lookupNode(parent, name)\n          for (var i in node.contents) {\n            throw new FS.ErrnoError(55)\n          }\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        readdir: function(node) {\n          var entries = ['.', '..']\n          for (var key in node.contents) {\n            if (!node.contents.hasOwnProperty(key)) {\n              continue\n            }\n            entries.push(key)\n          }\n          return entries\n        },\n        symlink: function(parent, newname, oldpath) {\n          var node = MEMFS.createNode(parent, newname, 511 | 40960, 0)\n          node.link = oldpath\n          return node\n        },\n        readlink: function(node) {\n          if (!FS.isLink(node.mode)) {\n            throw new FS.ErrnoError(28)\n          }\n          return node.link\n        },\n      },\n      stream_ops: {\n        read: function(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= stream.node.usedBytes) return 0\n          var size = Math.min(stream.node.usedBytes - position, length)\n          if (size > 8 && contents.subarray) {\n            buffer.set(contents.subarray(position, position + size), offset)\n          } else {\n            for (var i = 0; i < size; i++)\n              buffer[offset + i] = contents[position + i]\n          }\n          return size\n        },\n        write: function(stream, buffer, offset, length, position, canOwn) {\n          if (buffer.buffer === HEAP8.buffer) {\n            canOwn = false\n          }\n          if (!length) return 0\n          var node = stream.node\n          node.timestamp = Date.now()\n          if (buffer.subarray && (!node.contents || node.contents.subarray)) {\n            if (canOwn) {\n              node.contents = buffer.subarray(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (node.usedBytes === 0 && position === 0) {\n              node.contents = buffer.slice(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (position + length <= node.usedBytes) {\n              node.contents.set(\n                buffer.subarray(offset, offset + length),\n                position\n              )\n              return length\n            }\n          }\n          MEMFS.expandFileStorage(node, position + length)\n          if (node.contents.subarray && buffer.subarray) {\n            node.contents.set(\n              buffer.subarray(offset, offset + length),\n              position\n            )\n          } else {\n            for (var i = 0; i < length; i++) {\n              node.contents[position + i] = buffer[offset + i]\n            }\n          }\n          node.usedBytes = Math.max(node.usedBytes, position + length)\n          return length\n        },\n        llseek: function(stream, offset, whence) {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              position += stream.node.usedBytes\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        allocate: function(stream, offset, length) {\n          MEMFS.expandFileStorage(stream.node, offset + length)\n          stream.node.usedBytes = Math.max(\n            stream.node.usedBytes,\n            offset + length\n          )\n        },\n        mmap: function(stream, length, position, prot, flags) {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr\n          var allocated\n          var contents = stream.node.contents\n          if (!(flags & 2) && contents.buffer === buffer) {\n            allocated = false\n            ptr = contents.byteOffset\n          } else {\n            if (position > 0 || position + length < contents.length) {\n              if (contents.subarray) {\n                contents = contents.subarray(position, position + length)\n              } else {\n                contents = Array.prototype.slice.call(\n                  contents,\n                  position,\n                  position + length\n                )\n              }\n            }\n            allocated = true\n            ptr = mmapAlloc(length)\n            if (!ptr) {\n              throw new FS.ErrnoError(48)\n            }\n            HEAP8.set(contents, ptr)\n          }\n          return { ptr: ptr, allocated: allocated }\n        },\n        msync: function(stream, buffer, offset, length, mmapFlags) {\n          MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    function asyncLoad(url, onload, onerror, noRunDep) {\n      var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''\n      readAsync(\n        url,\n        arrayBuffer => {\n          assert(\n            arrayBuffer,\n            'Loading data file \"' + url + '\" failed (no arrayBuffer).'\n          )\n          onload(new Uint8Array(arrayBuffer))\n          if (dep) removeRunDependency(dep)\n        },\n        event => {\n          if (onerror) {\n            onerror()\n          } else {\n            throw 'Loading data file \"' + url + '\" failed.'\n          }\n        }\n      )\n      if (dep) addRunDependency(dep)\n    }\n    var ERRNO_CODES = {}\n    var NODEFS = {\n      isWindows: false,\n      staticInit: () => {\n        NODEFS.isWindows = !!process.platform.match(/^win/)\n        var flags = process['binding']('constants')\n        if (flags['fs']) {\n          flags = flags['fs']\n        }\n        NODEFS.flagsForNodeMap = {\n          1024: flags['O_APPEND'],\n          64: flags['O_CREAT'],\n          128: flags['O_EXCL'],\n          256: flags['O_NOCTTY'],\n          0: flags['O_RDONLY'],\n          2: flags['O_RDWR'],\n          4096: flags['O_SYNC'],\n          512: flags['O_TRUNC'],\n          1: flags['O_WRONLY'],\n          131072: flags['O_NOFOLLOW'],\n        }\n      },\n      convertNodeCode: e => {\n        var code = e.code\n        return ERRNO_CODES[code]\n      },\n      mount: mount => {\n        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0)\n      },\n      createNode: (parent, name, mode, dev) => {\n        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = FS.createNode(parent, name, mode)\n        node.node_ops = NODEFS.node_ops\n        node.stream_ops = NODEFS.stream_ops\n        return node\n      },\n      getMode: path => {\n        var stat\n        try {\n          stat = fs.lstatSync(path)\n          if (NODEFS.isWindows) {\n            stat.mode = stat.mode | ((stat.mode & 292) >> 2)\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n        }\n        return stat.mode\n      },\n      realPath: node => {\n        var parts = []\n        while (node.parent !== node) {\n          parts.push(node.name)\n          node = node.parent\n        }\n        parts.push(node.mount.opts.root)\n        parts.reverse()\n        return PATH.join.apply(null, parts)\n      },\n      flagsForNode: flags => {\n        flags &= ~2097152\n        flags &= ~2048\n        flags &= ~32768\n        flags &= ~524288\n        flags &= ~65536\n        var newFlags = 0\n        for (var k in NODEFS.flagsForNodeMap) {\n          if (flags & k) {\n            newFlags |= NODEFS.flagsForNodeMap[k]\n            flags ^= k\n          }\n        }\n        if (flags) {\n          throw new FS.ErrnoError(28)\n        }\n        return newFlags\n      },\n      node_ops: {\n        getattr: node => {\n          var path = NODEFS.realPath(node)\n          var stat\n          try {\n            stat = fs.lstatSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          if (NODEFS.isWindows && !stat.blksize) {\n            stat.blksize = 4096\n          }\n          if (NODEFS.isWindows && !stat.blocks) {\n            stat.blocks = ((stat.size + stat.blksize - 1) / stat.blksize) | 0\n          }\n          return {\n            dev: stat.dev,\n            ino: stat.ino,\n            mode: stat.mode,\n            nlink: stat.nlink,\n            uid: stat.uid,\n            gid: stat.gid,\n            rdev: stat.rdev,\n            size: stat.size,\n            atime: stat.atime,\n            mtime: stat.mtime,\n            ctime: stat.ctime,\n            blksize: stat.blksize,\n            blocks: stat.blocks,\n          }\n        },\n        setattr: (node, attr) => {\n          var path = NODEFS.realPath(node)\n          try {\n            if (attr.mode !== undefined) {\n              fs.chmodSync(path, attr.mode)\n              node.mode = attr.mode\n            }\n            if (attr.timestamp !== undefined) {\n              var date = new Date(attr.timestamp)\n              fs.utimesSync(path, date, date)\n            }\n            if (attr.size !== undefined) {\n              fs.truncateSync(path, attr.size)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        lookup: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          var mode = NODEFS.getMode(path)\n          return NODEFS.createNode(parent, name, mode)\n        },\n        mknod: (parent, name, mode, dev) => {\n          var node = NODEFS.createNode(parent, name, mode, dev)\n          var path = NODEFS.realPath(node)\n          try {\n            if (FS.isDir(node.mode)) {\n              fs.mkdirSync(path, node.mode)\n            } else {\n              fs.writeFileSync(path, '', { mode: node.mode })\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          return node\n        },\n        rename: (oldNode, newDir, newName) => {\n          var oldPath = NODEFS.realPath(oldNode)\n          var newPath = PATH.join2(NODEFS.realPath(newDir), newName)\n          try {\n            fs.renameSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          oldNode.name = newName\n        },\n        unlink: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.unlinkSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        rmdir: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.rmdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readdir: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            return fs.readdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        symlink: (parent, newName, oldPath) => {\n          var newPath = PATH.join2(NODEFS.realPath(parent), newName)\n          try {\n            fs.symlinkSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readlink: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            path = fs.readlinkSync(path)\n            path = nodePath.relative(\n              nodePath.resolve(node.mount.opts.root),\n              path\n            )\n            return path\n          } catch (e) {\n            if (!e.code) throw e\n            if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28)\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n      },\n      stream_ops: {\n        open: stream => {\n          var path = NODEFS.realPath(stream.node)\n          try {\n            if (FS.isFile(stream.node.mode)) {\n              stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags))\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        close: stream => {\n          try {\n            if (FS.isFile(stream.node.mode) && stream.nfd) {\n              fs.closeSync(stream.nfd)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        read: (stream, buffer, offset, length, position) => {\n          if (length === 0) return 0\n          try {\n            return fs.readSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        write: (stream, buffer, offset, length, position) => {\n          try {\n            return fs.writeSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        llseek: (stream, offset, whence) => {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              try {\n                var stat = fs.fstatSync(stream.nfd)\n                position += stat.size\n              } catch (e) {\n                throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n              }\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        mmap: (stream, length, position, prot, flags) => {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr = mmapAlloc(length)\n          NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        },\n        msync: (stream, buffer, offset, length, mmapFlags) => {\n          NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    var FS = {\n      root: null,\n      mounts: [],\n      devices: {},\n      streams: [],\n      nextInode: 1,\n      nameTable: null,\n      currentPath: '/',\n      initialized: false,\n      ignorePermissions: true,\n      ErrnoError: null,\n      genericErrors: {},\n      filesystems: null,\n      syncFSRequests: 0,\n      lookupPath: (path, opts = {}) => {\n        path = PATH_FS.resolve(path)\n        if (!path) return { path: '', node: null }\n        var defaults = { follow_mount: true, recurse_count: 0 }\n        opts = Object.assign(defaults, opts)\n        if (opts.recurse_count > 8) {\n          throw new FS.ErrnoError(32)\n        }\n        var parts = path.split('/').filter(p => !!p)\n        var current = FS.root\n        var current_path = '/'\n        for (var i = 0; i < parts.length; i++) {\n          var islast = i === parts.length - 1\n          if (islast && opts.parent) {\n            break\n          }\n          current = FS.lookupNode(current, parts[i])\n          current_path = PATH.join2(current_path, parts[i])\n          if (FS.isMountpoint(current)) {\n            if (!islast || (islast && opts.follow_mount)) {\n              current = current.mounted.root\n            }\n          }\n          if (!islast || opts.follow) {\n            var count = 0\n            while (FS.isLink(current.mode)) {\n              var link = FS.readlink(current_path)\n              current_path = PATH_FS.resolve(PATH.dirname(current_path), link)\n              var lookup = FS.lookupPath(current_path, {\n                recurse_count: opts.recurse_count + 1,\n              })\n              current = lookup.node\n              if (count++ > 40) {\n                throw new FS.ErrnoError(32)\n              }\n            }\n          }\n        }\n        return { path: current_path, node: current }\n      },\n      getPath: node => {\n        var path\n        while (true) {\n          if (FS.isRoot(node)) {\n            var mount = node.mount.mountpoint\n            if (!path) return mount\n            return mount[mount.length - 1] !== '/'\n              ? mount + '/' + path\n              : mount + path\n          }\n          path = path ? node.name + '/' + path : node.name\n          node = node.parent\n        }\n      },\n      hashName: (parentid, name) => {\n        var hash = 0\n        for (var i = 0; i < name.length; i++) {\n          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0\n        }\n        return ((parentid + hash) >>> 0) % FS.nameTable.length\n      },\n      hashAddNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        node.name_next = FS.nameTable[hash]\n        FS.nameTable[hash] = node\n      },\n      hashRemoveNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        if (FS.nameTable[hash] === node) {\n          FS.nameTable[hash] = node.name_next\n        } else {\n          var current = FS.nameTable[hash]\n          while (current) {\n            if (current.name_next === node) {\n              current.name_next = node.name_next\n              break\n            }\n            current = current.name_next\n          }\n        }\n      },\n      lookupNode: (parent, name) => {\n        var errCode = FS.mayLookup(parent)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode, parent)\n        }\n        var hash = FS.hashName(parent.id, name)\n        for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n          var nodeName = node.name\n          if (node.parent.id === parent.id && nodeName === name) {\n            return node\n          }\n        }\n        return FS.lookup(parent, name)\n      },\n      createNode: (parent, name, mode, rdev) => {\n        var node = new FS.FSNode(parent, name, mode, rdev)\n        FS.hashAddNode(node)\n        return node\n      },\n      destroyNode: node => {\n        FS.hashRemoveNode(node)\n      },\n      isRoot: node => {\n        return node === node.parent\n      },\n      isMountpoint: node => {\n        return !!node.mounted\n      },\n      isFile: mode => {\n        return (mode & 61440) === 32768\n      },\n      isDir: mode => {\n        return (mode & 61440) === 16384\n      },\n      isLink: mode => {\n        return (mode & 61440) === 40960\n      },\n      isChrdev: mode => {\n        return (mode & 61440) === 8192\n      },\n      isBlkdev: mode => {\n        return (mode & 61440) === 24576\n      },\n      isFIFO: mode => {\n        return (mode & 61440) === 4096\n      },\n      isSocket: mode => {\n        return (mode & 49152) === 49152\n      },\n      flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 },\n      modeStringToFlags: str => {\n        var flags = FS.flagModes[str]\n        if (typeof flags == 'undefined') {\n          throw new Error('Unknown file open mode: ' + str)\n        }\n        return flags\n      },\n      flagsToPermissionString: flag => {\n        var perms = ['r', 'w', 'rw'][flag & 3]\n        if (flag & 512) {\n          perms += 'w'\n        }\n        return perms\n      },\n      nodePermissions: (node, perms) => {\n        if (FS.ignorePermissions) {\n          return 0\n        }\n        if (perms.includes('r') && !(node.mode & 292)) {\n          return 2\n        } else if (perms.includes('w') && !(node.mode & 146)) {\n          return 2\n        } else if (perms.includes('x') && !(node.mode & 73)) {\n          return 2\n        }\n        return 0\n      },\n      mayLookup: dir => {\n        var errCode = FS.nodePermissions(dir, 'x')\n        if (errCode) return errCode\n        if (!dir.node_ops.lookup) return 2\n        return 0\n      },\n      mayCreate: (dir, name) => {\n        try {\n          var node = FS.lookupNode(dir, name)\n          return 20\n        } catch (e) {}\n        return FS.nodePermissions(dir, 'wx')\n      },\n      mayDelete: (dir, name, isdir) => {\n        var node\n        try {\n          node = FS.lookupNode(dir, name)\n        } catch (e) {\n          return e.errno\n        }\n        var errCode = FS.nodePermissions(dir, 'wx')\n        if (errCode) {\n          return errCode\n        }\n        if (isdir) {\n          if (!FS.isDir(node.mode)) {\n            return 54\n          }\n          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n            return 10\n          }\n        } else {\n          if (FS.isDir(node.mode)) {\n            return 31\n          }\n        }\n        return 0\n      },\n      mayOpen: (node, flags) => {\n        if (!node) {\n          return 44\n        }\n        if (FS.isLink(node.mode)) {\n          return 32\n        } else if (FS.isDir(node.mode)) {\n          if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) {\n            return 31\n          }\n        }\n        return FS.nodePermissions(node, FS.flagsToPermissionString(flags))\n      },\n      MAX_OPEN_FDS: 4096,\n      nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => {\n        for (var fd = fd_start; fd <= fd_end; fd++) {\n          if (!FS.streams[fd]) {\n            return fd\n          }\n        }\n        throw new FS.ErrnoError(33)\n      },\n      getStream: fd => FS.streams[fd],\n      createStream: (stream, fd_start, fd_end) => {\n        if (!FS.FSStream) {\n          FS.FSStream = function() {\n            this.shared = {}\n          }\n          FS.FSStream.prototype = {}\n          Object.defineProperties(FS.FSStream.prototype, {\n            object: {\n              get: function() {\n                return this.node\n              },\n              set: function(val) {\n                this.node = val\n              },\n            },\n            isRead: {\n              get: function() {\n                return (this.flags & 2097155) !== 1\n              },\n            },\n            isWrite: {\n              get: function() {\n                return (this.flags & 2097155) !== 0\n              },\n            },\n            isAppend: {\n              get: function() {\n                return this.flags & 1024\n              },\n            },\n            flags: {\n              get: function() {\n                return this.shared.flags\n              },\n              set: function(val) {\n                this.shared.flags = val\n              },\n            },\n            position: {\n              get: function() {\n                return this.shared.position\n              },\n              set: function(val) {\n                this.shared.position = val\n              },\n            },\n          })\n        }\n        stream = Object.assign(new FS.FSStream(), stream)\n        var fd = FS.nextfd(fd_start, fd_end)\n        stream.fd = fd\n        FS.streams[fd] = stream\n        return stream\n      },\n      closeStream: fd => {\n        FS.streams[fd] = null\n      },\n      chrdev_stream_ops: {\n        open: stream => {\n          var device = FS.getDevice(stream.node.rdev)\n          stream.stream_ops = device.stream_ops\n          if (stream.stream_ops.open) {\n            stream.stream_ops.open(stream)\n          }\n        },\n        llseek: () => {\n          throw new FS.ErrnoError(70)\n        },\n      },\n      major: dev => dev >> 8,\n      minor: dev => dev & 255,\n      makedev: (ma, mi) => (ma << 8) | mi,\n      registerDevice: (dev, ops) => {\n        FS.devices[dev] = { stream_ops: ops }\n      },\n      getDevice: dev => FS.devices[dev],\n      getMounts: mount => {\n        var mounts = []\n        var check = [mount]\n        while (check.length) {\n          var m = check.pop()\n          mounts.push(m)\n          check.push.apply(check, m.mounts)\n        }\n        return mounts\n      },\n      syncfs: (populate, callback) => {\n        if (typeof populate == 'function') {\n          callback = populate\n          populate = false\n        }\n        FS.syncFSRequests++\n        if (FS.syncFSRequests > 1) {\n          err(\n            'warning: ' +\n              FS.syncFSRequests +\n              ' FS.syncfs operations in flight at once, probably just doing extra work'\n          )\n        }\n        var mounts = FS.getMounts(FS.root.mount)\n        var completed = 0\n        function doCallback(errCode) {\n          FS.syncFSRequests--\n          return callback(errCode)\n        }\n        function done(errCode) {\n          if (errCode) {\n            if (!done.errored) {\n              done.errored = true\n              return doCallback(errCode)\n            }\n            return\n          }\n          if (++completed >= mounts.length) {\n            doCallback(null)\n          }\n        }\n        mounts.forEach(mount => {\n          if (!mount.type.syncfs) {\n            return done(null)\n          }\n          mount.type.syncfs(mount, populate, done)\n        })\n      },\n      mount: (type, opts, mountpoint) => {\n        var root = mountpoint === '/'\n        var pseudo = !mountpoint\n        var node\n        if (root && FS.root) {\n          throw new FS.ErrnoError(10)\n        } else if (!root && !pseudo) {\n          var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n          mountpoint = lookup.path\n          node = lookup.node\n          if (FS.isMountpoint(node)) {\n            throw new FS.ErrnoError(10)\n          }\n          if (!FS.isDir(node.mode)) {\n            throw new FS.ErrnoError(54)\n          }\n        }\n        var mount = {\n          type: type,\n          opts: opts,\n          mountpoint: mountpoint,\n          mounts: [],\n        }\n        var mountRoot = type.mount(mount)\n        mountRoot.mount = mount\n        mount.root = mountRoot\n        if (root) {\n          FS.root = mountRoot\n        } else if (node) {\n          node.mounted = mount\n          if (node.mount) {\n            node.mount.mounts.push(mount)\n          }\n        }\n        return mountRoot\n      },\n      unmount: mountpoint => {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n        if (!FS.isMountpoint(lookup.node)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = lookup.node\n        var mount = node.mounted\n        var mounts = FS.getMounts(mount)\n        Object.keys(FS.nameTable).forEach(hash => {\n          var current = FS.nameTable[hash]\n          while (current) {\n            var next = current.name_next\n            if (mounts.includes(current.mount)) {\n              FS.destroyNode(current)\n            }\n            current = next\n          }\n        })\n        node.mounted = null\n        var idx = node.mount.mounts.indexOf(mount)\n        node.mount.mounts.splice(idx, 1)\n      },\n      lookup: (parent, name) => {\n        return parent.node_ops.lookup(parent, name)\n      },\n      mknod: (path, mode, dev) => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        if (!name || name === '.' || name === '..') {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.mayCreate(parent, name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.mknod) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.mknod(parent, name, mode, dev)\n      },\n      create: (path, mode) => {\n        mode = mode !== undefined ? mode : 438\n        mode &= 4095\n        mode |= 32768\n        return FS.mknod(path, mode, 0)\n      },\n      mkdir: (path, mode) => {\n        mode = mode !== undefined ? mode : 511\n        mode &= 511 | 512\n        mode |= 16384\n        return FS.mknod(path, mode, 0)\n      },\n      mkdirTree: (path, mode) => {\n        var dirs = path.split('/')\n        var d = ''\n        for (var i = 0; i < dirs.length; ++i) {\n          if (!dirs[i]) continue\n          d += '/' + dirs[i]\n          try {\n            FS.mkdir(d, mode)\n          } catch (e) {\n            if (e.errno != 20) throw e\n          }\n        }\n      },\n      mkdev: (path, mode, dev) => {\n        if (typeof dev == 'undefined') {\n          dev = mode\n          mode = 438\n        }\n        mode |= 8192\n        return FS.mknod(path, mode, dev)\n      },\n      symlink: (oldpath, newpath) => {\n        if (!PATH_FS.resolve(oldpath)) {\n          throw new FS.ErrnoError(44)\n        }\n        var lookup = FS.lookupPath(newpath, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var newname = PATH.basename(newpath)\n        var errCode = FS.mayCreate(parent, newname)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.symlink) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.symlink(parent, newname, oldpath)\n      },\n      rename: (old_path, new_path) => {\n        var old_dirname = PATH.dirname(old_path)\n        var new_dirname = PATH.dirname(new_path)\n        var old_name = PATH.basename(old_path)\n        var new_name = PATH.basename(new_path)\n        var lookup, old_dir, new_dir\n        lookup = FS.lookupPath(old_path, { parent: true })\n        old_dir = lookup.node\n        lookup = FS.lookupPath(new_path, { parent: true })\n        new_dir = lookup.node\n        if (!old_dir || !new_dir) throw new FS.ErrnoError(44)\n        if (old_dir.mount !== new_dir.mount) {\n          throw new FS.ErrnoError(75)\n        }\n        var old_node = FS.lookupNode(old_dir, old_name)\n        var relative = PATH_FS.relative(old_path, new_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(28)\n        }\n        relative = PATH_FS.relative(new_path, old_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(55)\n        }\n        var new_node\n        try {\n          new_node = FS.lookupNode(new_dir, new_name)\n        } catch (e) {}\n        if (old_node === new_node) {\n          return\n        }\n        var isdir = FS.isDir(old_node.mode)\n        var errCode = FS.mayDelete(old_dir, old_name, isdir)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        errCode = new_node\n          ? FS.mayDelete(new_dir, new_name, isdir)\n          : FS.mayCreate(new_dir, new_name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!old_dir.node_ops.rename) {\n          throw new FS.ErrnoError(63)\n        }\n        if (\n          FS.isMountpoint(old_node) ||\n          (new_node && FS.isMountpoint(new_node))\n        ) {\n          throw new FS.ErrnoError(10)\n        }\n        if (new_dir !== old_dir) {\n          errCode = FS.nodePermissions(old_dir, 'w')\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        FS.hashRemoveNode(old_node)\n        try {\n          old_dir.node_ops.rename(old_node, new_dir, new_name)\n        } catch (e) {\n          throw e\n        } finally {\n          FS.hashAddNode(old_node)\n        }\n      },\n      rmdir: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, true)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.rmdir) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.rmdir(parent, name)\n        FS.destroyNode(node)\n      },\n      readdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        if (!node.node_ops.readdir) {\n          throw new FS.ErrnoError(54)\n        }\n        return node.node_ops.readdir(node)\n      },\n      unlink: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, false)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.unlink) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.unlink(parent, name)\n        FS.destroyNode(node)\n      },\n      readlink: path => {\n        var lookup = FS.lookupPath(path)\n        var link = lookup.node\n        if (!link) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!link.node_ops.readlink) {\n          throw new FS.ErrnoError(28)\n        }\n        return PATH_FS.resolve(\n          FS.getPath(link.parent),\n          link.node_ops.readlink(link)\n        )\n      },\n      stat: (path, dontFollow) => {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow })\n        var node = lookup.node\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!node.node_ops.getattr) {\n          throw new FS.ErrnoError(63)\n        }\n        return node.node_ops.getattr(node)\n      },\n      lstat: path => {\n        return FS.stat(path, true)\n      },\n      chmod: (path, mode, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, {\n          mode: (mode & 4095) | (node.mode & ~4095),\n          timestamp: Date.now(),\n        })\n      },\n      lchmod: (path, mode) => {\n        FS.chmod(path, mode, true)\n      },\n      fchmod: (fd, mode) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chmod(stream.node, mode)\n      },\n      chown: (path, uid, gid, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, { timestamp: Date.now() })\n      },\n      lchown: (path, uid, gid) => {\n        FS.chown(path, uid, gid, true)\n      },\n      fchown: (fd, uid, gid) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chown(stream.node, uid, gid)\n      },\n      truncate: (path, len) => {\n        if (len < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: true })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!FS.isFile(node.mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.nodePermissions(node, 'w')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        node.node_ops.setattr(node, { size: len, timestamp: Date.now() })\n      },\n      ftruncate: (fd, len) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(28)\n        }\n        FS.truncate(stream.node, len)\n      },\n      utime: (path, atime, mtime) => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) })\n      },\n      open: (path, flags, mode) => {\n        if (path === '') {\n          throw new FS.ErrnoError(44)\n        }\n        flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags\n        mode = typeof mode == 'undefined' ? 438 : mode\n        if (flags & 64) {\n          mode = (mode & 4095) | 32768\n        } else {\n          mode = 0\n        }\n        var node\n        if (typeof path == 'object') {\n          node = path\n        } else {\n          path = PATH.normalize(path)\n          try {\n            var lookup = FS.lookupPath(path, { follow: !(flags & 131072) })\n            node = lookup.node\n          } catch (e) {}\n        }\n        var created = false\n        if (flags & 64) {\n          if (node) {\n            if (flags & 128) {\n              throw new FS.ErrnoError(20)\n            }\n          } else {\n            node = FS.mknod(path, mode, 0)\n            created = true\n          }\n        }\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (FS.isChrdev(node.mode)) {\n          flags &= ~512\n        }\n        if (flags & 65536 && !FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        if (!created) {\n          var errCode = FS.mayOpen(node, flags)\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        if (flags & 512 && !created) {\n          FS.truncate(node, 0)\n        }\n        flags &= ~(128 | 512 | 131072)\n        var stream = FS.createStream({\n          node: node,\n          path: FS.getPath(node),\n          flags: flags,\n          seekable: true,\n          position: 0,\n          stream_ops: node.stream_ops,\n          ungotten: [],\n          error: false,\n        })\n        if (stream.stream_ops.open) {\n          stream.stream_ops.open(stream)\n        }\n        if (Module['logReadFiles'] && !(flags & 1)) {\n          if (!FS.readFiles) FS.readFiles = {}\n          if (!(path in FS.readFiles)) {\n            FS.readFiles[path] = 1\n          }\n        }\n        return stream\n      },\n      close: stream => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (stream.getdents) stream.getdents = null\n        try {\n          if (stream.stream_ops.close) {\n            stream.stream_ops.close(stream)\n          }\n        } catch (e) {\n          throw e\n        } finally {\n          FS.closeStream(stream.fd)\n        }\n        stream.fd = null\n      },\n      isClosed: stream => {\n        return stream.fd === null\n      },\n      llseek: (stream, offset, whence) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!stream.seekable || !stream.stream_ops.llseek) {\n          throw new FS.ErrnoError(70)\n        }\n        if (whence != 0 && whence != 1 && whence != 2) {\n          throw new FS.ErrnoError(28)\n        }\n        stream.position = stream.stream_ops.llseek(stream, offset, whence)\n        stream.ungotten = []\n        return stream.position\n      },\n      read: (stream, buffer, offset, length, position) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.read) {\n          throw new FS.ErrnoError(28)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesRead = stream.stream_ops.read(\n          stream,\n          buffer,\n          offset,\n          length,\n          position\n        )\n        if (!seeking) stream.position += bytesRead\n        return bytesRead\n      },\n      write: (stream, buffer, offset, length, position, canOwn) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.write) {\n          throw new FS.ErrnoError(28)\n        }\n        if (stream.seekable && stream.flags & 1024) {\n          FS.llseek(stream, 0, 2)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesWritten = stream.stream_ops.write(\n          stream,\n          buffer,\n          offset,\n          length,\n          position,\n          canOwn\n        )\n        if (!seeking) stream.position += bytesWritten\n        return bytesWritten\n      },\n      allocate: (stream, offset, length) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (offset < 0 || length <= 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (!stream.stream_ops.allocate) {\n          throw new FS.ErrnoError(138)\n        }\n        stream.stream_ops.allocate(stream, offset, length)\n      },\n      mmap: (stream, length, position, prot, flags) => {\n        if (\n          (prot & 2) !== 0 &&\n          (flags & 2) === 0 &&\n          (stream.flags & 2097155) !== 2\n        ) {\n          throw new FS.ErrnoError(2)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(2)\n        }\n        if (!stream.stream_ops.mmap) {\n          throw new FS.ErrnoError(43)\n        }\n        return stream.stream_ops.mmap(stream, length, position, prot, flags)\n      },\n      msync: (stream, buffer, offset, length, mmapFlags) => {\n        if (!stream.stream_ops.msync) {\n          return 0\n        }\n        return stream.stream_ops.msync(\n          stream,\n          buffer,\n          offset,\n          length,\n          mmapFlags\n        )\n      },\n      munmap: stream => 0,\n      ioctl: (stream, cmd, arg) => {\n        if (!stream.stream_ops.ioctl) {\n          throw new FS.ErrnoError(59)\n        }\n        return stream.stream_ops.ioctl(stream, cmd, arg)\n      },\n      readFile: (path, opts = {}) => {\n        opts.flags = opts.flags || 0\n        opts.encoding = opts.encoding || 'binary'\n        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {\n          throw new Error('Invalid encoding type \"' + opts.encoding + '\"')\n        }\n        var ret\n        var stream = FS.open(path, opts.flags)\n        var stat = FS.stat(path)\n        var length = stat.size\n        var buf = new Uint8Array(length)\n        FS.read(stream, buf, 0, length, 0)\n        if (opts.encoding === 'utf8') {\n          ret = UTF8ArrayToString(buf, 0)\n        } else if (opts.encoding === 'binary') {\n          ret = buf\n        }\n        FS.close(stream)\n        return ret\n      },\n      writeFile: (path, data, opts = {}) => {\n        opts.flags = opts.flags || 577\n        var stream = FS.open(path, opts.flags, opts.mode)\n        if (typeof data == 'string') {\n          var buf = new Uint8Array(lengthBytesUTF8(data) + 1)\n          var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length)\n          FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn)\n        } else if (ArrayBuffer.isView(data)) {\n          FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn)\n        } else {\n          throw new Error('Unsupported data type')\n        }\n        FS.close(stream)\n      },\n      cwd: () => FS.currentPath,\n      chdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        if (lookup.node === null) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!FS.isDir(lookup.node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        var errCode = FS.nodePermissions(lookup.node, 'x')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        FS.currentPath = lookup.path\n      },\n      createDefaultDirectories: () => {\n        FS.mkdir('/tmp')\n        FS.mkdir('/home')\n        FS.mkdir('/home/web_user')\n      },\n      createDefaultDevices: () => {\n        FS.mkdir('/dev')\n        FS.registerDevice(FS.makedev(1, 3), {\n          read: () => 0,\n          write: (stream, buffer, offset, length, pos) => length,\n        })\n        FS.mkdev('/dev/null', FS.makedev(1, 3))\n        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops)\n        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops)\n        FS.mkdev('/dev/tty', FS.makedev(5, 0))\n        FS.mkdev('/dev/tty1', FS.makedev(6, 0))\n        var random_device = getRandomDevice()\n        FS.createDevice('/dev', 'random', random_device)\n        FS.createDevice('/dev', 'urandom', random_device)\n        FS.mkdir('/dev/shm')\n        FS.mkdir('/dev/shm/tmp')\n      },\n      createSpecialDirectories: () => {\n        FS.mkdir('/proc')\n        var proc_self = FS.mkdir('/proc/self')\n        FS.mkdir('/proc/self/fd')\n        FS.mount(\n          {\n            mount: () => {\n              var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73)\n              node.node_ops = {\n                lookup: (parent, name) => {\n                  var fd = +name\n                  var stream = FS.getStream(fd)\n                  if (!stream) throw new FS.ErrnoError(8)\n                  var ret = {\n                    parent: null,\n                    mount: { mountpoint: 'fake' },\n                    node_ops: { readlink: () => stream.path },\n                  }\n                  ret.parent = ret\n                  return ret\n                },\n              }\n              return node\n            },\n          },\n          {},\n          '/proc/self/fd'\n        )\n      },\n      createStandardStreams: () => {\n        if (Module['stdin']) {\n          FS.createDevice('/dev', 'stdin', Module['stdin'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdin')\n        }\n        if (Module['stdout']) {\n          FS.createDevice('/dev', 'stdout', null, Module['stdout'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdout')\n        }\n        if (Module['stderr']) {\n          FS.createDevice('/dev', 'stderr', null, Module['stderr'])\n        } else {\n          FS.symlink('/dev/tty1', '/dev/stderr')\n        }\n        var stdin = FS.open('/dev/stdin', 0)\n        var stdout = FS.open('/dev/stdout', 1)\n        var stderr = FS.open('/dev/stderr', 1)\n      },\n      ensureErrnoError: () => {\n        if (FS.ErrnoError) return\n        FS.ErrnoError = function ErrnoError(errno, node) {\n          this.node = node\n          this.setErrno = function(errno) {\n            this.errno = errno\n          }\n          this.setErrno(errno)\n          this.message = 'FS error'\n        }\n        FS.ErrnoError.prototype = new Error()\n        FS.ErrnoError.prototype.constructor = FS.ErrnoError\n        ;[44].forEach(code => {\n          FS.genericErrors[code] = new FS.ErrnoError(code)\n          FS.genericErrors[code].stack = '<generic error, no stack>'\n        })\n      },\n      staticInit: () => {\n        FS.ensureErrnoError()\n        FS.nameTable = new Array(4096)\n        FS.mount(MEMFS, {}, '/')\n        FS.createDefaultDirectories()\n        FS.createDefaultDevices()\n        FS.createSpecialDirectories()\n        FS.filesystems = { MEMFS: MEMFS, NODEFS: NODEFS }\n      },\n      init: (input, output, error) => {\n        FS.init.initialized = true\n        FS.ensureErrnoError()\n        Module['stdin'] = input || Module['stdin']\n        Module['stdout'] = output || Module['stdout']\n        Module['stderr'] = error || Module['stderr']\n        FS.createStandardStreams()\n      },\n      quit: () => {\n        FS.init.initialized = false\n        for (var i = 0; i < FS.streams.length; i++) {\n          var stream = FS.streams[i]\n          if (!stream) {\n            continue\n          }\n          FS.close(stream)\n        }\n      },\n      getMode: (canRead, canWrite) => {\n        var mode = 0\n        if (canRead) mode |= 292 | 73\n        if (canWrite) mode |= 146\n        return mode\n      },\n      findObject: (path, dontResolveLastLink) => {\n        var ret = FS.analyzePath(path, dontResolveLastLink)\n        if (!ret.exists) {\n          return null\n        }\n        return ret.object\n      },\n      analyzePath: (path, dontResolveLastLink) => {\n        try {\n          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          path = lookup.path\n        } catch (e) {}\n        var ret = {\n          isRoot: false,\n          exists: false,\n          error: 0,\n          name: null,\n          path: null,\n          object: null,\n          parentExists: false,\n          parentPath: null,\n          parentObject: null,\n        }\n        try {\n          var lookup = FS.lookupPath(path, { parent: true })\n          ret.parentExists = true\n          ret.parentPath = lookup.path\n          ret.parentObject = lookup.node\n          ret.name = PATH.basename(path)\n          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          ret.exists = true\n          ret.path = lookup.path\n          ret.object = lookup.node\n          ret.name = lookup.node.name\n          ret.isRoot = lookup.path === '/'\n        } catch (e) {\n          ret.error = e.errno\n        }\n        return ret\n      },\n      createPath: (parent, path, canRead, canWrite) => {\n        parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n        var parts = path.split('/').reverse()\n        while (parts.length) {\n          var part = parts.pop()\n          if (!part) continue\n          var current = PATH.join2(parent, part)\n          try {\n            FS.mkdir(current)\n          } catch (e) {}\n          parent = current\n        }\n        return current\n      },\n      createFile: (parent, name, properties, canRead, canWrite) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(canRead, canWrite)\n        return FS.create(path, mode)\n      },\n      createDataFile: (parent, name, data, canRead, canWrite, canOwn) => {\n        var path = name\n        if (parent) {\n          parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n          path = name ? PATH.join2(parent, name) : parent\n        }\n        var mode = FS.getMode(canRead, canWrite)\n        var node = FS.create(path, mode)\n        if (data) {\n          if (typeof data == 'string') {\n            var arr = new Array(data.length)\n            for (var i = 0, len = data.length; i < len; ++i)\n              arr[i] = data.charCodeAt(i)\n            data = arr\n          }\n          FS.chmod(node, mode | 146)\n          var stream = FS.open(node, 577)\n          FS.write(stream, data, 0, data.length, 0, canOwn)\n          FS.close(stream)\n          FS.chmod(node, mode)\n        }\n        return node\n      },\n      createDevice: (parent, name, input, output) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(!!input, !!output)\n        if (!FS.createDevice.major) FS.createDevice.major = 64\n        var dev = FS.makedev(FS.createDevice.major++, 0)\n        FS.registerDevice(dev, {\n          open: stream => {\n            stream.seekable = false\n          },\n          close: stream => {\n            if (output && output.buffer && output.buffer.length) {\n              output(10)\n            }\n          },\n          read: (stream, buffer, offset, length, pos) => {\n            var bytesRead = 0\n            for (var i = 0; i < length; i++) {\n              var result\n              try {\n                result = input()\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n              if (result === undefined && bytesRead === 0) {\n                throw new FS.ErrnoError(6)\n              }\n              if (result === null || result === undefined) break\n              bytesRead++\n              buffer[offset + i] = result\n            }\n            if (bytesRead) {\n              stream.node.timestamp = Date.now()\n            }\n            return bytesRead\n          },\n          write: (stream, buffer, offset, length, pos) => {\n            for (var i = 0; i < length; i++) {\n              try {\n                output(buffer[offset + i])\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n            }\n            if (length) {\n              stream.node.timestamp = Date.now()\n            }\n            return i\n          },\n        })\n        return FS.mkdev(path, mode, dev)\n      },\n      forceLoadFile: obj => {\n        if (obj.isDevice || obj.isFolder || obj.link || obj.contents)\n          return true\n        if (typeof XMLHttpRequest != 'undefined') {\n          throw new Error(\n            'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.'\n          )\n        } else if (read_) {\n          try {\n            obj.contents = intArrayFromString(read_(obj.url), true)\n            obj.usedBytes = obj.contents.length\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n        } else {\n          throw new Error('Cannot load without read() or XMLHttpRequest.')\n        }\n      },\n      createLazyFile: (parent, name, url, canRead, canWrite) => {\n        function LazyUint8Array() {\n          this.lengthKnown = false\n          this.chunks = []\n        }\n        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n          if (idx > this.length - 1 || idx < 0) {\n            return undefined\n          }\n          var chunkOffset = idx % this.chunkSize\n          var chunkNum = (idx / this.chunkSize) | 0\n          return this.getter(chunkNum)[chunkOffset]\n        }\n        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(\n          getter\n        ) {\n          this.getter = getter\n        }\n        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n          var xhr = new XMLHttpRequest()\n          xhr.open('HEAD', url, false)\n          xhr.send(null)\n          if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n            throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n          var datalength = Number(xhr.getResponseHeader('Content-length'))\n          var header\n          var hasByteServing =\n            (header = xhr.getResponseHeader('Accept-Ranges')) &&\n            header === 'bytes'\n          var usesGzip =\n            (header = xhr.getResponseHeader('Content-Encoding')) &&\n            header === 'gzip'\n          var chunkSize = 1024 * 1024\n          if (!hasByteServing) chunkSize = datalength\n          var doXHR = (from, to) => {\n            if (from > to)\n              throw new Error(\n                'invalid range (' +\n                  from +\n                  ', ' +\n                  to +\n                  ') or no bytes requested!'\n              )\n            if (to > datalength - 1)\n              throw new Error(\n                'only ' + datalength + ' bytes available! programmer error!'\n              )\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            if (datalength !== chunkSize)\n              xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to)\n            xhr.responseType = 'arraybuffer'\n            if (xhr.overrideMimeType) {\n              xhr.overrideMimeType('text/plain; charset=x-user-defined')\n            }\n            xhr.send(null)\n            if (\n              !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)\n            )\n              throw new Error(\n                \"Couldn't load \" + url + '. Status: ' + xhr.status\n              )\n            if (xhr.response !== undefined) {\n              return new Uint8Array(xhr.response || [])\n            }\n            return intArrayFromString(xhr.responseText || '', true)\n          }\n          var lazyArray = this\n          lazyArray.setDataGetter(chunkNum => {\n            var start = chunkNum * chunkSize\n            var end = (chunkNum + 1) * chunkSize - 1\n            end = Math.min(end, datalength - 1)\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined') {\n              lazyArray.chunks[chunkNum] = doXHR(start, end)\n            }\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined')\n              throw new Error('doXHR failed!')\n            return lazyArray.chunks[chunkNum]\n          })\n          if (usesGzip || !datalength) {\n            chunkSize = datalength = 1\n            datalength = this.getter(0).length\n            chunkSize = datalength\n            out(\n              'LazyFiles on gzip forces download of the whole file when length is accessed'\n            )\n          }\n          this._length = datalength\n          this._chunkSize = chunkSize\n          this.lengthKnown = true\n        }\n        if (typeof XMLHttpRequest != 'undefined') {\n          if (!ENVIRONMENT_IS_WORKER)\n            throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'\n          var lazyArray = new LazyUint8Array()\n          Object.defineProperties(lazyArray, {\n            length: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._length\n              },\n            },\n            chunkSize: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._chunkSize\n              },\n            },\n          })\n          var properties = { isDevice: false, contents: lazyArray }\n        } else {\n          var properties = { isDevice: false, url: url }\n        }\n        var node = FS.createFile(parent, name, properties, canRead, canWrite)\n        if (properties.contents) {\n          node.contents = properties.contents\n        } else if (properties.url) {\n          node.contents = null\n          node.url = properties.url\n        }\n        Object.defineProperties(node, {\n          usedBytes: {\n            get: function() {\n              return this.contents.length\n            },\n          },\n        })\n        var stream_ops = {}\n        var keys = Object.keys(node.stream_ops)\n        keys.forEach(key => {\n          var fn = node.stream_ops[key]\n          stream_ops[key] = function forceLoadLazyFile() {\n            FS.forceLoadFile(node)\n            return fn.apply(null, arguments)\n          }\n        })\n        function writeChunks(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= contents.length) return 0\n          var size = Math.min(contents.length - position, length)\n          if (contents.slice) {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents[position + i]\n            }\n          } else {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents.get(position + i)\n            }\n          }\n          return size\n        }\n        stream_ops.read = (stream, buffer, offset, length, position) => {\n          FS.forceLoadFile(node)\n          return writeChunks(stream, buffer, offset, length, position)\n        }\n        stream_ops.mmap = (stream, length, position, prot, flags) => {\n          FS.forceLoadFile(node)\n          var ptr = mmapAlloc(length)\n          if (!ptr) {\n            throw new FS.ErrnoError(48)\n          }\n          writeChunks(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        }\n        node.stream_ops = stream_ops\n        return node\n      },\n      createPreloadedFile: (\n        parent,\n        name,\n        url,\n        canRead,\n        canWrite,\n        onload,\n        onerror,\n        dontCreateFile,\n        canOwn,\n        preFinish\n      ) => {\n        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent\n        var dep = getUniqueRunDependency('cp ' + fullname)\n        function processData(byteArray) {\n          function finish(byteArray) {\n            if (preFinish) preFinish()\n            if (!dontCreateFile) {\n              FS.createDataFile(\n                parent,\n                name,\n                byteArray,\n                canRead,\n                canWrite,\n                canOwn\n              )\n            }\n            if (onload) onload()\n            removeRunDependency(dep)\n          }\n          if (\n            Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => {\n              if (onerror) onerror()\n              removeRunDependency(dep)\n            })\n          ) {\n            return\n          }\n          finish(byteArray)\n        }\n        addRunDependency(dep)\n        if (typeof url == 'string') {\n          asyncLoad(url, byteArray => processData(byteArray), onerror)\n        } else {\n          processData(url)\n        }\n      },\n      indexedDB: () => {\n        return (\n          window.indexedDB ||\n          window.mozIndexedDB ||\n          window.webkitIndexedDB ||\n          window.msIndexedDB\n        )\n      },\n      DB_NAME: () => {\n        return 'EM_FS_' + window.location.pathname\n      },\n      DB_VERSION: 20,\n      DB_STORE_NAME: 'FILE_DATA',\n      saveFilesToDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = () => {\n          out('creating db')\n          var db = openRequest.result\n          db.createObjectStore(FS.DB_STORE_NAME)\n        }\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite')\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var putRequest = files.put(\n              FS.analyzePath(path).object.contents,\n              path\n            )\n            putRequest.onsuccess = () => {\n              ok++\n              if (ok + fail == total) finish()\n            }\n            putRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n      loadFilesFromDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = onerror\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          try {\n            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly')\n          } catch (e) {\n            onerror(e)\n            return\n          }\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var getRequest = files.get(path)\n            getRequest.onsuccess = () => {\n              if (FS.analyzePath(path).exists) {\n                FS.unlink(path)\n              }\n              FS.createDataFile(\n                PATH.dirname(path),\n                PATH.basename(path),\n                getRequest.result,\n                true,\n                true,\n                true\n              )\n              ok++\n              if (ok + fail == total) finish()\n            }\n            getRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n    }\n    var SYSCALLS = {\n      DEFAULT_POLLMASK: 5,\n      calculateAt: function(dirfd, path, allowEmpty) {\n        if (PATH.isAbs(path)) {\n          return path\n        }\n        var dir\n        if (dirfd === -100) {\n          dir = FS.cwd()\n        } else {\n          var dirstream = SYSCALLS.getStreamFromFD(dirfd)\n          dir = dirstream.path\n        }\n        if (path.length == 0) {\n          if (!allowEmpty) {\n            throw new FS.ErrnoError(44)\n          }\n          return dir\n        }\n        return PATH.join2(dir, path)\n      },\n      doStat: function(func, path, buf) {\n        try {\n          var stat = func(path)\n        } catch (e) {\n          if (\n            e &&\n            e.node &&\n            PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))\n          ) {\n            return -54\n          }\n          throw e\n        }\n        HEAP32[buf >> 2] = stat.dev\n        HEAP32[(buf + 8) >> 2] = stat.ino\n        HEAP32[(buf + 12) >> 2] = stat.mode\n        HEAPU32[(buf + 16) >> 2] = stat.nlink\n        HEAP32[(buf + 20) >> 2] = stat.uid\n        HEAP32[(buf + 24) >> 2] = stat.gid\n        HEAP32[(buf + 28) >> 2] = stat.rdev\n        ;(tempI64 = [\n          stat.size >>> 0,\n          ((tempDouble = stat.size),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 40) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 44) >> 2] = tempI64[1])\n        HEAP32[(buf + 48) >> 2] = 4096\n        HEAP32[(buf + 52) >> 2] = stat.blocks\n        var atime = stat.atime.getTime()\n        var mtime = stat.mtime.getTime()\n        var ctime = stat.ctime.getTime()\n        ;(tempI64 = [\n          Math.floor(atime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(atime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 56) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 60) >> 2] = tempI64[1])\n        HEAPU32[(buf + 64) >> 2] = (atime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(mtime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(mtime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 72) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 76) >> 2] = tempI64[1])\n        HEAPU32[(buf + 80) >> 2] = (mtime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(ctime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(ctime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 88) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 92) >> 2] = tempI64[1])\n        HEAPU32[(buf + 96) >> 2] = (ctime % 1e3) * 1e3\n        ;(tempI64 = [\n          stat.ino >>> 0,\n          ((tempDouble = stat.ino),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 104) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 108) >> 2] = tempI64[1])\n        return 0\n      },\n      doMsync: function(addr, stream, len, flags, offset) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (flags & 2) {\n          return 0\n        }\n        var buffer = HEAPU8.slice(addr, addr + len)\n        FS.msync(stream, buffer, offset, len, flags)\n      },\n      varargs: undefined,\n      get: function() {\n        SYSCALLS.varargs += 4\n        var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]\n        return ret\n      },\n      getStr: function(ptr) {\n        var ret = UTF8ToString(ptr)\n        return ret\n      },\n      getStreamFromFD: function(fd) {\n        var stream = FS.getStream(fd)\n        if (!stream) throw new FS.ErrnoError(8)\n        return stream\n      },\n    }\n    function ___syscall_fcntl64(fd, cmd, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (cmd) {\n          case 0: {\n            var arg = SYSCALLS.get()\n            if (arg < 0) {\n              return -28\n            }\n            var newStream\n            newStream = FS.createStream(stream, arg)\n            return newStream.fd\n          }\n          case 1:\n          case 2:\n            return 0\n          case 3:\n            return stream.flags\n          case 4: {\n            var arg = SYSCALLS.get()\n            stream.flags |= arg\n            return 0\n          }\n          case 5: {\n            var arg = SYSCALLS.get()\n            var offset = 0\n            HEAP16[(arg + offset) >> 1] = 2\n            return 0\n          }\n          case 6:\n          case 7:\n            return 0\n          case 16:\n          case 8:\n            return -28\n          case 9:\n            setErrNo(28)\n            return -1\n          default: {\n            return -28\n          }\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_getcwd(buf, size) {\n      try {\n        if (size === 0) return -28\n        var cwd = FS.cwd()\n        var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1\n        if (size < cwdLengthInBytes) return -68\n        stringToUTF8(cwd, buf, size)\n        return cwdLengthInBytes\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_ioctl(fd, op, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (op) {\n          case 21509:\n          case 21505: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21510:\n          case 21511:\n          case 21512:\n          case 21506:\n          case 21507:\n          case 21508: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21519: {\n            if (!stream.tty) return -59\n            var argp = SYSCALLS.get()\n            HEAP32[argp >> 2] = 0\n            return 0\n          }\n          case 21520: {\n            if (!stream.tty) return -59\n            return -28\n          }\n          case 21531: {\n            var argp = SYSCALLS.get()\n            return FS.ioctl(stream, op, argp)\n          }\n          case 21523: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21524: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          default:\n            return -28\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_openat(dirfd, path, flags, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        var mode = varargs ? SYSCALLS.get() : 0\n        return FS.open(path, flags, mode).fd\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_readlinkat(dirfd, path, buf, bufsize) {\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        if (bufsize <= 0) return -28\n        var ret = FS.readlink(path)\n        var len = Math.min(bufsize, lengthBytesUTF8(ret))\n        var endChar = HEAP8[buf + len]\n        stringToUTF8(ret, buf, bufsize + 1)\n        HEAP8[buf + len] = endChar\n        return len\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_stat64(path, buf) {\n      try {\n        path = SYSCALLS.getStr(path)\n        return SYSCALLS.doStat(FS.stat, path, buf)\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function _abort() {\n      abort('')\n    }\n    function _emscripten_memcpy_big(dest, src, num) {\n      HEAPU8.copyWithin(dest, src, src + num)\n    }\n    function getHeapMax() {\n      return 2147483648\n    }\n    function emscripten_realloc_buffer(size) {\n      try {\n        wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16)\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        return 1\n      } catch (e) {}\n    }\n    function _emscripten_resize_heap(requestedSize) {\n      var oldSize = HEAPU8.length\n      requestedSize = requestedSize >>> 0\n      var maxHeapSize = getHeapMax()\n      if (requestedSize > maxHeapSize) {\n        return false\n      }\n      let alignUp = (x, multiple) =>\n        x + ((multiple - (x % multiple)) % multiple)\n      for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {\n        var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown)\n        overGrownHeapSize = Math.min(\n          overGrownHeapSize,\n          requestedSize + 100663296\n        )\n        var newSize = Math.min(\n          maxHeapSize,\n          alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)\n        )\n        var replacement = emscripten_realloc_buffer(newSize)\n        if (replacement) {\n          return true\n        }\n      }\n      return false\n    }\n    var ENV = {}\n    function getExecutableName() {\n      return thisProgram || './this.program'\n    }\n    function getEnvStrings() {\n      if (!getEnvStrings.strings) {\n        var lang =\n          (\n            (typeof navigator == 'object' &&\n              navigator.languages &&\n              navigator.languages[0]) ||\n            'C'\n          ).replace('-', '_') + '.UTF-8'\n        var env = {\n          USER: 'web_user',\n          LOGNAME: 'web_user',\n          PATH: '/',\n          PWD: '/',\n          HOME: '/home/web_user',\n          LANG: lang,\n          _: getExecutableName(),\n        }\n        for (var x in ENV) {\n          if (ENV[x] === undefined) delete env[x]\n          else env[x] = ENV[x]\n        }\n        var strings = []\n        for (var x in env) {\n          strings.push(x + '=' + env[x])\n        }\n        getEnvStrings.strings = strings\n      }\n      return getEnvStrings.strings\n    }\n    function writeAsciiToMemory(str, buffer, dontAddNull) {\n      for (var i = 0; i < str.length; ++i) {\n        HEAP8[buffer++ >> 0] = str.charCodeAt(i)\n      }\n      if (!dontAddNull) HEAP8[buffer >> 0] = 0\n    }\n    function _environ_get(__environ, environ_buf) {\n      var bufSize = 0\n      getEnvStrings().forEach(function(string, i) {\n        var ptr = environ_buf + bufSize\n        HEAPU32[(__environ + i * 4) >> 2] = ptr\n        writeAsciiToMemory(string, ptr)\n        bufSize += string.length + 1\n      })\n      return 0\n    }\n    function _environ_sizes_get(penviron_count, penviron_buf_size) {\n      var strings = getEnvStrings()\n      HEAPU32[penviron_count >> 2] = strings.length\n      var bufSize = 0\n      strings.forEach(function(string) {\n        bufSize += string.length + 1\n      })\n      HEAPU32[penviron_buf_size >> 2] = bufSize\n      return 0\n    }\n    function _proc_exit(code) {\n      EXITSTATUS = code\n      if (!keepRuntimeAlive()) {\n        if (Module['onExit']) Module['onExit'](code)\n        ABORT = true\n      }\n      quit_(code, new ExitStatus(code))\n    }\n    function exitJS(status, implicit) {\n      EXITSTATUS = status\n      _proc_exit(status)\n    }\n    var _exit = exitJS\n    function _fd_close(fd) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.close(stream)\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doReadv(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.read(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n        if (curr < len) break\n      }\n      return ret\n    }\n    function _fd_read(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doReadv(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function convertI32PairToI53Checked(lo, hi) {\n      return (hi + 2097152) >>> 0 < 4194305 - !!lo\n        ? (lo >>> 0) + hi * 4294967296\n        : NaN\n    }\n    function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {\n      try {\n        var offset = convertI32PairToI53Checked(offset_low, offset_high)\n        if (isNaN(offset)) return 61\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.llseek(stream, offset, whence)\n        ;(tempI64 = [\n          stream.position >>> 0,\n          ((tempDouble = stream.position),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[newOffset >> 2] = tempI64[0]),\n          (HEAP32[(newOffset + 4) >> 2] = tempI64[1])\n        if (stream.getdents && offset === 0 && whence === 0)\n          stream.getdents = null\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doWritev(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.write(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n      }\n      return ret\n    }\n    function _fd_write(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doWritev(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function __isLeapYear(year) {\n      return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n    }\n    function __arraySum(array, index) {\n      var sum = 0\n      for (var i = 0; i <= index; sum += array[i++]) {}\n      return sum\n    }\n    var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    function __addDays(date, days) {\n      var newDate = new Date(date.getTime())\n      while (days > 0) {\n        var leap = __isLeapYear(newDate.getFullYear())\n        var currentMonth = newDate.getMonth()\n        var daysInCurrentMonth = (leap\n          ? __MONTH_DAYS_LEAP\n          : __MONTH_DAYS_REGULAR)[currentMonth]\n        if (days > daysInCurrentMonth - newDate.getDate()) {\n          days -= daysInCurrentMonth - newDate.getDate() + 1\n          newDate.setDate(1)\n          if (currentMonth < 11) {\n            newDate.setMonth(currentMonth + 1)\n          } else {\n            newDate.setMonth(0)\n            newDate.setFullYear(newDate.getFullYear() + 1)\n          }\n        } else {\n          newDate.setDate(newDate.getDate() + days)\n          return newDate\n        }\n      }\n      return newDate\n    }\n    function writeArrayToMemory(array, buffer) {\n      HEAP8.set(array, buffer)\n    }\n    function _strftime(s, maxsize, format, tm) {\n      var tm_zone = HEAP32[(tm + 40) >> 2]\n      var date = {\n        tm_sec: HEAP32[tm >> 2],\n        tm_min: HEAP32[(tm + 4) >> 2],\n        tm_hour: HEAP32[(tm + 8) >> 2],\n        tm_mday: HEAP32[(tm + 12) >> 2],\n        tm_mon: HEAP32[(tm + 16) >> 2],\n        tm_year: HEAP32[(tm + 20) >> 2],\n        tm_wday: HEAP32[(tm + 24) >> 2],\n        tm_yday: HEAP32[(tm + 28) >> 2],\n        tm_isdst: HEAP32[(tm + 32) >> 2],\n        tm_gmtoff: HEAP32[(tm + 36) >> 2],\n        tm_zone: tm_zone ? UTF8ToString(tm_zone) : '',\n      }\n      var pattern = UTF8ToString(format)\n      var EXPANSION_RULES_1 = {\n        '%c': '%a %b %d %H:%M:%S %Y',\n        '%D': '%m/%d/%y',\n        '%F': '%Y-%m-%d',\n        '%h': '%b',\n        '%r': '%I:%M:%S %p',\n        '%R': '%H:%M',\n        '%T': '%H:%M:%S',\n        '%x': '%m/%d/%y',\n        '%X': '%H:%M:%S',\n        '%Ec': '%c',\n        '%EC': '%C',\n        '%Ex': '%m/%d/%y',\n        '%EX': '%H:%M:%S',\n        '%Ey': '%y',\n        '%EY': '%Y',\n        '%Od': '%d',\n        '%Oe': '%e',\n        '%OH': '%H',\n        '%OI': '%I',\n        '%Om': '%m',\n        '%OM': '%M',\n        '%OS': '%S',\n        '%Ou': '%u',\n        '%OU': '%U',\n        '%OV': '%V',\n        '%Ow': '%w',\n        '%OW': '%W',\n        '%Oy': '%y',\n      }\n      for (var rule in EXPANSION_RULES_1) {\n        pattern = pattern.replace(\n          new RegExp(rule, 'g'),\n          EXPANSION_RULES_1[rule]\n        )\n      }\n      var WEEKDAYS = [\n        'Sunday',\n        'Monday',\n        'Tuesday',\n        'Wednesday',\n        'Thursday',\n        'Friday',\n        'Saturday',\n      ]\n      var MONTHS = [\n        'January',\n        'February',\n        'March',\n        'April',\n        'May',\n        'June',\n        'July',\n        'August',\n        'September',\n        'October',\n        'November',\n        'December',\n      ]\n      function leadingSomething(value, digits, character) {\n        var str = typeof value == 'number' ? value.toString() : value || ''\n        while (str.length < digits) {\n          str = character[0] + str\n        }\n        return str\n      }\n      function leadingNulls(value, digits) {\n        return leadingSomething(value, digits, '0')\n      }\n      function compareByDay(date1, date2) {\n        function sgn(value) {\n          return value < 0 ? -1 : value > 0 ? 1 : 0\n        }\n        var compare\n        if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) {\n          if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) {\n            compare = sgn(date1.getDate() - date2.getDate())\n          }\n        }\n        return compare\n      }\n      function getFirstWeekStartDate(janFourth) {\n        switch (janFourth.getDay()) {\n          case 0:\n            return new Date(janFourth.getFullYear() - 1, 11, 29)\n          case 1:\n            return janFourth\n          case 2:\n            return new Date(janFourth.getFullYear(), 0, 3)\n          case 3:\n            return new Date(janFourth.getFullYear(), 0, 2)\n          case 4:\n            return new Date(janFourth.getFullYear(), 0, 1)\n          case 5:\n            return new Date(janFourth.getFullYear() - 1, 11, 31)\n          case 6:\n            return new Date(janFourth.getFullYear() - 1, 11, 30)\n        }\n      }\n      function getWeekBasedYear(date) {\n        var thisDate = __addDays(\n          new Date(date.tm_year + 1900, 0, 1),\n          date.tm_yday\n        )\n        var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4)\n        var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4)\n        var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear)\n        var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear)\n        if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {\n          if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {\n            return thisDate.getFullYear() + 1\n          }\n          return thisDate.getFullYear()\n        }\n        return thisDate.getFullYear() - 1\n      }\n      var EXPANSION_RULES_2 = {\n        '%a': function(date) {\n          return WEEKDAYS[date.tm_wday].substring(0, 3)\n        },\n        '%A': function(date) {\n          return WEEKDAYS[date.tm_wday]\n        },\n        '%b': function(date) {\n          return MONTHS[date.tm_mon].substring(0, 3)\n        },\n        '%B': function(date) {\n          return MONTHS[date.tm_mon]\n        },\n        '%C': function(date) {\n          var year = date.tm_year + 1900\n          return leadingNulls((year / 100) | 0, 2)\n        },\n        '%d': function(date) {\n          return leadingNulls(date.tm_mday, 2)\n        },\n        '%e': function(date) {\n          return leadingSomething(date.tm_mday, 2, ' ')\n        },\n        '%g': function(date) {\n          return getWeekBasedYear(date)\n            .toString()\n            .substring(2)\n        },\n        '%G': function(date) {\n          return getWeekBasedYear(date)\n        },\n        '%H': function(date) {\n          return leadingNulls(date.tm_hour, 2)\n        },\n        '%I': function(date) {\n          var twelveHour = date.tm_hour\n          if (twelveHour == 0) twelveHour = 12\n          else if (twelveHour > 12) twelveHour -= 12\n          return leadingNulls(twelveHour, 2)\n        },\n        '%j': function(date) {\n          return leadingNulls(\n            date.tm_mday +\n              __arraySum(\n                __isLeapYear(date.tm_year + 1900)\n                  ? __MONTH_DAYS_LEAP\n                  : __MONTH_DAYS_REGULAR,\n                date.tm_mon - 1\n              ),\n            3\n          )\n        },\n        '%m': function(date) {\n          return leadingNulls(date.tm_mon + 1, 2)\n        },\n        '%M': function(date) {\n          return leadingNulls(date.tm_min, 2)\n        },\n        '%n': function() {\n          return '\\n'\n        },\n        '%p': function(date) {\n          if (date.tm_hour >= 0 && date.tm_hour < 12) {\n            return 'AM'\n          }\n          return 'PM'\n        },\n        '%S': function(date) {\n          return leadingNulls(date.tm_sec, 2)\n        },\n        '%t': function() {\n          return '\\t'\n        },\n        '%u': function(date) {\n          return date.tm_wday || 7\n        },\n        '%U': function(date) {\n          var days = date.tm_yday + 7 - date.tm_wday\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%V': function(date) {\n          var val = Math.floor(\n            (date.tm_yday + 7 - ((date.tm_wday + 6) % 7)) / 7\n          )\n          if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) {\n            val++\n          }\n          if (!val) {\n            val = 52\n            var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7\n            if (\n              dec31 == 4 ||\n              (dec31 == 5 && __isLeapYear((date.tm_year % 400) - 1))\n            ) {\n              val++\n            }\n          } else if (val == 53) {\n            var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7\n            if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) val = 1\n          }\n          return leadingNulls(val, 2)\n        },\n        '%w': function(date) {\n          return date.tm_wday\n        },\n        '%W': function(date) {\n          var days = date.tm_yday + 7 - ((date.tm_wday + 6) % 7)\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%y': function(date) {\n          return (date.tm_year + 1900).toString().substring(2)\n        },\n        '%Y': function(date) {\n          return date.tm_year + 1900\n        },\n        '%z': function(date) {\n          var off = date.tm_gmtoff\n          var ahead = off >= 0\n          off = Math.abs(off) / 60\n          off = (off / 60) * 100 + (off % 60)\n          return (ahead ? '+' : '-') + String('0000' + off).slice(-4)\n        },\n        '%Z': function(date) {\n          return date.tm_zone\n        },\n        '%%': function() {\n          return '%'\n        },\n      }\n      pattern = pattern.replace(/%%/g, '\\0\\0')\n      for (var rule in EXPANSION_RULES_2) {\n        if (pattern.includes(rule)) {\n          pattern = pattern.replace(\n            new RegExp(rule, 'g'),\n            EXPANSION_RULES_2[rule](date)\n          )\n        }\n      }\n      pattern = pattern.replace(/\\0\\0/g, '%')\n      var bytes = intArrayFromString(pattern, false)\n      if (bytes.length > maxsize) {\n        return 0\n      }\n      writeArrayToMemory(bytes, s)\n      return bytes.length - 1\n    }\n    function _strftime_l(s, maxsize, format, tm, loc) {\n      return _strftime(s, maxsize, format, tm)\n    }\n    function handleException(e) {\n      if (e instanceof ExitStatus || e == 'unwind') {\n        return EXITSTATUS\n      }\n      quit_(1, e)\n    }\n    function allocateUTF8OnStack(str) {\n      var size = lengthBytesUTF8(str) + 1\n      var ret = stackAlloc(size)\n      stringToUTF8Array(str, HEAP8, ret, size)\n      return ret\n    }\n    function getCFunc(ident) {\n      var func = Module['_' + ident]\n      return func\n    }\n    function ccall(ident, returnType, argTypes, args, opts) {\n      var toC = {\n        string: str => {\n          var ret = 0\n          if (str !== null && str !== undefined && str !== 0) {\n            var len = (str.length << 2) + 1\n            ret = stackAlloc(len)\n            stringToUTF8(str, ret, len)\n          }\n          return ret\n        },\n        array: arr => {\n          var ret = stackAlloc(arr.length)\n          writeArrayToMemory(arr, ret)\n          return ret\n        },\n      }\n      function convertReturnValue(ret) {\n        if (returnType === 'string') {\n          return UTF8ToString(ret)\n        }\n        if (returnType === 'boolean') return Boolean(ret)\n        return ret\n      }\n      var func = getCFunc(ident)\n      var cArgs = []\n      var stack = 0\n      if (args) {\n        for (var i = 0; i < args.length; i++) {\n          var converter = toC[argTypes[i]]\n          if (converter) {\n            if (stack === 0) stack = stackSave()\n            cArgs[i] = converter(args[i])\n          } else {\n            cArgs[i] = args[i]\n          }\n        }\n      }\n      var ret = func.apply(null, cArgs)\n      function onDone(ret) {\n        if (stack !== 0) stackRestore(stack)\n        return convertReturnValue(ret)\n      }\n      ret = onDone(ret)\n      return ret\n    }\n    function cwrap(ident, returnType, argTypes, opts) {\n      argTypes = argTypes || []\n      var numericArgs = argTypes.every(\n        type => type === 'number' || type === 'boolean'\n      )\n      var numericRet = returnType !== 'string'\n      if (numericRet && numericArgs && !opts) {\n        return getCFunc(ident)\n      }\n      return function() {\n        return ccall(ident, returnType, argTypes, arguments, opts)\n      }\n    }\n    function AsciiToString(ptr) {\n      var str = ''\n      while (1) {\n        var ch = HEAPU8[ptr++ >> 0]\n        if (!ch) return str\n        str += String.fromCharCode(ch)\n      }\n    }\n    var FSNode = function(parent, name, mode, rdev) {\n      if (!parent) {\n        parent = this\n      }\n      this.parent = parent\n      this.mount = parent.mount\n      this.mounted = null\n      this.id = FS.nextInode++\n      this.name = name\n      this.mode = mode\n      this.node_ops = {}\n      this.stream_ops = {}\n      this.rdev = rdev\n    }\n    var readMode = 292 | 73\n    var writeMode = 146\n    Object.defineProperties(FSNode.prototype, {\n      read: {\n        get: function() {\n          return (this.mode & readMode) === readMode\n        },\n        set: function(val) {\n          val ? (this.mode |= readMode) : (this.mode &= ~readMode)\n        },\n      },\n      write: {\n        get: function() {\n          return (this.mode & writeMode) === writeMode\n        },\n        set: function(val) {\n          val ? (this.mode |= writeMode) : (this.mode &= ~writeMode)\n        },\n      },\n      isFolder: {\n        get: function() {\n          return FS.isDir(this.mode)\n        },\n      },\n      isDevice: {\n        get: function() {\n          return FS.isChrdev(this.mode)\n        },\n      },\n    })\n    FS.FSNode = FSNode\n    FS.staticInit()\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_unlink'] = FS.unlink\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    if (ENVIRONMENT_IS_NODE) {\n      NODEFS.staticInit()\n    }\n    ERRNO_CODES = {\n      EPERM: 63,\n      ENOENT: 44,\n      ESRCH: 71,\n      EINTR: 27,\n      EIO: 29,\n      ENXIO: 60,\n      E2BIG: 1,\n      ENOEXEC: 45,\n      EBADF: 8,\n      ECHILD: 12,\n      EAGAIN: 6,\n      EWOULDBLOCK: 6,\n      ENOMEM: 48,\n      EACCES: 2,\n      EFAULT: 21,\n      ENOTBLK: 105,\n      EBUSY: 10,\n      EEXIST: 20,\n      EXDEV: 75,\n      ENODEV: 43,\n      ENOTDIR: 54,\n      EISDIR: 31,\n      EINVAL: 28,\n      ENFILE: 41,\n      EMFILE: 33,\n      ENOTTY: 59,\n      ETXTBSY: 74,\n      EFBIG: 22,\n      ENOSPC: 51,\n      ESPIPE: 70,\n      EROFS: 69,\n      EMLINK: 34,\n      EPIPE: 64,\n      EDOM: 18,\n      ERANGE: 68,\n      ENOMSG: 49,\n      EIDRM: 24,\n      ECHRNG: 106,\n      EL2NSYNC: 156,\n      EL3HLT: 107,\n      EL3RST: 108,\n      ELNRNG: 109,\n      EUNATCH: 110,\n      ENOCSI: 111,\n      EL2HLT: 112,\n      EDEADLK: 16,\n      ENOLCK: 46,\n      EBADE: 113,\n      EBADR: 114,\n      EXFULL: 115,\n      ENOANO: 104,\n      EBADRQC: 103,\n      EBADSLT: 102,\n      EDEADLOCK: 16,\n      EBFONT: 101,\n      ENOSTR: 100,\n      ENODATA: 116,\n      ETIME: 117,\n      ENOSR: 118,\n      ENONET: 119,\n      ENOPKG: 120,\n      EREMOTE: 121,\n      ENOLINK: 47,\n      EADV: 122,\n      ESRMNT: 123,\n      ECOMM: 124,\n      EPROTO: 65,\n      EMULTIHOP: 36,\n      EDOTDOT: 125,\n      EBADMSG: 9,\n      ENOTUNIQ: 126,\n      EBADFD: 127,\n      EREMCHG: 128,\n      ELIBACC: 129,\n      ELIBBAD: 130,\n      ELIBSCN: 131,\n      ELIBMAX: 132,\n      ELIBEXEC: 133,\n      ENOSYS: 52,\n      ENOTEMPTY: 55,\n      ENAMETOOLONG: 37,\n      ELOOP: 32,\n      EOPNOTSUPP: 138,\n      EPFNOSUPPORT: 139,\n      ECONNRESET: 15,\n      ENOBUFS: 42,\n      EAFNOSUPPORT: 5,\n      EPROTOTYPE: 67,\n      ENOTSOCK: 57,\n      ENOPROTOOPT: 50,\n      ESHUTDOWN: 140,\n      ECONNREFUSED: 14,\n      EADDRINUSE: 3,\n      ECONNABORTED: 13,\n      ENETUNREACH: 40,\n      ENETDOWN: 38,\n      ETIMEDOUT: 73,\n      EHOSTDOWN: 142,\n      EHOSTUNREACH: 23,\n      EINPROGRESS: 26,\n      EALREADY: 7,\n      EDESTADDRREQ: 17,\n      EMSGSIZE: 35,\n      EPROTONOSUPPORT: 66,\n      ESOCKTNOSUPPORT: 137,\n      EADDRNOTAVAIL: 4,\n      ENETRESET: 39,\n      EISCONN: 30,\n      ENOTCONN: 53,\n      ETOOMANYREFS: 141,\n      EUSERS: 136,\n      EDQUOT: 19,\n      ESTALE: 72,\n      ENOTSUP: 138,\n      ENOMEDIUM: 148,\n      EILSEQ: 25,\n      EOVERFLOW: 61,\n      ECANCELED: 11,\n      ENOTRECOVERABLE: 56,\n      EOWNERDEAD: 62,\n      ESTRPIPE: 135,\n    }\n    var asmLibraryArg = {\n      b: ___cxa_throw,\n      d: ___syscall_fcntl64,\n      r: ___syscall_getcwd,\n      i: ___syscall_ioctl,\n      j: ___syscall_openat,\n      n: ___syscall_readlinkat,\n      o: ___syscall_stat64,\n      c: _abort,\n      f: _emscripten_memcpy_big,\n      m: _emscripten_resize_heap,\n      p: _environ_get,\n      q: _environ_sizes_get,\n      a: _exit,\n      e: _fd_close,\n      h: _fd_read,\n      k: _fd_seek,\n      g: _fd_write,\n      l: _strftime_l,\n    }\n    var asm = createWasm()\n    var ___wasm_call_ctors = (Module['___wasm_call_ctors'] = function() {\n      return (___wasm_call_ctors = Module['___wasm_call_ctors'] =\n        Module['asm']['t']).apply(null, arguments)\n    })\n    var _main = (Module['_main'] = function() {\n      return (_main = Module['_main'] = Module['asm']['u']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___errno_location = (Module['___errno_location'] = function() {\n      return (___errno_location = Module['___errno_location'] =\n        Module['asm']['v']).apply(null, arguments)\n    })\n    var _itk_wasm_input_array_alloc = (Module[\n      '_itk_wasm_input_array_alloc'\n    ] = function() {\n      return (_itk_wasm_input_array_alloc = Module[\n        '_itk_wasm_input_array_alloc'\n      ] = Module['asm']['w']).apply(null, arguments)\n    })\n    var _itk_wasm_input_json_alloc = (Module[\n      '_itk_wasm_input_json_alloc'\n    ] = function() {\n      return (_itk_wasm_input_json_alloc = Module[\n        '_itk_wasm_input_json_alloc'\n      ] = Module['asm']['x']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_address = (Module[\n      '_itk_wasm_output_json_address'\n    ] = function() {\n      return (_itk_wasm_output_json_address = Module[\n        '_itk_wasm_output_json_address'\n      ] = Module['asm']['y']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_size = (Module[\n      '_itk_wasm_output_json_size'\n    ] = function() {\n      return (_itk_wasm_output_json_size = Module[\n        '_itk_wasm_output_json_size'\n      ] = Module['asm']['z']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_address = (Module[\n      '_itk_wasm_output_array_address'\n    ] = function() {\n      return (_itk_wasm_output_array_address = Module[\n        '_itk_wasm_output_array_address'\n      ] = Module['asm']['A']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_size = (Module[\n      '_itk_wasm_output_array_size'\n    ] = function() {\n      return (_itk_wasm_output_array_size = Module[\n        '_itk_wasm_output_array_size'\n      ] = Module['asm']['B']).apply(null, arguments)\n    })\n    var _itk_wasm_free_all = (Module['_itk_wasm_free_all'] = function() {\n      return (_itk_wasm_free_all = Module['_itk_wasm_free_all'] =\n        Module['asm']['C']).apply(null, arguments)\n    })\n    var stackSave = (Module['stackSave'] = function() {\n      return (stackSave = Module['stackSave'] = Module['asm']['E']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackRestore = (Module['stackRestore'] = function() {\n      return (stackRestore = Module['stackRestore'] = Module['asm']['F']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackAlloc = (Module['stackAlloc'] = function() {\n      return (stackAlloc = Module['stackAlloc'] = Module['asm']['G']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___cxa_is_pointer_type = (Module[\n      '___cxa_is_pointer_type'\n    ] = function() {\n      return (___cxa_is_pointer_type = Module['___cxa_is_pointer_type'] =\n        Module['asm']['H']).apply(null, arguments)\n    })\n    Module['addRunDependency'] = addRunDependency\n    Module['removeRunDependency'] = removeRunDependency\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    Module['FS_unlink'] = FS.unlink\n    Module['callMain'] = callMain\n    Module['ccall'] = ccall\n    Module['cwrap'] = cwrap\n    Module['AsciiToString'] = AsciiToString\n    Module['writeArrayToMemory'] = writeArrayToMemory\n    Module['writeAsciiToMemory'] = writeAsciiToMemory\n    var calledRun\n    dependenciesFulfilled = function runCaller() {\n      if (!calledRun) run()\n      if (!calledRun) dependenciesFulfilled = runCaller\n    }\n    function callMain(args) {\n      var entryFunction = Module['_main']\n      args = args || []\n      args.unshift(thisProgram)\n      var argc = args.length\n      var argv = stackAlloc((argc + 1) * 4)\n      var argv_ptr = argv >> 2\n      args.forEach(arg => {\n        HEAP32[argv_ptr++] = allocateUTF8OnStack(arg)\n      })\n      HEAP32[argv_ptr] = 0\n      try {\n        var ret = entryFunction(argc, argv)\n        exitJS(ret, true)\n        return ret\n      } catch (e) {\n        return handleException(e)\n      }\n    }\n    function run(args) {\n      args = args || arguments_\n      if (runDependencies > 0) {\n        return\n      }\n      preRun()\n      if (runDependencies > 0) {\n        return\n      }\n      function doRun() {\n        if (calledRun) return\n        calledRun = true\n        Module['calledRun'] = true\n        if (ABORT) return\n        initRuntime()\n        preMain()\n        readyPromiseResolve(Module)\n        if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']()\n        if (shouldRunNow) callMain(args)\n        postRun()\n      }\n      if (Module['setStatus']) {\n        Module['setStatus']('Running...')\n        setTimeout(function() {\n          setTimeout(function() {\n            Module['setStatus']('')\n          }, 1)\n          doRun()\n        }, 1)\n      } else {\n        doRun()\n      }\n    }\n    if (Module['preInit']) {\n      if (typeof Module['preInit'] == 'function')\n        Module['preInit'] = [Module['preInit']]\n      while (Module['preInit'].length > 0) {\n        Module['preInit'].pop()()\n      }\n    }\n    var shouldRunNow = false\n    if (Module['noInitialRun']) shouldRunNow = false\n    run()\n    Module.mountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      if (FS.isDir(containingDir) || containingDir === '/') {\n        return\n      }\n      var currentDir = '/'\n      var splitContainingDir = containingDir.split(path.sep)\n      for (var ii = 1; ii < splitContainingDir.length; ii++) {\n        currentDir += splitContainingDir[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n      FS.mount(NODEFS, { root: containingDir }, currentDir)\n      return currentDir + path.basename(filePath)\n    }\n    Module.unmountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      FS.unmount(containingDir)\n    }\n    Module.fs_mkdirs = function(dirs) {\n      var currentDir = '/'\n      var splitDirs = dirs.split('/')\n      for (var ii = 1; ii < splitDirs.length; ++ii) {\n        currentDir += splitDirs[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n    }\n    Module.fs_readFile = function(path, opts) {\n      return FS.readFile(path, opts)\n    }\n    Module.fs_writeFile = function(path, data, opts) {\n      return FS.writeFile(path, data, opts)\n    }\n    Module.fs_unlink = function(path) {\n      return FS.unlink(path)\n    }\n    Module.fs_open = function(path, flags, mode) {\n      return FS.open(path, flags, mode)\n    }\n    Module.fs_stat = function(path) {\n      return FS.stat(path)\n    }\n    Module.fs_read = function(stream, buffer, offset, length, position) {\n      return FS.read(stream, buffer, offset, length, position)\n    }\n    Module.fs_close = function(stream) {\n      return FS.close(stream)\n    }\n\n    return Compare.ready\n  }\n})()\nif (typeof exports === 'object' && typeof module === 'object')\n  module.exports = Compare\nelse if (typeof define === 'function' && define['amd'])\n  define([], function() {\n    return Compare\n  })\nelse if (typeof exports === 'object') exports['Compare'] = Compare\n"
  },
  {
    "path": "src/IO/Compare/index.mjs",
    "content": "#!/usr/bin/env node\n/* eslint-env node */\n\nimport { Command } from 'commander/esm.mjs'\nimport path from 'path'\n\nconst program = new Command()\n\nimport {\n  readLocalFile,\n  writeLocalFile,\n  runPipelineNode,\n  InterfaceTypes,\n} from 'itk-wasm'\n\nprogram\n  .description('Create checkerboard from 2 images')\n  .arguments('<inputFile1> <inputFile2> <outputFile> <boxes>')\n  .parse(process.argv)\n\nif (program.args.length < 3) {\n  console.error('Please pass in 2 input file paths and output file path.')\n  process.exit(1)\n}\n\nconst pipelinePath = path.resolve('./emscripten-build/Compare')\nconst inputFile1 = program.args[0]\nconst inputFile2 = program.args[1]\nconst outputFile = program.args[2]\nconst boxes = program.args[3]\n\ntry {\n  const inputImage1 = await readLocalFile(inputFile1)\n  const inputImage2 = await readLocalFile(inputFile2)\n\n  const inputs = [\n    {\n      type: InterfaceTypes.Image,\n      data: inputImage1,\n    },\n    {\n      type: InterfaceTypes.Image,\n      data: inputImage2,\n    },\n  ]\n  const desiredOutputs = [{ type: InterfaceTypes.Image }]\n\n  const args = [\n    '0',\n    '1',\n    '0',\n    '--boxes',\n    boxes,\n    // '--max-total-splits',\n    // '10',\n    // '--split',\n    // '5',\n    '--memory-io',\n  ]\n  const { outputs } = await runPipelineNode(\n    pipelinePath,\n    args,\n    desiredOutputs,\n    inputs\n  )\n\n  const outputImage = outputs[0].data\n\n  await writeLocalFile(outputImage, outputFile)\n} catch (error) {\n  console.error('Error during processing:\\n')\n  console.error(error)\n}\n"
  },
  {
    "path": "src/IO/Compare/package.json",
    "content": "{\n  \"name\": \"checkerboard-itk-wasm\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"itk-wasm -i itkwasm/emscripten:latest build\",\n    \"build:debug\": \"itk-wasm -i itkwasm/emscripten:latest-debug build -- -DCMAKE_BUILD_TYPE=Debug\",\n    \"test\": \"node index.mjs ../Downsample/cthead1.png ../Downsample/cthead1-bin.png output.png 5,8\"\n  },\n  \"author\": \"\",\n  \"license\": \"Apache-2.0\",\n  \"dependencies\": {\n    \"itk-image-io\": \"^1.0.0-b.84\",\n    \"itk-wasm\": \"^1.0.0-b.84\"\n  }\n}\n"
  },
  {
    "path": "src/IO/ConglomerateMultiscaleSpatialImage.js",
    "content": "import MultiscaleSpatialImage from './MultiscaleSpatialImage'\n\nexport class ConglomerateMultiscaleSpatialImage extends MultiscaleSpatialImage {\n  constructor(images) {\n    const { scaleInfo, imageType } = images.slice(1).reduce(\n      (fused, { scaleInfo, imageType }) => ({\n        imageType: {\n          ...imageType,\n          components: fused.imageType.components + imageType.components,\n        },\n        scaleInfo: fused.scaleInfo.map((scale, scaleIdx) => ({\n          ...scale,\n          ranges: scale.ranges\n            ? [...scale.ranges, ...scaleInfo[scaleIdx].ranges]\n            : scale.ranges, // ranges may be undefined\n        })),\n      }),\n      images[0]\n    )\n    super(scaleInfo, imageType)\n    this.images = images\n  }\n\n  async getImage(scale, worldBounds = []) {\n    this.worldBoundsForBuildImage = worldBounds\n    return super.getImage(scale, worldBounds)\n  }\n\n  async buildImage(scale /*bounds*/) {\n    // Run sequentially rather than Promise.all to avoid hang during chunk fetching\n    const builtImages = []\n    for (const image of this.images) {\n      builtImages.push(\n        await image.getImage(scale, this.worldBoundsForBuildImage)\n      )\n    }\n    return builtImages\n  }\n}\n"
  },
  {
    "path": "src/IO/Downsample/.gitignore",
    "content": "/emscripten-build/*\n!emscripten-build/Downsample*\nresample.png"
  },
  {
    "path": "src/IO/Downsample/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\nproject(Downsample)\n\nset(CMAKE_CXX_STANDARD 17)\n\nset(io_components)\nif (NOT EMSCRIPTEN AND NOT WASI)\n  set(io_components\n    ITKIOPNG\n    ITKIOMeta\n    ITKIONRRD\n    )\nendif()\nfind_package(ITK REQUIRED\n  COMPONENTS\n    ${io_components}\n    WebAssemblyInterface\n    ITKImageGrid\n    ITKImageFunction\n    GenericLabelInterpolator\n  )\ninclude(${ITK_USE_FILE})\n\nadd_executable(Downsample Downsample.cxx)\ntarget_link_libraries(Downsample PUBLIC ${ITK_LIBRARIES})\n\nadd_executable(DownsampleLabelImage DownsampleLabelImage.cxx)\ntarget_link_libraries(DownsampleLabelImage PUBLIC ${ITK_LIBRARIES})\n\nenable_testing()\nadd_test(NAME DownsampleTest\n  COMMAND Downsample\n    ${CMAKE_CURRENT_SOURCE_DIR}/cthead1.png\n    ${CMAKE_CURRENT_BINARY_DIR}/cthead1.shrink.png\n    2,2\n  )\n\nadd_test(NAME DownsampleTestLabelImage\n  COMMAND DownsampleLabelImage\n    ${CMAKE_CURRENT_SOURCE_DIR}/cthead1-bin.png\n    ${CMAKE_CURRENT_BINARY_DIR}/cthead1Label.shrink.png\n    2,2\n  )\n"
  },
  {
    "path": "src/IO/Downsample/Downsample.cxx",
    "content": "/*=========================================================================\n *\n *  Copyright NumFOCUS\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *         http://www.apache.org/licenses/LICENSE-2.0.txt\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n *=========================================================================*/\n#include \"itkBinShrinkImageFilter.h\"\n#include \"itkVectorImage.h\"\n#include \"itkResampleImageFilter.h\"\n#include \"itkLabelImageGaussianInterpolateImageFunction.h\"\n#include \"itkImageRegionSplitterSlowDimension.h\"\n#include \"itkExtractImageFilter.h\"\n#include \"itkRGBPixel.h\"\n#include \"itkRGBAPixel.h\"\n#include \"itkVectorImage.h\"\n#include \"itkOffset.h\"\n#include \"itkVector.h\"\n#include \"itkPoint.h\"\n#include \"itkCovariantVector.h\"\n#include \"itkSymmetricSecondRankTensor.h\"\n#include \"itkDiffusionTensor3D.h\"\n#include <complex>\n#include \"itkFixedArray.h\"\n#include \"itkArray.h\"\n#include \"itkMatrix.h\"\n#include \"itkVariableLengthVector.h\"\n#include \"itkVariableSizeMatrix.h\"\n#include <fstream>\n#include \"itkPipeline.h\"\n#include \"itkInputImage.h\"\n#include \"itkOutputImage.h\"\n#include \"itkSupportInputImageTypes.h\"\n#include \"itkOutputTextStream.h\"\n\ntemplate <typename TImage>\nint Downsample(itk::wasm::Pipeline &pipeline, itk::wasm::InputImage<TImage> &inputImage)\n{\n  using ImageType = TImage;\n\n  pipeline.get_option(\"InputImage\")->required();\n\n  using OutputImageType = itk::wasm::OutputImage<ImageType>;\n  OutputImageType outputImage;\n  pipeline.add_option(\"OutputImage\", outputImage, \"Output image\")->required();\n\n  std::vector<unsigned int> factors;\n  pipeline.add_option(\"DownsampleFactors\", factors, \"Downsampling factors for each direction\")->expected(2, 3)->delimiter(',');\n\n  unsigned int maxTotalSplits = 1;\n  pipeline.add_option(\"-m,--max-total-splits\", maxTotalSplits, \"Maximum total splits when processed in parallel\");\n\n  unsigned int split = 0;\n  pipeline.add_option(\"-s,--split\", split, \"Current processed split\");\n\n  itk::wasm::OutputTextStream numberOfSplitsStream;\n  auto numberOfSplitsStreamOption = pipeline.add_option(\"--number-of-splits\", numberOfSplitsStream, \"Number of splits\");\n\n  ITK_WASM_PARSE(pipeline);\n\n  using FilterType = itk::BinShrinkImageFilter<ImageType, ImageType>;\n  auto filter = FilterType::New();\n  filter->SetInput(inputImage.Get());\n  filter->SetShrinkFactor(0, factors[0]);\n  filter->SetShrinkFactor(1, factors[1]);\n  if (ImageType::ImageDimension > 2)\n  {\n    filter->SetShrinkFactor(2, factors[2]);\n  }\n\n  using ResampleFilterType = itk::ResampleImageFilter<ImageType, ImageType>;\n  auto resampleFilter = ResampleFilterType::New();\n  resampleFilter->SetInput(inputImage.Get());\n\n  filter->UpdateOutputInformation();\n  using ROIFilterType = itk::ExtractImageFilter<ImageType, ImageType>;\n  auto roiFilter = ROIFilterType::New();\n  using RegionType = typename ImageType::RegionType;\n  const RegionType largestRegion(filter->GetOutput()->GetLargestPossibleRegion());\n\n  using SplitterType = itk::ImageRegionSplitterSlowDimension;\n  auto splitter = SplitterType::New();\n  const unsigned int numberOfSplits = splitter->GetNumberOfSplits(largestRegion, maxTotalSplits);\n\n  if (split >= numberOfSplits)\n  {\n    std::cerr << \"Error: requested split: \" << split << \" is outside the number of splits: \" << numberOfSplits << std::endl;\n    return EXIT_FAILURE;\n  }\n\n  if (!numberOfSplitsStreamOption->empty())\n  {\n    numberOfSplitsStream.Get() << numberOfSplits;\n  }\n\n  RegionType requestedRegion(largestRegion);\n  splitter->GetSplit(split, numberOfSplits, requestedRegion);\n  roiFilter->SetExtractionRegion(requestedRegion);\n  roiFilter->SetInput(filter->GetOutput());\n\n  ITK_WASM_CATCH_EXCEPTION(pipeline, roiFilter->Update());\n\n  auto result = roiFilter->GetOutput();\n  outputImage.Set(result);\n\n  return EXIT_SUCCESS;\n}\n\ntemplate <typename TImage>\nclass PipelineFunctor\n{\npublic:\n  int operator()(itk::wasm::Pipeline &pipeline)\n  {\n    using ImageType = TImage;\n\n    using InputImageType = itk::wasm::InputImage<ImageType>;\n    InputImageType inputImage;\n    pipeline.add_option(\"InputImage\", inputImage, \"Input image\");\n\n    ITK_WASM_PRE_PARSE(pipeline);\n\n    return Downsample<ImageType>(pipeline, inputImage);\n  }\n};\n\nint main(int argc, char *argv[])\n{\n  itk::wasm::Pipeline pipeline(\"Downsample\", \"Downsample an image\", argc, argv);\n\n  return itk::wasm::SupportInputImageTypes<PipelineFunctor,\n                                           uint8_t,\n                                           int8_t,\n                                           uint16_t,\n                                           int16_t,\n                                           uint32_t,\n                                           int32_t,\n                                           uint64_t,\n                                           int64_t,\n                                           float,\n                                           double,\n                                           itk::RGBPixel<uint8_t>,\n                                           itk::RGBAPixel<uint8_t>,\n                                           itk::VariableLengthVector<uint8_t>,\n                                           itk::VariableLengthVector<int8_t>,\n                                           itk::VariableLengthVector<uint16_t>,\n                                           itk::VariableLengthVector<int16_t>,\n                                           itk::VariableLengthVector<uint32_t>,\n                                           itk::VariableLengthVector<int32_t>,\n                                           itk::VariableLengthVector<uint64_t>,\n                                           itk::VariableLengthVector<int64_t>,\n                                           itk::VariableLengthVector<float>,\n                                           itk::VariableLengthVector<double>,\n                                           itk::Vector<float, 2>,\n                                           itk::Vector<double, 2>,\n                                           itk::Vector<float, 3>,\n                                           itk::Vector<double, 3>,\n                                           itk::Vector<uint8_t, 3>,\n                                           itk::Vector<uint8_t, 3>,\n                                           itk::Vector<uint8_t, 4>,\n                                           itk::Vector<uint8_t, 4>,\n                                           itk::CovariantVector<float, 2>,\n                                           itk::CovariantVector<double, 2>,\n                                           itk::CovariantVector<float, 3>,\n                                           itk::CovariantVector<double, 3>>::Dimensions<2U, 3U>(\"InputImage\", pipeline);\n}\n"
  },
  {
    "path": "src/IO/Downsample/DownsampleLabelImage.cxx",
    "content": "/*=========================================================================\n *\n *  Copyright NumFOCUS\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *         http://www.apache.org/licenses/LICENSE-2.0.txt\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n *=========================================================================*/\n#include \"itkBinShrinkImageFilter.h\"\n#include \"itkVectorImage.h\"\n#include \"itkResampleImageFilter.h\"\n#include \"itkLabelImageGenericInterpolateImageFunction.h\"\n#include \"itkLinearInterpolateImageFunction.h\"\n#include \"itkImageRegionSplitterSlowDimension.h\"\n#include \"itkExtractImageFilter.h\"\n#include \"itkRGBPixel.h\"\n#include \"itkRGBAPixel.h\"\n#include \"itkVectorImage.h\"\n#include \"itkOffset.h\"\n#include \"itkVector.h\"\n#include \"itkPoint.h\"\n#include \"itkCovariantVector.h\"\n#include \"itkSymmetricSecondRankTensor.h\"\n#include \"itkDiffusionTensor3D.h\"\n#include <complex>\n#include \"itkFixedArray.h\"\n#include \"itkArray.h\"\n#include \"itkMatrix.h\"\n#include \"itkVariableLengthVector.h\"\n#include \"itkVariableSizeMatrix.h\"\n#include <fstream>\n#include \"itkPipeline.h\"\n#include \"itkInputImage.h\"\n#include \"itkOutputImage.h\"\n#include \"itkSupportInputImageTypes.h\"\n#include \"itkOutputTextStream.h\"\n\ntemplate <typename TImage>\nint DownsampleLabelImage(itk::wasm::Pipeline &pipeline, itk::wasm::InputImage<TImage> &inputImage)\n{\n  using ImageType = TImage;\n\n  pipeline.get_option(\"InputImage\")->required();\n\n  using OutputImageType = itk::wasm::OutputImage<ImageType>;\n  OutputImageType outputImage;\n  pipeline.add_option(\"OutputImage\", outputImage, \"Output image\")->required();\n\n  std::vector<unsigned int> factors;\n  pipeline.add_option(\"DownsampleFactors\", factors, \"Downsampling factors for each direction\")->expected(2, 3)->delimiter(',');\n\n  unsigned int maxTotalSplits = 1;\n  pipeline.add_option(\"-m,--max-total-splits\", maxTotalSplits, \"Maximum total splits when processed in parallel\");\n\n  unsigned int split = 0;\n  pipeline.add_option(\"-s,--split\", split, \"Current processed split\");\n\n  itk::wasm::OutputTextStream numberOfSplitsStream;\n  auto numberOfSplitsStreamOption = pipeline.add_option(\"--number-of-splits\", numberOfSplitsStream, \"Number of splits\");\n\n  ITK_WASM_PARSE(pipeline);\n\n  using FilterType = itk::BinShrinkImageFilter<ImageType, ImageType>;\n  auto filter = FilterType::New();\n  filter->SetInput(inputImage.Get());\n  filter->SetShrinkFactor(0, factors[0]);\n  filter->SetShrinkFactor(1, factors[1]);\n  if (ImageType::ImageDimension > 2)\n  {\n    filter->SetShrinkFactor(2, factors[2]);\n  }\n\n  using ResampleFilterType = itk::ResampleImageFilter<ImageType, ImageType>;\n  auto resampleFilter = ResampleFilterType::New();\n  resampleFilter->SetInput(inputImage.Get());\n\n  filter->UpdateOutputInformation();\n  using ROIFilterType = itk::ExtractImageFilter<ImageType, ImageType>;\n  auto roiFilter = ROIFilterType::New();\n  using RegionType = typename ImageType::RegionType;\n  const RegionType largestRegion(filter->GetOutput()->GetLargestPossibleRegion());\n\n  using SplitterType = itk::ImageRegionSplitterSlowDimension;\n  auto splitter = SplitterType::New();\n  const unsigned int numberOfSplits = splitter->GetNumberOfSplits(largestRegion, maxTotalSplits);\n\n  if (split >= numberOfSplits)\n  {\n    std::cerr << \"Error: requested split: \" << split << \" is outside the number of splits: \" << numberOfSplits << std::endl;\n    return EXIT_FAILURE;\n  }\n\n  if (!numberOfSplitsStreamOption->empty())\n  {\n    numberOfSplitsStream.Get() << numberOfSplits;\n  }\n\n  RegionType requestedRegion(largestRegion);\n  splitter->GetSplit(split, numberOfSplits, requestedRegion);\n  roiFilter->SetExtractionRegion(requestedRegion);\n\n  roiFilter->SetInput(resampleFilter->GetOutput());\n  const ImageType *shrunk = filter->GetOutput();\n  resampleFilter->SetSize(shrunk->GetLargestPossibleRegion().GetSize());\n  resampleFilter->SetOutputOrigin(shrunk->GetOrigin());\n  auto spacing = shrunk->GetSpacing();\n  resampleFilter->SetOutputSpacing(spacing);\n  resampleFilter->SetOutputDirection(shrunk->GetDirection());\n  using CoordRepType = double;\n  using InterpolatorType = itk::LabelImageGenericInterpolateImageFunction<ImageType, itk::LinearInterpolateImageFunction>;\n  auto interpolator = InterpolatorType::New();\n  resampleFilter->SetInterpolator(interpolator);\n\n  try\n  {\n    roiFilter->Update();\n  }\n  catch (std::exception &error)\n  {\n    std::cerr << \"Error: \" << error.what() << std::endl;\n    return EXIT_FAILURE;\n  }\n\n  outputImage.Set(roiFilter->GetOutput());\n\n  return EXIT_SUCCESS;\n}\n\ntemplate <typename TImage>\nclass PipelineFunctor\n{\npublic:\n  int operator()(itk::wasm::Pipeline &pipeline)\n  {\n    using ImageType = TImage;\n\n    using InputImageType = itk::wasm::InputImage<ImageType>;\n    InputImageType inputImage;\n    pipeline.add_option(\"InputImage\", inputImage, \"Input image\");\n\n    ITK_WASM_PRE_PARSE(pipeline);\n\n    return DownsampleLabelImage<ImageType>(pipeline, inputImage);\n  }\n};\n\nint main(int argc, char *argv[])\n{\n  itk::wasm::Pipeline pipeline(\"DownsampleLabel\", \"Downsample a label image\", argc, argv);\n\n  return itk::wasm::SupportInputImageTypes<PipelineFunctor,\n                                           uint8_t,\n                                           int8_t,\n                                           uint16_t,\n                                           int16_t,\n                                           uint32_t,\n                                           int32_t,\n                                           uint64_t,\n                                           int64_t,\n                                           float,\n                                           double>::Dimensions<2U, 3U>(\"InputImage\", pipeline);\n}\n"
  },
  {
    "path": "src/IO/Downsample/cypress/integration/load_data_spec.js",
    "content": "describe('Downsample images', () => {\n  it('successfully downsamples an image', () => {\n    cy.visit('http://localhost:8080/')\n    cy.readFile('cthead1.png', null).then(headBuffer => {\n      cy.get('input[type=file]').selectFile({\n        contents: headBuffer,\n        fileName: 'cthead1.png',\n      })\n      cy.get('textarea').contains('\"imageType\"')\n    })\n  })\n\n  it('successfully downsamples a label image', () => {\n    cy.visit('http://localhost:8080/')\n    cy.readFile('cthead1-bin.png', null).then(headBuffer => {\n      cy.get('input[type=checkbox]').check()\n      cy.get('input[type=file]').selectFile({\n        contents: headBuffer,\n        fileName: 'cthead1-bin.png',\n      })\n      cy.get('textarea').contains('\"imageType\"')\n    })\n  })\n})\n"
  },
  {
    "path": "src/IO/Downsample/cypress/plugins/index.cjs",
    "content": "/// <reference types=\"cypress\" />\n// ***********************************************************\n// This example plugins/index.js can be used to load plugins\n//\n// You can change the location of this file or turn off loading\n// the plugins file with the 'pluginsFile' configuration option.\n//\n// You can read more here:\n// https://on.cypress.io/plugins-guide\n// ***********************************************************\n\n// This function is called when a project is opened or re-opened (e.g. due to\n// the project's config changing)\n\n/**\n * @type {Cypress.PluginConfig}\n */\n// eslint-disable-next-line no-unused-vars\nmodule.exports = (on, config) => {\n  // `on` is used to hook into various events Cypress emits\n  // `config` is the resolved Cypress config\n}\n"
  },
  {
    "path": "src/IO/Downsample/cypress.json",
    "content": "{}\n"
  },
  {
    "path": "src/IO/Downsample/downsample.js",
    "content": "#!/usr/bin/env node\n\nimport { Command } from 'commander/esm.mjs'\nimport path from 'path'\n\nconst program = new Command()\n\nimport {\n  readLocalFile,\n  writeLocalFile,\n  runPipelineNode,\n  InterfaceTypes,\n} from 'itk-wasm'\n\nprogram\n  .description('Downsample an image')\n  .option(\n    '-l, --label-image',\n    'Downsample as a label image as opposed to an intensity image'\n  )\n  .arguments('<inputFile> <outputFile>')\n  .parse(process.argv)\n\nif (program.args.length < 2) {\n  console.error('Please pass in both the input and output file paths.')\n  process.exit(1)\n}\n\nconst inputFile = program.args[0]\nconst outputFile = program.args[1]\nconst pipelinePath = program.options.labelImage\n  ? path.resolve('./emscripten-build/DownsampleLabelImage')\n  : path.resolve('./emscripten-build/Downsample')\nconsole.log(pipelinePath)\n\nconst factors = [2, 2, 2]\n\ntry {\n  const inputImage = await readLocalFile(inputFile)\n\n  const inputs = [\n    {\n      type: InterfaceTypes.Image,\n      data: inputImage,\n    },\n  ]\n  const desiredOutputs = [\n    { type: InterfaceTypes.Image },\n    // { type: InterfaceTypes.TextStream },\n  ]\n  const args = [\n    '0',\n    '0',\n    factors.join(','),\n    // '--max-total-splits', '' + maxTotalSplits,\n    // '--split', '' + index,\n    // '--number-of-splits', '1',\n    '--memory-io',\n  ]\n  const { stdout, stderr, outputs } = await runPipelineNode(\n    pipelinePath,\n    args,\n    desiredOutputs,\n    inputs\n  )\n\n  const outputImage = outputs[0].data\n\n  await writeLocalFile(outputImage, outputFile)\n} catch (error) {\n  console.error('Error during processing:\\n')\n  console.error(error)\n}\n"
  },
  {
    "path": "src/IO/Downsample/emscripten-build/Downsample.js",
    "content": "var Downsample = (() => {\n  var _scriptDir = import.meta.url\n\n  return async function(Downsample) {\n    Downsample = Downsample || {}\n\n    var Module = typeof Downsample != 'undefined' ? Downsample : {}\n    var readyPromiseResolve, readyPromiseReject\n    Module['ready'] = new Promise(function(resolve, reject) {\n      readyPromiseResolve = resolve\n      readyPromiseReject = reject\n    })\n    var mStdout = null\n    var mStderr = null\n    Module['resetModuleStdout'] = function() {\n      mStdout = ''\n    }\n    Module['resetModuleStderr'] = function() {\n      mStderr = ''\n    }\n    Module['print'] = function(text) {\n      console.log(text)\n      mStdout += text + '\\n'\n    }\n    Module['printErr'] = function(text) {\n      console.error(text)\n      mStderr += text + '\\n'\n    }\n    Module['getModuleStdout'] = function() {\n      return mStdout\n    }\n    Module['getModuleStderr'] = function() {\n      return mStderr\n    }\n    var moduleOverrides = Object.assign({}, Module)\n    var arguments_ = []\n    var thisProgram = './this.program'\n    var quit_ = (status, toThrow) => {\n      throw toThrow\n    }\n    var ENVIRONMENT_IS_WEB = typeof window == 'object'\n    var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'\n    var ENVIRONMENT_IS_NODE =\n      typeof process == 'object' &&\n      typeof process.versions == 'object' &&\n      typeof process.versions.node == 'string'\n    var scriptDirectory = ''\n    function locateFile(path) {\n      if (Module['locateFile']) {\n        return Module['locateFile'](path, scriptDirectory)\n      }\n      return scriptDirectory + path\n    }\n    var read_, readAsync, readBinary, setWindowTitle\n    function logExceptionOnExit(e) {\n      if (e instanceof ExitStatus) return\n      let toLog = e\n      err('exiting due to exception: ' + toLog)\n    }\n    if (ENVIRONMENT_IS_NODE) {\n      const { createRequire: createRequire } = await import('module')\n      var require = createRequire(import.meta.url)\n      var fs = require('fs')\n      var nodePath = require('path')\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = nodePath.dirname(scriptDirectory) + '/'\n      } else {\n        scriptDirectory = require('url').fileURLToPath(\n          new URL('./', import.meta.url)\n        )\n      }\n      read_ = (filename, binary) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        return fs.readFileSync(filename, binary ? undefined : 'utf8')\n      }\n      readBinary = filename => {\n        var ret = read_(filename, true)\n        if (!ret.buffer) {\n          ret = new Uint8Array(ret)\n        }\n        return ret\n      }\n      readAsync = (filename, onload, onerror) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        fs.readFile(filename, function(err, data) {\n          if (err) onerror(err)\n          else onload(data.buffer)\n        })\n      }\n      if (process['argv'].length > 1) {\n        thisProgram = process['argv'][1].replace(/\\\\/g, '/')\n      }\n      arguments_ = process['argv'].slice(2)\n      process['on']('uncaughtException', function(ex) {\n        if (!(ex instanceof ExitStatus)) {\n          throw ex\n        }\n      })\n      process['on']('unhandledRejection', function(reason) {\n        throw reason\n      })\n      quit_ = (status, toThrow) => {\n        if (keepRuntimeAlive()) {\n          process['exitCode'] = status\n          throw toThrow\n        }\n        logExceptionOnExit(toThrow)\n        process['exit'](status)\n      }\n      Module['inspect'] = function() {\n        return '[Emscripten Module object]'\n      }\n    } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = self.location.href\n      } else if (typeof document != 'undefined' && document.currentScript) {\n        scriptDirectory = document.currentScript.src\n      }\n      if (_scriptDir) {\n        scriptDirectory = _scriptDir\n      }\n      if (scriptDirectory.indexOf('blob:') !== 0) {\n        scriptDirectory = scriptDirectory.substr(\n          0,\n          scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1\n        )\n      } else {\n        scriptDirectory = ''\n      }\n      {\n        read_ = url => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, false)\n          xhr.send(null)\n          return xhr.responseText\n        }\n        if (ENVIRONMENT_IS_WORKER) {\n          readBinary = url => {\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            xhr.responseType = 'arraybuffer'\n            xhr.send(null)\n            return new Uint8Array(xhr.response)\n          }\n        }\n        readAsync = (url, onload, onerror) => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, true)\n          xhr.responseType = 'arraybuffer'\n          xhr.onload = () => {\n            if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n              onload(xhr.response)\n              return\n            }\n            onerror()\n          }\n          xhr.onerror = onerror\n          xhr.send(null)\n        }\n      }\n      setWindowTitle = title => (document.title = title)\n    } else {\n    }\n    var out = Module['print'] || console.log.bind(console)\n    var err = Module['printErr'] || console.warn.bind(console)\n    Object.assign(Module, moduleOverrides)\n    moduleOverrides = null\n    if (Module['arguments']) arguments_ = Module['arguments']\n    if (Module['thisProgram']) thisProgram = Module['thisProgram']\n    if (Module['quit']) quit_ = Module['quit']\n    var wasmBinary\n    if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']\n    var noExitRuntime = Module['noExitRuntime'] || true\n    if (typeof WebAssembly != 'object') {\n      abort('no native wasm support detected')\n    }\n    var wasmMemory\n    var ABORT = false\n    var EXITSTATUS\n    function assert(condition, text) {\n      if (!condition) {\n        abort(text)\n      }\n    }\n    var UTF8Decoder =\n      typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined\n    function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {\n      var endIdx = idx + maxBytesToRead\n      var endPtr = idx\n      while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr\n      if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {\n        return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr))\n      }\n      var str = ''\n      while (idx < endPtr) {\n        var u0 = heapOrArray[idx++]\n        if (!(u0 & 128)) {\n          str += String.fromCharCode(u0)\n          continue\n        }\n        var u1 = heapOrArray[idx++] & 63\n        if ((u0 & 224) == 192) {\n          str += String.fromCharCode(((u0 & 31) << 6) | u1)\n          continue\n        }\n        var u2 = heapOrArray[idx++] & 63\n        if ((u0 & 240) == 224) {\n          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2\n        } else {\n          u0 =\n            ((u0 & 7) << 18) |\n            (u1 << 12) |\n            (u2 << 6) |\n            (heapOrArray[idx++] & 63)\n        }\n        if (u0 < 65536) {\n          str += String.fromCharCode(u0)\n        } else {\n          var ch = u0 - 65536\n          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023))\n        }\n      }\n      return str\n    }\n    function UTF8ToString(ptr, maxBytesToRead) {\n      return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''\n    }\n    function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {\n      if (!(maxBytesToWrite > 0)) return 0\n      var startIdx = outIdx\n      var endIdx = outIdx + maxBytesToWrite - 1\n      for (var i = 0; i < str.length; ++i) {\n        var u = str.charCodeAt(i)\n        if (u >= 55296 && u <= 57343) {\n          var u1 = str.charCodeAt(++i)\n          u = (65536 + ((u & 1023) << 10)) | (u1 & 1023)\n        }\n        if (u <= 127) {\n          if (outIdx >= endIdx) break\n          heap[outIdx++] = u\n        } else if (u <= 2047) {\n          if (outIdx + 1 >= endIdx) break\n          heap[outIdx++] = 192 | (u >> 6)\n          heap[outIdx++] = 128 | (u & 63)\n        } else if (u <= 65535) {\n          if (outIdx + 2 >= endIdx) break\n          heap[outIdx++] = 224 | (u >> 12)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        } else {\n          if (outIdx + 3 >= endIdx) break\n          heap[outIdx++] = 240 | (u >> 18)\n          heap[outIdx++] = 128 | ((u >> 12) & 63)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        }\n      }\n      heap[outIdx] = 0\n      return outIdx - startIdx\n    }\n    function stringToUTF8(str, outPtr, maxBytesToWrite) {\n      return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite)\n    }\n    function lengthBytesUTF8(str) {\n      var len = 0\n      for (var i = 0; i < str.length; ++i) {\n        var c = str.charCodeAt(i)\n        if (c <= 127) {\n          len++\n        } else if (c <= 2047) {\n          len += 2\n        } else if (c >= 55296 && c <= 57343) {\n          len += 4\n          ++i\n        } else {\n          len += 3\n        }\n      }\n      return len\n    }\n    var buffer,\n      HEAP8,\n      HEAPU8,\n      HEAP16,\n      HEAPU16,\n      HEAP32,\n      HEAPU32,\n      HEAPF32,\n      HEAPF64\n    function updateGlobalBufferAndViews(buf) {\n      buffer = buf\n      Module['HEAP8'] = HEAP8 = new Int8Array(buf)\n      Module['HEAP16'] = HEAP16 = new Int16Array(buf)\n      Module['HEAP32'] = HEAP32 = new Int32Array(buf)\n      Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf)\n      Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf)\n      Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf)\n      Module['HEAPF32'] = HEAPF32 = new Float32Array(buf)\n      Module['HEAPF64'] = HEAPF64 = new Float64Array(buf)\n    }\n    var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216\n    var wasmTable\n    var __ATPRERUN__ = []\n    var __ATINIT__ = []\n    var __ATMAIN__ = []\n    var __ATPOSTRUN__ = []\n    var runtimeInitialized = false\n    function keepRuntimeAlive() {\n      return noExitRuntime\n    }\n    function preRun() {\n      if (Module['preRun']) {\n        if (typeof Module['preRun'] == 'function')\n          Module['preRun'] = [Module['preRun']]\n        while (Module['preRun'].length) {\n          addOnPreRun(Module['preRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPRERUN__)\n    }\n    function initRuntime() {\n      runtimeInitialized = true\n      if (!Module['noFSInit'] && !FS.init.initialized) FS.init()\n      FS.ignorePermissions = false\n      TTY.init()\n      callRuntimeCallbacks(__ATINIT__)\n    }\n    function preMain() {\n      callRuntimeCallbacks(__ATMAIN__)\n    }\n    function postRun() {\n      if (Module['postRun']) {\n        if (typeof Module['postRun'] == 'function')\n          Module['postRun'] = [Module['postRun']]\n        while (Module['postRun'].length) {\n          addOnPostRun(Module['postRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPOSTRUN__)\n    }\n    function addOnPreRun(cb) {\n      __ATPRERUN__.unshift(cb)\n    }\n    function addOnInit(cb) {\n      __ATINIT__.unshift(cb)\n    }\n    function addOnPostRun(cb) {\n      __ATPOSTRUN__.unshift(cb)\n    }\n    var runDependencies = 0\n    var runDependencyWatcher = null\n    var dependenciesFulfilled = null\n    function getUniqueRunDependency(id) {\n      return id\n    }\n    function addRunDependency(id) {\n      runDependencies++\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n    }\n    function removeRunDependency(id) {\n      runDependencies--\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n      if (runDependencies == 0) {\n        if (runDependencyWatcher !== null) {\n          clearInterval(runDependencyWatcher)\n          runDependencyWatcher = null\n        }\n        if (dependenciesFulfilled) {\n          var callback = dependenciesFulfilled\n          dependenciesFulfilled = null\n          callback()\n        }\n      }\n    }\n    function abort(what) {\n      if (Module['onAbort']) {\n        Module['onAbort'](what)\n      }\n      what = 'Aborted(' + what + ')'\n      err(what)\n      ABORT = true\n      EXITSTATUS = 1\n      what += '. Build with -sASSERTIONS for more info.'\n      var e = new WebAssembly.RuntimeError(what)\n      readyPromiseReject(e)\n      throw e\n    }\n    var dataURIPrefix = 'data:application/octet-stream;base64,'\n    function isDataURI(filename) {\n      return filename.startsWith(dataURIPrefix)\n    }\n    function isFileURI(filename) {\n      return filename.startsWith('file://')\n    }\n    var wasmBinaryFile\n    if (Module['locateFile']) {\n      wasmBinaryFile = 'Downsample.wasm'\n      if (!isDataURI(wasmBinaryFile)) {\n        wasmBinaryFile = locateFile(wasmBinaryFile)\n      }\n    } else {\n      wasmBinaryFile = new URL('Downsample.wasm', import.meta.url).href\n    }\n    function getBinary(file) {\n      try {\n        if (file == wasmBinaryFile && wasmBinary) {\n          return new Uint8Array(wasmBinary)\n        }\n        if (readBinary) {\n          return readBinary(file)\n        }\n        throw 'both async and sync fetching of the wasm failed'\n      } catch (err) {\n        abort(err)\n      }\n    }\n    function getBinaryPromise() {\n      if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {\n        if (typeof fetch == 'function' && !isFileURI(wasmBinaryFile)) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' })\n            .then(function(response) {\n              if (!response['ok']) {\n                throw \"failed to load wasm binary file at '\" +\n                  wasmBinaryFile +\n                  \"'\"\n              }\n              return response['arrayBuffer']()\n            })\n            .catch(function() {\n              return getBinary(wasmBinaryFile)\n            })\n        } else {\n          if (readAsync) {\n            return new Promise(function(resolve, reject) {\n              readAsync(\n                wasmBinaryFile,\n                function(response) {\n                  resolve(new Uint8Array(response))\n                },\n                reject\n              )\n            })\n          }\n        }\n      }\n      return Promise.resolve().then(function() {\n        return getBinary(wasmBinaryFile)\n      })\n    }\n    function createWasm() {\n      var info = { a: asmLibraryArg }\n      function receiveInstance(instance, module) {\n        var exports = instance.exports\n        Module['asm'] = exports\n        wasmMemory = Module['asm']['s']\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        wasmTable = Module['asm']['D']\n        addOnInit(Module['asm']['t'])\n        removeRunDependency('wasm-instantiate')\n      }\n      addRunDependency('wasm-instantiate')\n      function receiveInstantiationResult(result) {\n        receiveInstance(result['instance'])\n      }\n      function instantiateArrayBuffer(receiver) {\n        return getBinaryPromise()\n          .then(function(binary) {\n            return WebAssembly.instantiate(binary, info)\n          })\n          .then(function(instance) {\n            return instance\n          })\n          .then(receiver, function(reason) {\n            err('failed to asynchronously prepare wasm: ' + reason)\n            abort(reason)\n          })\n      }\n      function instantiateAsync() {\n        if (\n          !wasmBinary &&\n          typeof WebAssembly.instantiateStreaming == 'function' &&\n          !isDataURI(wasmBinaryFile) &&\n          !isFileURI(wasmBinaryFile) &&\n          !ENVIRONMENT_IS_NODE &&\n          typeof fetch == 'function'\n        ) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(\n            function(response) {\n              var result = WebAssembly.instantiateStreaming(response, info)\n              return result.then(receiveInstantiationResult, function(reason) {\n                err('wasm streaming compile failed: ' + reason)\n                err('falling back to ArrayBuffer instantiation')\n                return instantiateArrayBuffer(receiveInstantiationResult)\n              })\n            }\n          )\n        } else {\n          return instantiateArrayBuffer(receiveInstantiationResult)\n        }\n      }\n      if (Module['instantiateWasm']) {\n        try {\n          var exports = Module['instantiateWasm'](info, receiveInstance)\n          return exports\n        } catch (e) {\n          err('Module.instantiateWasm callback failed with error: ' + e)\n          readyPromiseReject(e)\n        }\n      }\n      instantiateAsync().catch(readyPromiseReject)\n      return {}\n    }\n    var tempDouble\n    var tempI64\n    function ExitStatus(status) {\n      this.name = 'ExitStatus'\n      this.message = 'Program terminated with exit(' + status + ')'\n      this.status = status\n    }\n    function callRuntimeCallbacks(callbacks) {\n      while (callbacks.length > 0) {\n        callbacks.shift()(Module)\n      }\n    }\n    function ExceptionInfo(excPtr) {\n      this.excPtr = excPtr\n      this.ptr = excPtr - 24\n      this.set_type = function(type) {\n        HEAPU32[(this.ptr + 4) >> 2] = type\n      }\n      this.get_type = function() {\n        return HEAPU32[(this.ptr + 4) >> 2]\n      }\n      this.set_destructor = function(destructor) {\n        HEAPU32[(this.ptr + 8) >> 2] = destructor\n      }\n      this.get_destructor = function() {\n        return HEAPU32[(this.ptr + 8) >> 2]\n      }\n      this.set_refcount = function(refcount) {\n        HEAP32[this.ptr >> 2] = refcount\n      }\n      this.set_caught = function(caught) {\n        caught = caught ? 1 : 0\n        HEAP8[(this.ptr + 12) >> 0] = caught\n      }\n      this.get_caught = function() {\n        return HEAP8[(this.ptr + 12) >> 0] != 0\n      }\n      this.set_rethrown = function(rethrown) {\n        rethrown = rethrown ? 1 : 0\n        HEAP8[(this.ptr + 13) >> 0] = rethrown\n      }\n      this.get_rethrown = function() {\n        return HEAP8[(this.ptr + 13) >> 0] != 0\n      }\n      this.init = function(type, destructor) {\n        this.set_adjusted_ptr(0)\n        this.set_type(type)\n        this.set_destructor(destructor)\n        this.set_refcount(0)\n        this.set_caught(false)\n        this.set_rethrown(false)\n      }\n      this.add_ref = function() {\n        var value = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = value + 1\n      }\n      this.release_ref = function() {\n        var prev = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = prev - 1\n        return prev === 1\n      }\n      this.set_adjusted_ptr = function(adjustedPtr) {\n        HEAPU32[(this.ptr + 16) >> 2] = adjustedPtr\n      }\n      this.get_adjusted_ptr = function() {\n        return HEAPU32[(this.ptr + 16) >> 2]\n      }\n      this.get_exception_ptr = function() {\n        var isPointer = ___cxa_is_pointer_type(this.get_type())\n        if (isPointer) {\n          return HEAPU32[this.excPtr >> 2]\n        }\n        var adjusted = this.get_adjusted_ptr()\n        if (adjusted !== 0) return adjusted\n        return this.excPtr\n      }\n    }\n    var exceptionLast = 0\n    var uncaughtExceptionCount = 0\n    function ___cxa_throw(ptr, type, destructor) {\n      var info = new ExceptionInfo(ptr)\n      info.init(type, destructor)\n      exceptionLast = ptr\n      uncaughtExceptionCount++\n      throw ptr\n    }\n    function setErrNo(value) {\n      HEAP32[___errno_location() >> 2] = value\n      return value\n    }\n    var PATH = {\n      isAbs: path => path.charAt(0) === '/',\n      splitPath: filename => {\n        var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/\n        return splitPathRe.exec(filename).slice(1)\n      },\n      normalizeArray: (parts, allowAboveRoot) => {\n        var up = 0\n        for (var i = parts.length - 1; i >= 0; i--) {\n          var last = parts[i]\n          if (last === '.') {\n            parts.splice(i, 1)\n          } else if (last === '..') {\n            parts.splice(i, 1)\n            up++\n          } else if (up) {\n            parts.splice(i, 1)\n            up--\n          }\n        }\n        if (allowAboveRoot) {\n          for (; up; up--) {\n            parts.unshift('..')\n          }\n        }\n        return parts\n      },\n      normalize: path => {\n        var isAbsolute = PATH.isAbs(path),\n          trailingSlash = path.substr(-1) === '/'\n        path = PATH.normalizeArray(\n          path.split('/').filter(p => !!p),\n          !isAbsolute\n        ).join('/')\n        if (!path && !isAbsolute) {\n          path = '.'\n        }\n        if (path && trailingSlash) {\n          path += '/'\n        }\n        return (isAbsolute ? '/' : '') + path\n      },\n      dirname: path => {\n        var result = PATH.splitPath(path),\n          root = result[0],\n          dir = result[1]\n        if (!root && !dir) {\n          return '.'\n        }\n        if (dir) {\n          dir = dir.substr(0, dir.length - 1)\n        }\n        return root + dir\n      },\n      basename: path => {\n        if (path === '/') return '/'\n        path = PATH.normalize(path)\n        path = path.replace(/\\/$/, '')\n        var lastSlash = path.lastIndexOf('/')\n        if (lastSlash === -1) return path\n        return path.substr(lastSlash + 1)\n      },\n      join: function() {\n        var paths = Array.prototype.slice.call(arguments)\n        return PATH.normalize(paths.join('/'))\n      },\n      join2: (l, r) => {\n        return PATH.normalize(l + '/' + r)\n      },\n    }\n    function getRandomDevice() {\n      if (\n        typeof crypto == 'object' &&\n        typeof crypto['getRandomValues'] == 'function'\n      ) {\n        var randomBuffer = new Uint8Array(1)\n        return () => {\n          crypto.getRandomValues(randomBuffer)\n          return randomBuffer[0]\n        }\n      } else if (ENVIRONMENT_IS_NODE) {\n        try {\n          var crypto_module = require('crypto')\n          return () => crypto_module['randomBytes'](1)[0]\n        } catch (e) {}\n      }\n      return () => abort('randomDevice')\n    }\n    var PATH_FS = {\n      resolve: function() {\n        var resolvedPath = '',\n          resolvedAbsolute = false\n        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n          var path = i >= 0 ? arguments[i] : FS.cwd()\n          if (typeof path != 'string') {\n            throw new TypeError('Arguments to path.resolve must be strings')\n          } else if (!path) {\n            return ''\n          }\n          resolvedPath = path + '/' + resolvedPath\n          resolvedAbsolute = PATH.isAbs(path)\n        }\n        resolvedPath = PATH.normalizeArray(\n          resolvedPath.split('/').filter(p => !!p),\n          !resolvedAbsolute\n        ).join('/')\n        return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'\n      },\n      relative: (from, to) => {\n        from = PATH_FS.resolve(from).substr(1)\n        to = PATH_FS.resolve(to).substr(1)\n        function trim(arr) {\n          var start = 0\n          for (; start < arr.length; start++) {\n            if (arr[start] !== '') break\n          }\n          var end = arr.length - 1\n          for (; end >= 0; end--) {\n            if (arr[end] !== '') break\n          }\n          if (start > end) return []\n          return arr.slice(start, end - start + 1)\n        }\n        var fromParts = trim(from.split('/'))\n        var toParts = trim(to.split('/'))\n        var length = Math.min(fromParts.length, toParts.length)\n        var samePartsLength = length\n        for (var i = 0; i < length; i++) {\n          if (fromParts[i] !== toParts[i]) {\n            samePartsLength = i\n            break\n          }\n        }\n        var outputParts = []\n        for (var i = samePartsLength; i < fromParts.length; i++) {\n          outputParts.push('..')\n        }\n        outputParts = outputParts.concat(toParts.slice(samePartsLength))\n        return outputParts.join('/')\n      },\n    }\n    function intArrayFromString(stringy, dontAddNull, length) {\n      var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1\n      var u8array = new Array(len)\n      var numBytesWritten = stringToUTF8Array(\n        stringy,\n        u8array,\n        0,\n        u8array.length\n      )\n      if (dontAddNull) u8array.length = numBytesWritten\n      return u8array\n    }\n    var TTY = {\n      ttys: [],\n      init: function() {},\n      shutdown: function() {},\n      register: function(dev, ops) {\n        TTY.ttys[dev] = { input: [], output: [], ops: ops }\n        FS.registerDevice(dev, TTY.stream_ops)\n      },\n      stream_ops: {\n        open: function(stream) {\n          var tty = TTY.ttys[stream.node.rdev]\n          if (!tty) {\n            throw new FS.ErrnoError(43)\n          }\n          stream.tty = tty\n          stream.seekable = false\n        },\n        close: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        fsync: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        read: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.get_char) {\n            throw new FS.ErrnoError(60)\n          }\n          var bytesRead = 0\n          for (var i = 0; i < length; i++) {\n            var result\n            try {\n              result = stream.tty.ops.get_char(stream.tty)\n            } catch (e) {\n              throw new FS.ErrnoError(29)\n            }\n            if (result === undefined && bytesRead === 0) {\n              throw new FS.ErrnoError(6)\n            }\n            if (result === null || result === undefined) break\n            bytesRead++\n            buffer[offset + i] = result\n          }\n          if (bytesRead) {\n            stream.node.timestamp = Date.now()\n          }\n          return bytesRead\n        },\n        write: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.put_char) {\n            throw new FS.ErrnoError(60)\n          }\n          try {\n            for (var i = 0; i < length; i++) {\n              stream.tty.ops.put_char(stream.tty, buffer[offset + i])\n            }\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n          if (length) {\n            stream.node.timestamp = Date.now()\n          }\n          return i\n        },\n      },\n      default_tty_ops: {\n        get_char: function(tty) {\n          if (!tty.input.length) {\n            var result = null\n            if (ENVIRONMENT_IS_NODE) {\n              var BUFSIZE = 256\n              var buf = Buffer.alloc(BUFSIZE)\n              var bytesRead = 0\n              try {\n                bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, -1)\n              } catch (e) {\n                if (e.toString().includes('EOF')) bytesRead = 0\n                else throw e\n              }\n              if (bytesRead > 0) {\n                result = buf.slice(0, bytesRead).toString('utf-8')\n              } else {\n                result = null\n              }\n            } else if (\n              typeof window != 'undefined' &&\n              typeof window.prompt == 'function'\n            ) {\n              result = window.prompt('Input: ')\n              if (result !== null) {\n                result += '\\n'\n              }\n            } else if (typeof readline == 'function') {\n              result = readline()\n              if (result !== null) {\n                result += '\\n'\n              }\n            }\n            if (!result) {\n              return null\n            }\n            tty.input = intArrayFromString(result, true)\n          }\n          return tty.input.shift()\n        },\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n      default_tty1_ops: {\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n    }\n    function mmapAlloc(size) {\n      abort()\n    }\n    var MEMFS = {\n      ops_table: null,\n      mount: function(mount) {\n        return MEMFS.createNode(null, '/', 16384 | 511, 0)\n      },\n      createNode: function(parent, name, mode, dev) {\n        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n          throw new FS.ErrnoError(63)\n        }\n        if (!MEMFS.ops_table) {\n          MEMFS.ops_table = {\n            dir: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                lookup: MEMFS.node_ops.lookup,\n                mknod: MEMFS.node_ops.mknod,\n                rename: MEMFS.node_ops.rename,\n                unlink: MEMFS.node_ops.unlink,\n                rmdir: MEMFS.node_ops.rmdir,\n                readdir: MEMFS.node_ops.readdir,\n                symlink: MEMFS.node_ops.symlink,\n              },\n              stream: { llseek: MEMFS.stream_ops.llseek },\n            },\n            file: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: {\n                llseek: MEMFS.stream_ops.llseek,\n                read: MEMFS.stream_ops.read,\n                write: MEMFS.stream_ops.write,\n                allocate: MEMFS.stream_ops.allocate,\n                mmap: MEMFS.stream_ops.mmap,\n                msync: MEMFS.stream_ops.msync,\n              },\n            },\n            link: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                readlink: MEMFS.node_ops.readlink,\n              },\n              stream: {},\n            },\n            chrdev: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: FS.chrdev_stream_ops,\n            },\n          }\n        }\n        var node = FS.createNode(parent, name, mode, dev)\n        if (FS.isDir(node.mode)) {\n          node.node_ops = MEMFS.ops_table.dir.node\n          node.stream_ops = MEMFS.ops_table.dir.stream\n          node.contents = {}\n        } else if (FS.isFile(node.mode)) {\n          node.node_ops = MEMFS.ops_table.file.node\n          node.stream_ops = MEMFS.ops_table.file.stream\n          node.usedBytes = 0\n          node.contents = null\n        } else if (FS.isLink(node.mode)) {\n          node.node_ops = MEMFS.ops_table.link.node\n          node.stream_ops = MEMFS.ops_table.link.stream\n        } else if (FS.isChrdev(node.mode)) {\n          node.node_ops = MEMFS.ops_table.chrdev.node\n          node.stream_ops = MEMFS.ops_table.chrdev.stream\n        }\n        node.timestamp = Date.now()\n        if (parent) {\n          parent.contents[name] = node\n          parent.timestamp = node.timestamp\n        }\n        return node\n      },\n      getFileDataAsTypedArray: function(node) {\n        if (!node.contents) return new Uint8Array(0)\n        if (node.contents.subarray)\n          return node.contents.subarray(0, node.usedBytes)\n        return new Uint8Array(node.contents)\n      },\n      expandFileStorage: function(node, newCapacity) {\n        var prevCapacity = node.contents ? node.contents.length : 0\n        if (prevCapacity >= newCapacity) return\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024\n        newCapacity = Math.max(\n          newCapacity,\n          (prevCapacity *\n            (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>>\n            0\n        )\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256)\n        var oldContents = node.contents\n        node.contents = new Uint8Array(newCapacity)\n        if (node.usedBytes > 0)\n          node.contents.set(oldContents.subarray(0, node.usedBytes), 0)\n      },\n      resizeFileStorage: function(node, newSize) {\n        if (node.usedBytes == newSize) return\n        if (newSize == 0) {\n          node.contents = null\n          node.usedBytes = 0\n        } else {\n          var oldContents = node.contents\n          node.contents = new Uint8Array(newSize)\n          if (oldContents) {\n            node.contents.set(\n              oldContents.subarray(0, Math.min(newSize, node.usedBytes))\n            )\n          }\n          node.usedBytes = newSize\n        }\n      },\n      node_ops: {\n        getattr: function(node) {\n          var attr = {}\n          attr.dev = FS.isChrdev(node.mode) ? node.id : 1\n          attr.ino = node.id\n          attr.mode = node.mode\n          attr.nlink = 1\n          attr.uid = 0\n          attr.gid = 0\n          attr.rdev = node.rdev\n          if (FS.isDir(node.mode)) {\n            attr.size = 4096\n          } else if (FS.isFile(node.mode)) {\n            attr.size = node.usedBytes\n          } else if (FS.isLink(node.mode)) {\n            attr.size = node.link.length\n          } else {\n            attr.size = 0\n          }\n          attr.atime = new Date(node.timestamp)\n          attr.mtime = new Date(node.timestamp)\n          attr.ctime = new Date(node.timestamp)\n          attr.blksize = 4096\n          attr.blocks = Math.ceil(attr.size / attr.blksize)\n          return attr\n        },\n        setattr: function(node, attr) {\n          if (attr.mode !== undefined) {\n            node.mode = attr.mode\n          }\n          if (attr.timestamp !== undefined) {\n            node.timestamp = attr.timestamp\n          }\n          if (attr.size !== undefined) {\n            MEMFS.resizeFileStorage(node, attr.size)\n          }\n        },\n        lookup: function(parent, name) {\n          throw FS.genericErrors[44]\n        },\n        mknod: function(parent, name, mode, dev) {\n          return MEMFS.createNode(parent, name, mode, dev)\n        },\n        rename: function(old_node, new_dir, new_name) {\n          if (FS.isDir(old_node.mode)) {\n            var new_node\n            try {\n              new_node = FS.lookupNode(new_dir, new_name)\n            } catch (e) {}\n            if (new_node) {\n              for (var i in new_node.contents) {\n                throw new FS.ErrnoError(55)\n              }\n            }\n          }\n          delete old_node.parent.contents[old_node.name]\n          old_node.parent.timestamp = Date.now()\n          old_node.name = new_name\n          new_dir.contents[new_name] = old_node\n          new_dir.timestamp = old_node.parent.timestamp\n          old_node.parent = new_dir\n        },\n        unlink: function(parent, name) {\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        rmdir: function(parent, name) {\n          var node = FS.lookupNode(parent, name)\n          for (var i in node.contents) {\n            throw new FS.ErrnoError(55)\n          }\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        readdir: function(node) {\n          var entries = ['.', '..']\n          for (var key in node.contents) {\n            if (!node.contents.hasOwnProperty(key)) {\n              continue\n            }\n            entries.push(key)\n          }\n          return entries\n        },\n        symlink: function(parent, newname, oldpath) {\n          var node = MEMFS.createNode(parent, newname, 511 | 40960, 0)\n          node.link = oldpath\n          return node\n        },\n        readlink: function(node) {\n          if (!FS.isLink(node.mode)) {\n            throw new FS.ErrnoError(28)\n          }\n          return node.link\n        },\n      },\n      stream_ops: {\n        read: function(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= stream.node.usedBytes) return 0\n          var size = Math.min(stream.node.usedBytes - position, length)\n          if (size > 8 && contents.subarray) {\n            buffer.set(contents.subarray(position, position + size), offset)\n          } else {\n            for (var i = 0; i < size; i++)\n              buffer[offset + i] = contents[position + i]\n          }\n          return size\n        },\n        write: function(stream, buffer, offset, length, position, canOwn) {\n          if (buffer.buffer === HEAP8.buffer) {\n            canOwn = false\n          }\n          if (!length) return 0\n          var node = stream.node\n          node.timestamp = Date.now()\n          if (buffer.subarray && (!node.contents || node.contents.subarray)) {\n            if (canOwn) {\n              node.contents = buffer.subarray(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (node.usedBytes === 0 && position === 0) {\n              node.contents = buffer.slice(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (position + length <= node.usedBytes) {\n              node.contents.set(\n                buffer.subarray(offset, offset + length),\n                position\n              )\n              return length\n            }\n          }\n          MEMFS.expandFileStorage(node, position + length)\n          if (node.contents.subarray && buffer.subarray) {\n            node.contents.set(\n              buffer.subarray(offset, offset + length),\n              position\n            )\n          } else {\n            for (var i = 0; i < length; i++) {\n              node.contents[position + i] = buffer[offset + i]\n            }\n          }\n          node.usedBytes = Math.max(node.usedBytes, position + length)\n          return length\n        },\n        llseek: function(stream, offset, whence) {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              position += stream.node.usedBytes\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        allocate: function(stream, offset, length) {\n          MEMFS.expandFileStorage(stream.node, offset + length)\n          stream.node.usedBytes = Math.max(\n            stream.node.usedBytes,\n            offset + length\n          )\n        },\n        mmap: function(stream, length, position, prot, flags) {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr\n          var allocated\n          var contents = stream.node.contents\n          if (!(flags & 2) && contents.buffer === buffer) {\n            allocated = false\n            ptr = contents.byteOffset\n          } else {\n            if (position > 0 || position + length < contents.length) {\n              if (contents.subarray) {\n                contents = contents.subarray(position, position + length)\n              } else {\n                contents = Array.prototype.slice.call(\n                  contents,\n                  position,\n                  position + length\n                )\n              }\n            }\n            allocated = true\n            ptr = mmapAlloc(length)\n            if (!ptr) {\n              throw new FS.ErrnoError(48)\n            }\n            HEAP8.set(contents, ptr)\n          }\n          return { ptr: ptr, allocated: allocated }\n        },\n        msync: function(stream, buffer, offset, length, mmapFlags) {\n          MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    function asyncLoad(url, onload, onerror, noRunDep) {\n      var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''\n      readAsync(\n        url,\n        arrayBuffer => {\n          assert(\n            arrayBuffer,\n            'Loading data file \"' + url + '\" failed (no arrayBuffer).'\n          )\n          onload(new Uint8Array(arrayBuffer))\n          if (dep) removeRunDependency(dep)\n        },\n        event => {\n          if (onerror) {\n            onerror()\n          } else {\n            throw 'Loading data file \"' + url + '\" failed.'\n          }\n        }\n      )\n      if (dep) addRunDependency(dep)\n    }\n    var ERRNO_CODES = {}\n    var NODEFS = {\n      isWindows: false,\n      staticInit: () => {\n        NODEFS.isWindows = !!process.platform.match(/^win/)\n        var flags = process['binding']('constants')\n        if (flags['fs']) {\n          flags = flags['fs']\n        }\n        NODEFS.flagsForNodeMap = {\n          1024: flags['O_APPEND'],\n          64: flags['O_CREAT'],\n          128: flags['O_EXCL'],\n          256: flags['O_NOCTTY'],\n          0: flags['O_RDONLY'],\n          2: flags['O_RDWR'],\n          4096: flags['O_SYNC'],\n          512: flags['O_TRUNC'],\n          1: flags['O_WRONLY'],\n          131072: flags['O_NOFOLLOW'],\n        }\n      },\n      convertNodeCode: e => {\n        var code = e.code\n        return ERRNO_CODES[code]\n      },\n      mount: mount => {\n        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0)\n      },\n      createNode: (parent, name, mode, dev) => {\n        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = FS.createNode(parent, name, mode)\n        node.node_ops = NODEFS.node_ops\n        node.stream_ops = NODEFS.stream_ops\n        return node\n      },\n      getMode: path => {\n        var stat\n        try {\n          stat = fs.lstatSync(path)\n          if (NODEFS.isWindows) {\n            stat.mode = stat.mode | ((stat.mode & 292) >> 2)\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n        }\n        return stat.mode\n      },\n      realPath: node => {\n        var parts = []\n        while (node.parent !== node) {\n          parts.push(node.name)\n          node = node.parent\n        }\n        parts.push(node.mount.opts.root)\n        parts.reverse()\n        return PATH.join.apply(null, parts)\n      },\n      flagsForNode: flags => {\n        flags &= ~2097152\n        flags &= ~2048\n        flags &= ~32768\n        flags &= ~524288\n        flags &= ~65536\n        var newFlags = 0\n        for (var k in NODEFS.flagsForNodeMap) {\n          if (flags & k) {\n            newFlags |= NODEFS.flagsForNodeMap[k]\n            flags ^= k\n          }\n        }\n        if (flags) {\n          throw new FS.ErrnoError(28)\n        }\n        return newFlags\n      },\n      node_ops: {\n        getattr: node => {\n          var path = NODEFS.realPath(node)\n          var stat\n          try {\n            stat = fs.lstatSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          if (NODEFS.isWindows && !stat.blksize) {\n            stat.blksize = 4096\n          }\n          if (NODEFS.isWindows && !stat.blocks) {\n            stat.blocks = ((stat.size + stat.blksize - 1) / stat.blksize) | 0\n          }\n          return {\n            dev: stat.dev,\n            ino: stat.ino,\n            mode: stat.mode,\n            nlink: stat.nlink,\n            uid: stat.uid,\n            gid: stat.gid,\n            rdev: stat.rdev,\n            size: stat.size,\n            atime: stat.atime,\n            mtime: stat.mtime,\n            ctime: stat.ctime,\n            blksize: stat.blksize,\n            blocks: stat.blocks,\n          }\n        },\n        setattr: (node, attr) => {\n          var path = NODEFS.realPath(node)\n          try {\n            if (attr.mode !== undefined) {\n              fs.chmodSync(path, attr.mode)\n              node.mode = attr.mode\n            }\n            if (attr.timestamp !== undefined) {\n              var date = new Date(attr.timestamp)\n              fs.utimesSync(path, date, date)\n            }\n            if (attr.size !== undefined) {\n              fs.truncateSync(path, attr.size)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        lookup: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          var mode = NODEFS.getMode(path)\n          return NODEFS.createNode(parent, name, mode)\n        },\n        mknod: (parent, name, mode, dev) => {\n          var node = NODEFS.createNode(parent, name, mode, dev)\n          var path = NODEFS.realPath(node)\n          try {\n            if (FS.isDir(node.mode)) {\n              fs.mkdirSync(path, node.mode)\n            } else {\n              fs.writeFileSync(path, '', { mode: node.mode })\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          return node\n        },\n        rename: (oldNode, newDir, newName) => {\n          var oldPath = NODEFS.realPath(oldNode)\n          var newPath = PATH.join2(NODEFS.realPath(newDir), newName)\n          try {\n            fs.renameSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          oldNode.name = newName\n        },\n        unlink: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.unlinkSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        rmdir: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.rmdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readdir: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            return fs.readdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        symlink: (parent, newName, oldPath) => {\n          var newPath = PATH.join2(NODEFS.realPath(parent), newName)\n          try {\n            fs.symlinkSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readlink: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            path = fs.readlinkSync(path)\n            path = nodePath.relative(\n              nodePath.resolve(node.mount.opts.root),\n              path\n            )\n            return path\n          } catch (e) {\n            if (!e.code) throw e\n            if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28)\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n      },\n      stream_ops: {\n        open: stream => {\n          var path = NODEFS.realPath(stream.node)\n          try {\n            if (FS.isFile(stream.node.mode)) {\n              stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags))\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        close: stream => {\n          try {\n            if (FS.isFile(stream.node.mode) && stream.nfd) {\n              fs.closeSync(stream.nfd)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        read: (stream, buffer, offset, length, position) => {\n          if (length === 0) return 0\n          try {\n            return fs.readSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        write: (stream, buffer, offset, length, position) => {\n          try {\n            return fs.writeSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        llseek: (stream, offset, whence) => {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              try {\n                var stat = fs.fstatSync(stream.nfd)\n                position += stat.size\n              } catch (e) {\n                throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n              }\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        mmap: (stream, length, position, prot, flags) => {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr = mmapAlloc(length)\n          NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        },\n        msync: (stream, buffer, offset, length, mmapFlags) => {\n          NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    var FS = {\n      root: null,\n      mounts: [],\n      devices: {},\n      streams: [],\n      nextInode: 1,\n      nameTable: null,\n      currentPath: '/',\n      initialized: false,\n      ignorePermissions: true,\n      ErrnoError: null,\n      genericErrors: {},\n      filesystems: null,\n      syncFSRequests: 0,\n      lookupPath: (path, opts = {}) => {\n        path = PATH_FS.resolve(path)\n        if (!path) return { path: '', node: null }\n        var defaults = { follow_mount: true, recurse_count: 0 }\n        opts = Object.assign(defaults, opts)\n        if (opts.recurse_count > 8) {\n          throw new FS.ErrnoError(32)\n        }\n        var parts = path.split('/').filter(p => !!p)\n        var current = FS.root\n        var current_path = '/'\n        for (var i = 0; i < parts.length; i++) {\n          var islast = i === parts.length - 1\n          if (islast && opts.parent) {\n            break\n          }\n          current = FS.lookupNode(current, parts[i])\n          current_path = PATH.join2(current_path, parts[i])\n          if (FS.isMountpoint(current)) {\n            if (!islast || (islast && opts.follow_mount)) {\n              current = current.mounted.root\n            }\n          }\n          if (!islast || opts.follow) {\n            var count = 0\n            while (FS.isLink(current.mode)) {\n              var link = FS.readlink(current_path)\n              current_path = PATH_FS.resolve(PATH.dirname(current_path), link)\n              var lookup = FS.lookupPath(current_path, {\n                recurse_count: opts.recurse_count + 1,\n              })\n              current = lookup.node\n              if (count++ > 40) {\n                throw new FS.ErrnoError(32)\n              }\n            }\n          }\n        }\n        return { path: current_path, node: current }\n      },\n      getPath: node => {\n        var path\n        while (true) {\n          if (FS.isRoot(node)) {\n            var mount = node.mount.mountpoint\n            if (!path) return mount\n            return mount[mount.length - 1] !== '/'\n              ? mount + '/' + path\n              : mount + path\n          }\n          path = path ? node.name + '/' + path : node.name\n          node = node.parent\n        }\n      },\n      hashName: (parentid, name) => {\n        var hash = 0\n        for (var i = 0; i < name.length; i++) {\n          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0\n        }\n        return ((parentid + hash) >>> 0) % FS.nameTable.length\n      },\n      hashAddNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        node.name_next = FS.nameTable[hash]\n        FS.nameTable[hash] = node\n      },\n      hashRemoveNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        if (FS.nameTable[hash] === node) {\n          FS.nameTable[hash] = node.name_next\n        } else {\n          var current = FS.nameTable[hash]\n          while (current) {\n            if (current.name_next === node) {\n              current.name_next = node.name_next\n              break\n            }\n            current = current.name_next\n          }\n        }\n      },\n      lookupNode: (parent, name) => {\n        var errCode = FS.mayLookup(parent)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode, parent)\n        }\n        var hash = FS.hashName(parent.id, name)\n        for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n          var nodeName = node.name\n          if (node.parent.id === parent.id && nodeName === name) {\n            return node\n          }\n        }\n        return FS.lookup(parent, name)\n      },\n      createNode: (parent, name, mode, rdev) => {\n        var node = new FS.FSNode(parent, name, mode, rdev)\n        FS.hashAddNode(node)\n        return node\n      },\n      destroyNode: node => {\n        FS.hashRemoveNode(node)\n      },\n      isRoot: node => {\n        return node === node.parent\n      },\n      isMountpoint: node => {\n        return !!node.mounted\n      },\n      isFile: mode => {\n        return (mode & 61440) === 32768\n      },\n      isDir: mode => {\n        return (mode & 61440) === 16384\n      },\n      isLink: mode => {\n        return (mode & 61440) === 40960\n      },\n      isChrdev: mode => {\n        return (mode & 61440) === 8192\n      },\n      isBlkdev: mode => {\n        return (mode & 61440) === 24576\n      },\n      isFIFO: mode => {\n        return (mode & 61440) === 4096\n      },\n      isSocket: mode => {\n        return (mode & 49152) === 49152\n      },\n      flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 },\n      modeStringToFlags: str => {\n        var flags = FS.flagModes[str]\n        if (typeof flags == 'undefined') {\n          throw new Error('Unknown file open mode: ' + str)\n        }\n        return flags\n      },\n      flagsToPermissionString: flag => {\n        var perms = ['r', 'w', 'rw'][flag & 3]\n        if (flag & 512) {\n          perms += 'w'\n        }\n        return perms\n      },\n      nodePermissions: (node, perms) => {\n        if (FS.ignorePermissions) {\n          return 0\n        }\n        if (perms.includes('r') && !(node.mode & 292)) {\n          return 2\n        } else if (perms.includes('w') && !(node.mode & 146)) {\n          return 2\n        } else if (perms.includes('x') && !(node.mode & 73)) {\n          return 2\n        }\n        return 0\n      },\n      mayLookup: dir => {\n        var errCode = FS.nodePermissions(dir, 'x')\n        if (errCode) return errCode\n        if (!dir.node_ops.lookup) return 2\n        return 0\n      },\n      mayCreate: (dir, name) => {\n        try {\n          var node = FS.lookupNode(dir, name)\n          return 20\n        } catch (e) {}\n        return FS.nodePermissions(dir, 'wx')\n      },\n      mayDelete: (dir, name, isdir) => {\n        var node\n        try {\n          node = FS.lookupNode(dir, name)\n        } catch (e) {\n          return e.errno\n        }\n        var errCode = FS.nodePermissions(dir, 'wx')\n        if (errCode) {\n          return errCode\n        }\n        if (isdir) {\n          if (!FS.isDir(node.mode)) {\n            return 54\n          }\n          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n            return 10\n          }\n        } else {\n          if (FS.isDir(node.mode)) {\n            return 31\n          }\n        }\n        return 0\n      },\n      mayOpen: (node, flags) => {\n        if (!node) {\n          return 44\n        }\n        if (FS.isLink(node.mode)) {\n          return 32\n        } else if (FS.isDir(node.mode)) {\n          if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) {\n            return 31\n          }\n        }\n        return FS.nodePermissions(node, FS.flagsToPermissionString(flags))\n      },\n      MAX_OPEN_FDS: 4096,\n      nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => {\n        for (var fd = fd_start; fd <= fd_end; fd++) {\n          if (!FS.streams[fd]) {\n            return fd\n          }\n        }\n        throw new FS.ErrnoError(33)\n      },\n      getStream: fd => FS.streams[fd],\n      createStream: (stream, fd_start, fd_end) => {\n        if (!FS.FSStream) {\n          FS.FSStream = function() {\n            this.shared = {}\n          }\n          FS.FSStream.prototype = {}\n          Object.defineProperties(FS.FSStream.prototype, {\n            object: {\n              get: function() {\n                return this.node\n              },\n              set: function(val) {\n                this.node = val\n              },\n            },\n            isRead: {\n              get: function() {\n                return (this.flags & 2097155) !== 1\n              },\n            },\n            isWrite: {\n              get: function() {\n                return (this.flags & 2097155) !== 0\n              },\n            },\n            isAppend: {\n              get: function() {\n                return this.flags & 1024\n              },\n            },\n            flags: {\n              get: function() {\n                return this.shared.flags\n              },\n              set: function(val) {\n                this.shared.flags = val\n              },\n            },\n            position: {\n              get: function() {\n                return this.shared.position\n              },\n              set: function(val) {\n                this.shared.position = val\n              },\n            },\n          })\n        }\n        stream = Object.assign(new FS.FSStream(), stream)\n        var fd = FS.nextfd(fd_start, fd_end)\n        stream.fd = fd\n        FS.streams[fd] = stream\n        return stream\n      },\n      closeStream: fd => {\n        FS.streams[fd] = null\n      },\n      chrdev_stream_ops: {\n        open: stream => {\n          var device = FS.getDevice(stream.node.rdev)\n          stream.stream_ops = device.stream_ops\n          if (stream.stream_ops.open) {\n            stream.stream_ops.open(stream)\n          }\n        },\n        llseek: () => {\n          throw new FS.ErrnoError(70)\n        },\n      },\n      major: dev => dev >> 8,\n      minor: dev => dev & 255,\n      makedev: (ma, mi) => (ma << 8) | mi,\n      registerDevice: (dev, ops) => {\n        FS.devices[dev] = { stream_ops: ops }\n      },\n      getDevice: dev => FS.devices[dev],\n      getMounts: mount => {\n        var mounts = []\n        var check = [mount]\n        while (check.length) {\n          var m = check.pop()\n          mounts.push(m)\n          check.push.apply(check, m.mounts)\n        }\n        return mounts\n      },\n      syncfs: (populate, callback) => {\n        if (typeof populate == 'function') {\n          callback = populate\n          populate = false\n        }\n        FS.syncFSRequests++\n        if (FS.syncFSRequests > 1) {\n          err(\n            'warning: ' +\n              FS.syncFSRequests +\n              ' FS.syncfs operations in flight at once, probably just doing extra work'\n          )\n        }\n        var mounts = FS.getMounts(FS.root.mount)\n        var completed = 0\n        function doCallback(errCode) {\n          FS.syncFSRequests--\n          return callback(errCode)\n        }\n        function done(errCode) {\n          if (errCode) {\n            if (!done.errored) {\n              done.errored = true\n              return doCallback(errCode)\n            }\n            return\n          }\n          if (++completed >= mounts.length) {\n            doCallback(null)\n          }\n        }\n        mounts.forEach(mount => {\n          if (!mount.type.syncfs) {\n            return done(null)\n          }\n          mount.type.syncfs(mount, populate, done)\n        })\n      },\n      mount: (type, opts, mountpoint) => {\n        var root = mountpoint === '/'\n        var pseudo = !mountpoint\n        var node\n        if (root && FS.root) {\n          throw new FS.ErrnoError(10)\n        } else if (!root && !pseudo) {\n          var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n          mountpoint = lookup.path\n          node = lookup.node\n          if (FS.isMountpoint(node)) {\n            throw new FS.ErrnoError(10)\n          }\n          if (!FS.isDir(node.mode)) {\n            throw new FS.ErrnoError(54)\n          }\n        }\n        var mount = {\n          type: type,\n          opts: opts,\n          mountpoint: mountpoint,\n          mounts: [],\n        }\n        var mountRoot = type.mount(mount)\n        mountRoot.mount = mount\n        mount.root = mountRoot\n        if (root) {\n          FS.root = mountRoot\n        } else if (node) {\n          node.mounted = mount\n          if (node.mount) {\n            node.mount.mounts.push(mount)\n          }\n        }\n        return mountRoot\n      },\n      unmount: mountpoint => {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n        if (!FS.isMountpoint(lookup.node)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = lookup.node\n        var mount = node.mounted\n        var mounts = FS.getMounts(mount)\n        Object.keys(FS.nameTable).forEach(hash => {\n          var current = FS.nameTable[hash]\n          while (current) {\n            var next = current.name_next\n            if (mounts.includes(current.mount)) {\n              FS.destroyNode(current)\n            }\n            current = next\n          }\n        })\n        node.mounted = null\n        var idx = node.mount.mounts.indexOf(mount)\n        node.mount.mounts.splice(idx, 1)\n      },\n      lookup: (parent, name) => {\n        return parent.node_ops.lookup(parent, name)\n      },\n      mknod: (path, mode, dev) => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        if (!name || name === '.' || name === '..') {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.mayCreate(parent, name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.mknod) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.mknod(parent, name, mode, dev)\n      },\n      create: (path, mode) => {\n        mode = mode !== undefined ? mode : 438\n        mode &= 4095\n        mode |= 32768\n        return FS.mknod(path, mode, 0)\n      },\n      mkdir: (path, mode) => {\n        mode = mode !== undefined ? mode : 511\n        mode &= 511 | 512\n        mode |= 16384\n        return FS.mknod(path, mode, 0)\n      },\n      mkdirTree: (path, mode) => {\n        var dirs = path.split('/')\n        var d = ''\n        for (var i = 0; i < dirs.length; ++i) {\n          if (!dirs[i]) continue\n          d += '/' + dirs[i]\n          try {\n            FS.mkdir(d, mode)\n          } catch (e) {\n            if (e.errno != 20) throw e\n          }\n        }\n      },\n      mkdev: (path, mode, dev) => {\n        if (typeof dev == 'undefined') {\n          dev = mode\n          mode = 438\n        }\n        mode |= 8192\n        return FS.mknod(path, mode, dev)\n      },\n      symlink: (oldpath, newpath) => {\n        if (!PATH_FS.resolve(oldpath)) {\n          throw new FS.ErrnoError(44)\n        }\n        var lookup = FS.lookupPath(newpath, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var newname = PATH.basename(newpath)\n        var errCode = FS.mayCreate(parent, newname)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.symlink) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.symlink(parent, newname, oldpath)\n      },\n      rename: (old_path, new_path) => {\n        var old_dirname = PATH.dirname(old_path)\n        var new_dirname = PATH.dirname(new_path)\n        var old_name = PATH.basename(old_path)\n        var new_name = PATH.basename(new_path)\n        var lookup, old_dir, new_dir\n        lookup = FS.lookupPath(old_path, { parent: true })\n        old_dir = lookup.node\n        lookup = FS.lookupPath(new_path, { parent: true })\n        new_dir = lookup.node\n        if (!old_dir || !new_dir) throw new FS.ErrnoError(44)\n        if (old_dir.mount !== new_dir.mount) {\n          throw new FS.ErrnoError(75)\n        }\n        var old_node = FS.lookupNode(old_dir, old_name)\n        var relative = PATH_FS.relative(old_path, new_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(28)\n        }\n        relative = PATH_FS.relative(new_path, old_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(55)\n        }\n        var new_node\n        try {\n          new_node = FS.lookupNode(new_dir, new_name)\n        } catch (e) {}\n        if (old_node === new_node) {\n          return\n        }\n        var isdir = FS.isDir(old_node.mode)\n        var errCode = FS.mayDelete(old_dir, old_name, isdir)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        errCode = new_node\n          ? FS.mayDelete(new_dir, new_name, isdir)\n          : FS.mayCreate(new_dir, new_name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!old_dir.node_ops.rename) {\n          throw new FS.ErrnoError(63)\n        }\n        if (\n          FS.isMountpoint(old_node) ||\n          (new_node && FS.isMountpoint(new_node))\n        ) {\n          throw new FS.ErrnoError(10)\n        }\n        if (new_dir !== old_dir) {\n          errCode = FS.nodePermissions(old_dir, 'w')\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        FS.hashRemoveNode(old_node)\n        try {\n          old_dir.node_ops.rename(old_node, new_dir, new_name)\n        } catch (e) {\n          throw e\n        } finally {\n          FS.hashAddNode(old_node)\n        }\n      },\n      rmdir: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, true)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.rmdir) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.rmdir(parent, name)\n        FS.destroyNode(node)\n      },\n      readdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        if (!node.node_ops.readdir) {\n          throw new FS.ErrnoError(54)\n        }\n        return node.node_ops.readdir(node)\n      },\n      unlink: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, false)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.unlink) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.unlink(parent, name)\n        FS.destroyNode(node)\n      },\n      readlink: path => {\n        var lookup = FS.lookupPath(path)\n        var link = lookup.node\n        if (!link) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!link.node_ops.readlink) {\n          throw new FS.ErrnoError(28)\n        }\n        return PATH_FS.resolve(\n          FS.getPath(link.parent),\n          link.node_ops.readlink(link)\n        )\n      },\n      stat: (path, dontFollow) => {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow })\n        var node = lookup.node\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!node.node_ops.getattr) {\n          throw new FS.ErrnoError(63)\n        }\n        return node.node_ops.getattr(node)\n      },\n      lstat: path => {\n        return FS.stat(path, true)\n      },\n      chmod: (path, mode, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, {\n          mode: (mode & 4095) | (node.mode & ~4095),\n          timestamp: Date.now(),\n        })\n      },\n      lchmod: (path, mode) => {\n        FS.chmod(path, mode, true)\n      },\n      fchmod: (fd, mode) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chmod(stream.node, mode)\n      },\n      chown: (path, uid, gid, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, { timestamp: Date.now() })\n      },\n      lchown: (path, uid, gid) => {\n        FS.chown(path, uid, gid, true)\n      },\n      fchown: (fd, uid, gid) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chown(stream.node, uid, gid)\n      },\n      truncate: (path, len) => {\n        if (len < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: true })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!FS.isFile(node.mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.nodePermissions(node, 'w')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        node.node_ops.setattr(node, { size: len, timestamp: Date.now() })\n      },\n      ftruncate: (fd, len) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(28)\n        }\n        FS.truncate(stream.node, len)\n      },\n      utime: (path, atime, mtime) => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) })\n      },\n      open: (path, flags, mode) => {\n        if (path === '') {\n          throw new FS.ErrnoError(44)\n        }\n        flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags\n        mode = typeof mode == 'undefined' ? 438 : mode\n        if (flags & 64) {\n          mode = (mode & 4095) | 32768\n        } else {\n          mode = 0\n        }\n        var node\n        if (typeof path == 'object') {\n          node = path\n        } else {\n          path = PATH.normalize(path)\n          try {\n            var lookup = FS.lookupPath(path, { follow: !(flags & 131072) })\n            node = lookup.node\n          } catch (e) {}\n        }\n        var created = false\n        if (flags & 64) {\n          if (node) {\n            if (flags & 128) {\n              throw new FS.ErrnoError(20)\n            }\n          } else {\n            node = FS.mknod(path, mode, 0)\n            created = true\n          }\n        }\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (FS.isChrdev(node.mode)) {\n          flags &= ~512\n        }\n        if (flags & 65536 && !FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        if (!created) {\n          var errCode = FS.mayOpen(node, flags)\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        if (flags & 512 && !created) {\n          FS.truncate(node, 0)\n        }\n        flags &= ~(128 | 512 | 131072)\n        var stream = FS.createStream({\n          node: node,\n          path: FS.getPath(node),\n          flags: flags,\n          seekable: true,\n          position: 0,\n          stream_ops: node.stream_ops,\n          ungotten: [],\n          error: false,\n        })\n        if (stream.stream_ops.open) {\n          stream.stream_ops.open(stream)\n        }\n        if (Module['logReadFiles'] && !(flags & 1)) {\n          if (!FS.readFiles) FS.readFiles = {}\n          if (!(path in FS.readFiles)) {\n            FS.readFiles[path] = 1\n          }\n        }\n        return stream\n      },\n      close: stream => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (stream.getdents) stream.getdents = null\n        try {\n          if (stream.stream_ops.close) {\n            stream.stream_ops.close(stream)\n          }\n        } catch (e) {\n          throw e\n        } finally {\n          FS.closeStream(stream.fd)\n        }\n        stream.fd = null\n      },\n      isClosed: stream => {\n        return stream.fd === null\n      },\n      llseek: (stream, offset, whence) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!stream.seekable || !stream.stream_ops.llseek) {\n          throw new FS.ErrnoError(70)\n        }\n        if (whence != 0 && whence != 1 && whence != 2) {\n          throw new FS.ErrnoError(28)\n        }\n        stream.position = stream.stream_ops.llseek(stream, offset, whence)\n        stream.ungotten = []\n        return stream.position\n      },\n      read: (stream, buffer, offset, length, position) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.read) {\n          throw new FS.ErrnoError(28)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesRead = stream.stream_ops.read(\n          stream,\n          buffer,\n          offset,\n          length,\n          position\n        )\n        if (!seeking) stream.position += bytesRead\n        return bytesRead\n      },\n      write: (stream, buffer, offset, length, position, canOwn) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.write) {\n          throw new FS.ErrnoError(28)\n        }\n        if (stream.seekable && stream.flags & 1024) {\n          FS.llseek(stream, 0, 2)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesWritten = stream.stream_ops.write(\n          stream,\n          buffer,\n          offset,\n          length,\n          position,\n          canOwn\n        )\n        if (!seeking) stream.position += bytesWritten\n        return bytesWritten\n      },\n      allocate: (stream, offset, length) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (offset < 0 || length <= 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (!stream.stream_ops.allocate) {\n          throw new FS.ErrnoError(138)\n        }\n        stream.stream_ops.allocate(stream, offset, length)\n      },\n      mmap: (stream, length, position, prot, flags) => {\n        if (\n          (prot & 2) !== 0 &&\n          (flags & 2) === 0 &&\n          (stream.flags & 2097155) !== 2\n        ) {\n          throw new FS.ErrnoError(2)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(2)\n        }\n        if (!stream.stream_ops.mmap) {\n          throw new FS.ErrnoError(43)\n        }\n        return stream.stream_ops.mmap(stream, length, position, prot, flags)\n      },\n      msync: (stream, buffer, offset, length, mmapFlags) => {\n        if (!stream.stream_ops.msync) {\n          return 0\n        }\n        return stream.stream_ops.msync(\n          stream,\n          buffer,\n          offset,\n          length,\n          mmapFlags\n        )\n      },\n      munmap: stream => 0,\n      ioctl: (stream, cmd, arg) => {\n        if (!stream.stream_ops.ioctl) {\n          throw new FS.ErrnoError(59)\n        }\n        return stream.stream_ops.ioctl(stream, cmd, arg)\n      },\n      readFile: (path, opts = {}) => {\n        opts.flags = opts.flags || 0\n        opts.encoding = opts.encoding || 'binary'\n        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {\n          throw new Error('Invalid encoding type \"' + opts.encoding + '\"')\n        }\n        var ret\n        var stream = FS.open(path, opts.flags)\n        var stat = FS.stat(path)\n        var length = stat.size\n        var buf = new Uint8Array(length)\n        FS.read(stream, buf, 0, length, 0)\n        if (opts.encoding === 'utf8') {\n          ret = UTF8ArrayToString(buf, 0)\n        } else if (opts.encoding === 'binary') {\n          ret = buf\n        }\n        FS.close(stream)\n        return ret\n      },\n      writeFile: (path, data, opts = {}) => {\n        opts.flags = opts.flags || 577\n        var stream = FS.open(path, opts.flags, opts.mode)\n        if (typeof data == 'string') {\n          var buf = new Uint8Array(lengthBytesUTF8(data) + 1)\n          var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length)\n          FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn)\n        } else if (ArrayBuffer.isView(data)) {\n          FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn)\n        } else {\n          throw new Error('Unsupported data type')\n        }\n        FS.close(stream)\n      },\n      cwd: () => FS.currentPath,\n      chdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        if (lookup.node === null) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!FS.isDir(lookup.node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        var errCode = FS.nodePermissions(lookup.node, 'x')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        FS.currentPath = lookup.path\n      },\n      createDefaultDirectories: () => {\n        FS.mkdir('/tmp')\n        FS.mkdir('/home')\n        FS.mkdir('/home/web_user')\n      },\n      createDefaultDevices: () => {\n        FS.mkdir('/dev')\n        FS.registerDevice(FS.makedev(1, 3), {\n          read: () => 0,\n          write: (stream, buffer, offset, length, pos) => length,\n        })\n        FS.mkdev('/dev/null', FS.makedev(1, 3))\n        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops)\n        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops)\n        FS.mkdev('/dev/tty', FS.makedev(5, 0))\n        FS.mkdev('/dev/tty1', FS.makedev(6, 0))\n        var random_device = getRandomDevice()\n        FS.createDevice('/dev', 'random', random_device)\n        FS.createDevice('/dev', 'urandom', random_device)\n        FS.mkdir('/dev/shm')\n        FS.mkdir('/dev/shm/tmp')\n      },\n      createSpecialDirectories: () => {\n        FS.mkdir('/proc')\n        var proc_self = FS.mkdir('/proc/self')\n        FS.mkdir('/proc/self/fd')\n        FS.mount(\n          {\n            mount: () => {\n              var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73)\n              node.node_ops = {\n                lookup: (parent, name) => {\n                  var fd = +name\n                  var stream = FS.getStream(fd)\n                  if (!stream) throw new FS.ErrnoError(8)\n                  var ret = {\n                    parent: null,\n                    mount: { mountpoint: 'fake' },\n                    node_ops: { readlink: () => stream.path },\n                  }\n                  ret.parent = ret\n                  return ret\n                },\n              }\n              return node\n            },\n          },\n          {},\n          '/proc/self/fd'\n        )\n      },\n      createStandardStreams: () => {\n        if (Module['stdin']) {\n          FS.createDevice('/dev', 'stdin', Module['stdin'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdin')\n        }\n        if (Module['stdout']) {\n          FS.createDevice('/dev', 'stdout', null, Module['stdout'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdout')\n        }\n        if (Module['stderr']) {\n          FS.createDevice('/dev', 'stderr', null, Module['stderr'])\n        } else {\n          FS.symlink('/dev/tty1', '/dev/stderr')\n        }\n        var stdin = FS.open('/dev/stdin', 0)\n        var stdout = FS.open('/dev/stdout', 1)\n        var stderr = FS.open('/dev/stderr', 1)\n      },\n      ensureErrnoError: () => {\n        if (FS.ErrnoError) return\n        FS.ErrnoError = function ErrnoError(errno, node) {\n          this.node = node\n          this.setErrno = function(errno) {\n            this.errno = errno\n          }\n          this.setErrno(errno)\n          this.message = 'FS error'\n        }\n        FS.ErrnoError.prototype = new Error()\n        FS.ErrnoError.prototype.constructor = FS.ErrnoError\n        ;[44].forEach(code => {\n          FS.genericErrors[code] = new FS.ErrnoError(code)\n          FS.genericErrors[code].stack = '<generic error, no stack>'\n        })\n      },\n      staticInit: () => {\n        FS.ensureErrnoError()\n        FS.nameTable = new Array(4096)\n        FS.mount(MEMFS, {}, '/')\n        FS.createDefaultDirectories()\n        FS.createDefaultDevices()\n        FS.createSpecialDirectories()\n        FS.filesystems = { MEMFS: MEMFS, NODEFS: NODEFS }\n      },\n      init: (input, output, error) => {\n        FS.init.initialized = true\n        FS.ensureErrnoError()\n        Module['stdin'] = input || Module['stdin']\n        Module['stdout'] = output || Module['stdout']\n        Module['stderr'] = error || Module['stderr']\n        FS.createStandardStreams()\n      },\n      quit: () => {\n        FS.init.initialized = false\n        for (var i = 0; i < FS.streams.length; i++) {\n          var stream = FS.streams[i]\n          if (!stream) {\n            continue\n          }\n          FS.close(stream)\n        }\n      },\n      getMode: (canRead, canWrite) => {\n        var mode = 0\n        if (canRead) mode |= 292 | 73\n        if (canWrite) mode |= 146\n        return mode\n      },\n      findObject: (path, dontResolveLastLink) => {\n        var ret = FS.analyzePath(path, dontResolveLastLink)\n        if (!ret.exists) {\n          return null\n        }\n        return ret.object\n      },\n      analyzePath: (path, dontResolveLastLink) => {\n        try {\n          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          path = lookup.path\n        } catch (e) {}\n        var ret = {\n          isRoot: false,\n          exists: false,\n          error: 0,\n          name: null,\n          path: null,\n          object: null,\n          parentExists: false,\n          parentPath: null,\n          parentObject: null,\n        }\n        try {\n          var lookup = FS.lookupPath(path, { parent: true })\n          ret.parentExists = true\n          ret.parentPath = lookup.path\n          ret.parentObject = lookup.node\n          ret.name = PATH.basename(path)\n          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          ret.exists = true\n          ret.path = lookup.path\n          ret.object = lookup.node\n          ret.name = lookup.node.name\n          ret.isRoot = lookup.path === '/'\n        } catch (e) {\n          ret.error = e.errno\n        }\n        return ret\n      },\n      createPath: (parent, path, canRead, canWrite) => {\n        parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n        var parts = path.split('/').reverse()\n        while (parts.length) {\n          var part = parts.pop()\n          if (!part) continue\n          var current = PATH.join2(parent, part)\n          try {\n            FS.mkdir(current)\n          } catch (e) {}\n          parent = current\n        }\n        return current\n      },\n      createFile: (parent, name, properties, canRead, canWrite) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(canRead, canWrite)\n        return FS.create(path, mode)\n      },\n      createDataFile: (parent, name, data, canRead, canWrite, canOwn) => {\n        var path = name\n        if (parent) {\n          parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n          path = name ? PATH.join2(parent, name) : parent\n        }\n        var mode = FS.getMode(canRead, canWrite)\n        var node = FS.create(path, mode)\n        if (data) {\n          if (typeof data == 'string') {\n            var arr = new Array(data.length)\n            for (var i = 0, len = data.length; i < len; ++i)\n              arr[i] = data.charCodeAt(i)\n            data = arr\n          }\n          FS.chmod(node, mode | 146)\n          var stream = FS.open(node, 577)\n          FS.write(stream, data, 0, data.length, 0, canOwn)\n          FS.close(stream)\n          FS.chmod(node, mode)\n        }\n        return node\n      },\n      createDevice: (parent, name, input, output) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(!!input, !!output)\n        if (!FS.createDevice.major) FS.createDevice.major = 64\n        var dev = FS.makedev(FS.createDevice.major++, 0)\n        FS.registerDevice(dev, {\n          open: stream => {\n            stream.seekable = false\n          },\n          close: stream => {\n            if (output && output.buffer && output.buffer.length) {\n              output(10)\n            }\n          },\n          read: (stream, buffer, offset, length, pos) => {\n            var bytesRead = 0\n            for (var i = 0; i < length; i++) {\n              var result\n              try {\n                result = input()\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n              if (result === undefined && bytesRead === 0) {\n                throw new FS.ErrnoError(6)\n              }\n              if (result === null || result === undefined) break\n              bytesRead++\n              buffer[offset + i] = result\n            }\n            if (bytesRead) {\n              stream.node.timestamp = Date.now()\n            }\n            return bytesRead\n          },\n          write: (stream, buffer, offset, length, pos) => {\n            for (var i = 0; i < length; i++) {\n              try {\n                output(buffer[offset + i])\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n            }\n            if (length) {\n              stream.node.timestamp = Date.now()\n            }\n            return i\n          },\n        })\n        return FS.mkdev(path, mode, dev)\n      },\n      forceLoadFile: obj => {\n        if (obj.isDevice || obj.isFolder || obj.link || obj.contents)\n          return true\n        if (typeof XMLHttpRequest != 'undefined') {\n          throw new Error(\n            'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.'\n          )\n        } else if (read_) {\n          try {\n            obj.contents = intArrayFromString(read_(obj.url), true)\n            obj.usedBytes = obj.contents.length\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n        } else {\n          throw new Error('Cannot load without read() or XMLHttpRequest.')\n        }\n      },\n      createLazyFile: (parent, name, url, canRead, canWrite) => {\n        function LazyUint8Array() {\n          this.lengthKnown = false\n          this.chunks = []\n        }\n        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n          if (idx > this.length - 1 || idx < 0) {\n            return undefined\n          }\n          var chunkOffset = idx % this.chunkSize\n          var chunkNum = (idx / this.chunkSize) | 0\n          return this.getter(chunkNum)[chunkOffset]\n        }\n        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(\n          getter\n        ) {\n          this.getter = getter\n        }\n        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n          var xhr = new XMLHttpRequest()\n          xhr.open('HEAD', url, false)\n          xhr.send(null)\n          if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n            throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n          var datalength = Number(xhr.getResponseHeader('Content-length'))\n          var header\n          var hasByteServing =\n            (header = xhr.getResponseHeader('Accept-Ranges')) &&\n            header === 'bytes'\n          var usesGzip =\n            (header = xhr.getResponseHeader('Content-Encoding')) &&\n            header === 'gzip'\n          var chunkSize = 1024 * 1024\n          if (!hasByteServing) chunkSize = datalength\n          var doXHR = (from, to) => {\n            if (from > to)\n              throw new Error(\n                'invalid range (' +\n                  from +\n                  ', ' +\n                  to +\n                  ') or no bytes requested!'\n              )\n            if (to > datalength - 1)\n              throw new Error(\n                'only ' + datalength + ' bytes available! programmer error!'\n              )\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            if (datalength !== chunkSize)\n              xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to)\n            xhr.responseType = 'arraybuffer'\n            if (xhr.overrideMimeType) {\n              xhr.overrideMimeType('text/plain; charset=x-user-defined')\n            }\n            xhr.send(null)\n            if (\n              !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)\n            )\n              throw new Error(\n                \"Couldn't load \" + url + '. Status: ' + xhr.status\n              )\n            if (xhr.response !== undefined) {\n              return new Uint8Array(xhr.response || [])\n            }\n            return intArrayFromString(xhr.responseText || '', true)\n          }\n          var lazyArray = this\n          lazyArray.setDataGetter(chunkNum => {\n            var start = chunkNum * chunkSize\n            var end = (chunkNum + 1) * chunkSize - 1\n            end = Math.min(end, datalength - 1)\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined') {\n              lazyArray.chunks[chunkNum] = doXHR(start, end)\n            }\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined')\n              throw new Error('doXHR failed!')\n            return lazyArray.chunks[chunkNum]\n          })\n          if (usesGzip || !datalength) {\n            chunkSize = datalength = 1\n            datalength = this.getter(0).length\n            chunkSize = datalength\n            out(\n              'LazyFiles on gzip forces download of the whole file when length is accessed'\n            )\n          }\n          this._length = datalength\n          this._chunkSize = chunkSize\n          this.lengthKnown = true\n        }\n        if (typeof XMLHttpRequest != 'undefined') {\n          if (!ENVIRONMENT_IS_WORKER)\n            throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'\n          var lazyArray = new LazyUint8Array()\n          Object.defineProperties(lazyArray, {\n            length: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._length\n              },\n            },\n            chunkSize: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._chunkSize\n              },\n            },\n          })\n          var properties = { isDevice: false, contents: lazyArray }\n        } else {\n          var properties = { isDevice: false, url: url }\n        }\n        var node = FS.createFile(parent, name, properties, canRead, canWrite)\n        if (properties.contents) {\n          node.contents = properties.contents\n        } else if (properties.url) {\n          node.contents = null\n          node.url = properties.url\n        }\n        Object.defineProperties(node, {\n          usedBytes: {\n            get: function() {\n              return this.contents.length\n            },\n          },\n        })\n        var stream_ops = {}\n        var keys = Object.keys(node.stream_ops)\n        keys.forEach(key => {\n          var fn = node.stream_ops[key]\n          stream_ops[key] = function forceLoadLazyFile() {\n            FS.forceLoadFile(node)\n            return fn.apply(null, arguments)\n          }\n        })\n        function writeChunks(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= contents.length) return 0\n          var size = Math.min(contents.length - position, length)\n          if (contents.slice) {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents[position + i]\n            }\n          } else {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents.get(position + i)\n            }\n          }\n          return size\n        }\n        stream_ops.read = (stream, buffer, offset, length, position) => {\n          FS.forceLoadFile(node)\n          return writeChunks(stream, buffer, offset, length, position)\n        }\n        stream_ops.mmap = (stream, length, position, prot, flags) => {\n          FS.forceLoadFile(node)\n          var ptr = mmapAlloc(length)\n          if (!ptr) {\n            throw new FS.ErrnoError(48)\n          }\n          writeChunks(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        }\n        node.stream_ops = stream_ops\n        return node\n      },\n      createPreloadedFile: (\n        parent,\n        name,\n        url,\n        canRead,\n        canWrite,\n        onload,\n        onerror,\n        dontCreateFile,\n        canOwn,\n        preFinish\n      ) => {\n        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent\n        var dep = getUniqueRunDependency('cp ' + fullname)\n        function processData(byteArray) {\n          function finish(byteArray) {\n            if (preFinish) preFinish()\n            if (!dontCreateFile) {\n              FS.createDataFile(\n                parent,\n                name,\n                byteArray,\n                canRead,\n                canWrite,\n                canOwn\n              )\n            }\n            if (onload) onload()\n            removeRunDependency(dep)\n          }\n          if (\n            Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => {\n              if (onerror) onerror()\n              removeRunDependency(dep)\n            })\n          ) {\n            return\n          }\n          finish(byteArray)\n        }\n        addRunDependency(dep)\n        if (typeof url == 'string') {\n          asyncLoad(url, byteArray => processData(byteArray), onerror)\n        } else {\n          processData(url)\n        }\n      },\n      indexedDB: () => {\n        return (\n          window.indexedDB ||\n          window.mozIndexedDB ||\n          window.webkitIndexedDB ||\n          window.msIndexedDB\n        )\n      },\n      DB_NAME: () => {\n        return 'EM_FS_' + window.location.pathname\n      },\n      DB_VERSION: 20,\n      DB_STORE_NAME: 'FILE_DATA',\n      saveFilesToDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = () => {\n          out('creating db')\n          var db = openRequest.result\n          db.createObjectStore(FS.DB_STORE_NAME)\n        }\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite')\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var putRequest = files.put(\n              FS.analyzePath(path).object.contents,\n              path\n            )\n            putRequest.onsuccess = () => {\n              ok++\n              if (ok + fail == total) finish()\n            }\n            putRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n      loadFilesFromDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = onerror\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          try {\n            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly')\n          } catch (e) {\n            onerror(e)\n            return\n          }\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var getRequest = files.get(path)\n            getRequest.onsuccess = () => {\n              if (FS.analyzePath(path).exists) {\n                FS.unlink(path)\n              }\n              FS.createDataFile(\n                PATH.dirname(path),\n                PATH.basename(path),\n                getRequest.result,\n                true,\n                true,\n                true\n              )\n              ok++\n              if (ok + fail == total) finish()\n            }\n            getRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n    }\n    var SYSCALLS = {\n      DEFAULT_POLLMASK: 5,\n      calculateAt: function(dirfd, path, allowEmpty) {\n        if (PATH.isAbs(path)) {\n          return path\n        }\n        var dir\n        if (dirfd === -100) {\n          dir = FS.cwd()\n        } else {\n          var dirstream = SYSCALLS.getStreamFromFD(dirfd)\n          dir = dirstream.path\n        }\n        if (path.length == 0) {\n          if (!allowEmpty) {\n            throw new FS.ErrnoError(44)\n          }\n          return dir\n        }\n        return PATH.join2(dir, path)\n      },\n      doStat: function(func, path, buf) {\n        try {\n          var stat = func(path)\n        } catch (e) {\n          if (\n            e &&\n            e.node &&\n            PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))\n          ) {\n            return -54\n          }\n          throw e\n        }\n        HEAP32[buf >> 2] = stat.dev\n        HEAP32[(buf + 8) >> 2] = stat.ino\n        HEAP32[(buf + 12) >> 2] = stat.mode\n        HEAPU32[(buf + 16) >> 2] = stat.nlink\n        HEAP32[(buf + 20) >> 2] = stat.uid\n        HEAP32[(buf + 24) >> 2] = stat.gid\n        HEAP32[(buf + 28) >> 2] = stat.rdev\n        ;(tempI64 = [\n          stat.size >>> 0,\n          ((tempDouble = stat.size),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 40) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 44) >> 2] = tempI64[1])\n        HEAP32[(buf + 48) >> 2] = 4096\n        HEAP32[(buf + 52) >> 2] = stat.blocks\n        var atime = stat.atime.getTime()\n        var mtime = stat.mtime.getTime()\n        var ctime = stat.ctime.getTime()\n        ;(tempI64 = [\n          Math.floor(atime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(atime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 56) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 60) >> 2] = tempI64[1])\n        HEAPU32[(buf + 64) >> 2] = (atime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(mtime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(mtime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 72) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 76) >> 2] = tempI64[1])\n        HEAPU32[(buf + 80) >> 2] = (mtime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(ctime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(ctime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 88) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 92) >> 2] = tempI64[1])\n        HEAPU32[(buf + 96) >> 2] = (ctime % 1e3) * 1e3\n        ;(tempI64 = [\n          stat.ino >>> 0,\n          ((tempDouble = stat.ino),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 104) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 108) >> 2] = tempI64[1])\n        return 0\n      },\n      doMsync: function(addr, stream, len, flags, offset) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (flags & 2) {\n          return 0\n        }\n        var buffer = HEAPU8.slice(addr, addr + len)\n        FS.msync(stream, buffer, offset, len, flags)\n      },\n      varargs: undefined,\n      get: function() {\n        SYSCALLS.varargs += 4\n        var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]\n        return ret\n      },\n      getStr: function(ptr) {\n        var ret = UTF8ToString(ptr)\n        return ret\n      },\n      getStreamFromFD: function(fd) {\n        var stream = FS.getStream(fd)\n        if (!stream) throw new FS.ErrnoError(8)\n        return stream\n      },\n    }\n    function ___syscall_fcntl64(fd, cmd, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (cmd) {\n          case 0: {\n            var arg = SYSCALLS.get()\n            if (arg < 0) {\n              return -28\n            }\n            var newStream\n            newStream = FS.createStream(stream, arg)\n            return newStream.fd\n          }\n          case 1:\n          case 2:\n            return 0\n          case 3:\n            return stream.flags\n          case 4: {\n            var arg = SYSCALLS.get()\n            stream.flags |= arg\n            return 0\n          }\n          case 5: {\n            var arg = SYSCALLS.get()\n            var offset = 0\n            HEAP16[(arg + offset) >> 1] = 2\n            return 0\n          }\n          case 6:\n          case 7:\n            return 0\n          case 16:\n          case 8:\n            return -28\n          case 9:\n            setErrNo(28)\n            return -1\n          default: {\n            return -28\n          }\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_getcwd(buf, size) {\n      try {\n        if (size === 0) return -28\n        var cwd = FS.cwd()\n        var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1\n        if (size < cwdLengthInBytes) return -68\n        stringToUTF8(cwd, buf, size)\n        return cwdLengthInBytes\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_ioctl(fd, op, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (op) {\n          case 21509:\n          case 21505: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21510:\n          case 21511:\n          case 21512:\n          case 21506:\n          case 21507:\n          case 21508: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21519: {\n            if (!stream.tty) return -59\n            var argp = SYSCALLS.get()\n            HEAP32[argp >> 2] = 0\n            return 0\n          }\n          case 21520: {\n            if (!stream.tty) return -59\n            return -28\n          }\n          case 21531: {\n            var argp = SYSCALLS.get()\n            return FS.ioctl(stream, op, argp)\n          }\n          case 21523: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21524: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          default:\n            return -28\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_openat(dirfd, path, flags, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        var mode = varargs ? SYSCALLS.get() : 0\n        return FS.open(path, flags, mode).fd\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_readlinkat(dirfd, path, buf, bufsize) {\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        if (bufsize <= 0) return -28\n        var ret = FS.readlink(path)\n        var len = Math.min(bufsize, lengthBytesUTF8(ret))\n        var endChar = HEAP8[buf + len]\n        stringToUTF8(ret, buf, bufsize + 1)\n        HEAP8[buf + len] = endChar\n        return len\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_stat64(path, buf) {\n      try {\n        path = SYSCALLS.getStr(path)\n        return SYSCALLS.doStat(FS.stat, path, buf)\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function _abort() {\n      abort('')\n    }\n    function _emscripten_memcpy_big(dest, src, num) {\n      HEAPU8.copyWithin(dest, src, src + num)\n    }\n    function getHeapMax() {\n      return 2147483648\n    }\n    function emscripten_realloc_buffer(size) {\n      try {\n        wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16)\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        return 1\n      } catch (e) {}\n    }\n    function _emscripten_resize_heap(requestedSize) {\n      var oldSize = HEAPU8.length\n      requestedSize = requestedSize >>> 0\n      var maxHeapSize = getHeapMax()\n      if (requestedSize > maxHeapSize) {\n        return false\n      }\n      let alignUp = (x, multiple) =>\n        x + ((multiple - (x % multiple)) % multiple)\n      for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {\n        var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown)\n        overGrownHeapSize = Math.min(\n          overGrownHeapSize,\n          requestedSize + 100663296\n        )\n        var newSize = Math.min(\n          maxHeapSize,\n          alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)\n        )\n        var replacement = emscripten_realloc_buffer(newSize)\n        if (replacement) {\n          return true\n        }\n      }\n      return false\n    }\n    var ENV = {}\n    function getExecutableName() {\n      return thisProgram || './this.program'\n    }\n    function getEnvStrings() {\n      if (!getEnvStrings.strings) {\n        var lang =\n          (\n            (typeof navigator == 'object' &&\n              navigator.languages &&\n              navigator.languages[0]) ||\n            'C'\n          ).replace('-', '_') + '.UTF-8'\n        var env = {\n          USER: 'web_user',\n          LOGNAME: 'web_user',\n          PATH: '/',\n          PWD: '/',\n          HOME: '/home/web_user',\n          LANG: lang,\n          _: getExecutableName(),\n        }\n        for (var x in ENV) {\n          if (ENV[x] === undefined) delete env[x]\n          else env[x] = ENV[x]\n        }\n        var strings = []\n        for (var x in env) {\n          strings.push(x + '=' + env[x])\n        }\n        getEnvStrings.strings = strings\n      }\n      return getEnvStrings.strings\n    }\n    function writeAsciiToMemory(str, buffer, dontAddNull) {\n      for (var i = 0; i < str.length; ++i) {\n        HEAP8[buffer++ >> 0] = str.charCodeAt(i)\n      }\n      if (!dontAddNull) HEAP8[buffer >> 0] = 0\n    }\n    function _environ_get(__environ, environ_buf) {\n      var bufSize = 0\n      getEnvStrings().forEach(function(string, i) {\n        var ptr = environ_buf + bufSize\n        HEAPU32[(__environ + i * 4) >> 2] = ptr\n        writeAsciiToMemory(string, ptr)\n        bufSize += string.length + 1\n      })\n      return 0\n    }\n    function _environ_sizes_get(penviron_count, penviron_buf_size) {\n      var strings = getEnvStrings()\n      HEAPU32[penviron_count >> 2] = strings.length\n      var bufSize = 0\n      strings.forEach(function(string) {\n        bufSize += string.length + 1\n      })\n      HEAPU32[penviron_buf_size >> 2] = bufSize\n      return 0\n    }\n    function _proc_exit(code) {\n      EXITSTATUS = code\n      if (!keepRuntimeAlive()) {\n        if (Module['onExit']) Module['onExit'](code)\n        ABORT = true\n      }\n      quit_(code, new ExitStatus(code))\n    }\n    function exitJS(status, implicit) {\n      EXITSTATUS = status\n      _proc_exit(status)\n    }\n    var _exit = exitJS\n    function _fd_close(fd) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.close(stream)\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doReadv(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.read(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n        if (curr < len) break\n      }\n      return ret\n    }\n    function _fd_read(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doReadv(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function convertI32PairToI53Checked(lo, hi) {\n      return (hi + 2097152) >>> 0 < 4194305 - !!lo\n        ? (lo >>> 0) + hi * 4294967296\n        : NaN\n    }\n    function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {\n      try {\n        var offset = convertI32PairToI53Checked(offset_low, offset_high)\n        if (isNaN(offset)) return 61\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.llseek(stream, offset, whence)\n        ;(tempI64 = [\n          stream.position >>> 0,\n          ((tempDouble = stream.position),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[newOffset >> 2] = tempI64[0]),\n          (HEAP32[(newOffset + 4) >> 2] = tempI64[1])\n        if (stream.getdents && offset === 0 && whence === 0)\n          stream.getdents = null\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doWritev(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.write(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n      }\n      return ret\n    }\n    function _fd_write(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doWritev(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function __isLeapYear(year) {\n      return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n    }\n    function __arraySum(array, index) {\n      var sum = 0\n      for (var i = 0; i <= index; sum += array[i++]) {}\n      return sum\n    }\n    var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    function __addDays(date, days) {\n      var newDate = new Date(date.getTime())\n      while (days > 0) {\n        var leap = __isLeapYear(newDate.getFullYear())\n        var currentMonth = newDate.getMonth()\n        var daysInCurrentMonth = (leap\n          ? __MONTH_DAYS_LEAP\n          : __MONTH_DAYS_REGULAR)[currentMonth]\n        if (days > daysInCurrentMonth - newDate.getDate()) {\n          days -= daysInCurrentMonth - newDate.getDate() + 1\n          newDate.setDate(1)\n          if (currentMonth < 11) {\n            newDate.setMonth(currentMonth + 1)\n          } else {\n            newDate.setMonth(0)\n            newDate.setFullYear(newDate.getFullYear() + 1)\n          }\n        } else {\n          newDate.setDate(newDate.getDate() + days)\n          return newDate\n        }\n      }\n      return newDate\n    }\n    function writeArrayToMemory(array, buffer) {\n      HEAP8.set(array, buffer)\n    }\n    function _strftime(s, maxsize, format, tm) {\n      var tm_zone = HEAP32[(tm + 40) >> 2]\n      var date = {\n        tm_sec: HEAP32[tm >> 2],\n        tm_min: HEAP32[(tm + 4) >> 2],\n        tm_hour: HEAP32[(tm + 8) >> 2],\n        tm_mday: HEAP32[(tm + 12) >> 2],\n        tm_mon: HEAP32[(tm + 16) >> 2],\n        tm_year: HEAP32[(tm + 20) >> 2],\n        tm_wday: HEAP32[(tm + 24) >> 2],\n        tm_yday: HEAP32[(tm + 28) >> 2],\n        tm_isdst: HEAP32[(tm + 32) >> 2],\n        tm_gmtoff: HEAP32[(tm + 36) >> 2],\n        tm_zone: tm_zone ? UTF8ToString(tm_zone) : '',\n      }\n      var pattern = UTF8ToString(format)\n      var EXPANSION_RULES_1 = {\n        '%c': '%a %b %d %H:%M:%S %Y',\n        '%D': '%m/%d/%y',\n        '%F': '%Y-%m-%d',\n        '%h': '%b',\n        '%r': '%I:%M:%S %p',\n        '%R': '%H:%M',\n        '%T': '%H:%M:%S',\n        '%x': '%m/%d/%y',\n        '%X': '%H:%M:%S',\n        '%Ec': '%c',\n        '%EC': '%C',\n        '%Ex': '%m/%d/%y',\n        '%EX': '%H:%M:%S',\n        '%Ey': '%y',\n        '%EY': '%Y',\n        '%Od': '%d',\n        '%Oe': '%e',\n        '%OH': '%H',\n        '%OI': '%I',\n        '%Om': '%m',\n        '%OM': '%M',\n        '%OS': '%S',\n        '%Ou': '%u',\n        '%OU': '%U',\n        '%OV': '%V',\n        '%Ow': '%w',\n        '%OW': '%W',\n        '%Oy': '%y',\n      }\n      for (var rule in EXPANSION_RULES_1) {\n        pattern = pattern.replace(\n          new RegExp(rule, 'g'),\n          EXPANSION_RULES_1[rule]\n        )\n      }\n      var WEEKDAYS = [\n        'Sunday',\n        'Monday',\n        'Tuesday',\n        'Wednesday',\n        'Thursday',\n        'Friday',\n        'Saturday',\n      ]\n      var MONTHS = [\n        'January',\n        'February',\n        'March',\n        'April',\n        'May',\n        'June',\n        'July',\n        'August',\n        'September',\n        'October',\n        'November',\n        'December',\n      ]\n      function leadingSomething(value, digits, character) {\n        var str = typeof value == 'number' ? value.toString() : value || ''\n        while (str.length < digits) {\n          str = character[0] + str\n        }\n        return str\n      }\n      function leadingNulls(value, digits) {\n        return leadingSomething(value, digits, '0')\n      }\n      function compareByDay(date1, date2) {\n        function sgn(value) {\n          return value < 0 ? -1 : value > 0 ? 1 : 0\n        }\n        var compare\n        if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) {\n          if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) {\n            compare = sgn(date1.getDate() - date2.getDate())\n          }\n        }\n        return compare\n      }\n      function getFirstWeekStartDate(janFourth) {\n        switch (janFourth.getDay()) {\n          case 0:\n            return new Date(janFourth.getFullYear() - 1, 11, 29)\n          case 1:\n            return janFourth\n          case 2:\n            return new Date(janFourth.getFullYear(), 0, 3)\n          case 3:\n            return new Date(janFourth.getFullYear(), 0, 2)\n          case 4:\n            return new Date(janFourth.getFullYear(), 0, 1)\n          case 5:\n            return new Date(janFourth.getFullYear() - 1, 11, 31)\n          case 6:\n            return new Date(janFourth.getFullYear() - 1, 11, 30)\n        }\n      }\n      function getWeekBasedYear(date) {\n        var thisDate = __addDays(\n          new Date(date.tm_year + 1900, 0, 1),\n          date.tm_yday\n        )\n        var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4)\n        var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4)\n        var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear)\n        var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear)\n        if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {\n          if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {\n            return thisDate.getFullYear() + 1\n          }\n          return thisDate.getFullYear()\n        }\n        return thisDate.getFullYear() - 1\n      }\n      var EXPANSION_RULES_2 = {\n        '%a': function(date) {\n          return WEEKDAYS[date.tm_wday].substring(0, 3)\n        },\n        '%A': function(date) {\n          return WEEKDAYS[date.tm_wday]\n        },\n        '%b': function(date) {\n          return MONTHS[date.tm_mon].substring(0, 3)\n        },\n        '%B': function(date) {\n          return MONTHS[date.tm_mon]\n        },\n        '%C': function(date) {\n          var year = date.tm_year + 1900\n          return leadingNulls((year / 100) | 0, 2)\n        },\n        '%d': function(date) {\n          return leadingNulls(date.tm_mday, 2)\n        },\n        '%e': function(date) {\n          return leadingSomething(date.tm_mday, 2, ' ')\n        },\n        '%g': function(date) {\n          return getWeekBasedYear(date)\n            .toString()\n            .substring(2)\n        },\n        '%G': function(date) {\n          return getWeekBasedYear(date)\n        },\n        '%H': function(date) {\n          return leadingNulls(date.tm_hour, 2)\n        },\n        '%I': function(date) {\n          var twelveHour = date.tm_hour\n          if (twelveHour == 0) twelveHour = 12\n          else if (twelveHour > 12) twelveHour -= 12\n          return leadingNulls(twelveHour, 2)\n        },\n        '%j': function(date) {\n          return leadingNulls(\n            date.tm_mday +\n              __arraySum(\n                __isLeapYear(date.tm_year + 1900)\n                  ? __MONTH_DAYS_LEAP\n                  : __MONTH_DAYS_REGULAR,\n                date.tm_mon - 1\n              ),\n            3\n          )\n        },\n        '%m': function(date) {\n          return leadingNulls(date.tm_mon + 1, 2)\n        },\n        '%M': function(date) {\n          return leadingNulls(date.tm_min, 2)\n        },\n        '%n': function() {\n          return '\\n'\n        },\n        '%p': function(date) {\n          if (date.tm_hour >= 0 && date.tm_hour < 12) {\n            return 'AM'\n          }\n          return 'PM'\n        },\n        '%S': function(date) {\n          return leadingNulls(date.tm_sec, 2)\n        },\n        '%t': function() {\n          return '\\t'\n        },\n        '%u': function(date) {\n          return date.tm_wday || 7\n        },\n        '%U': function(date) {\n          var days = date.tm_yday + 7 - date.tm_wday\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%V': function(date) {\n          var val = Math.floor(\n            (date.tm_yday + 7 - ((date.tm_wday + 6) % 7)) / 7\n          )\n          if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) {\n            val++\n          }\n          if (!val) {\n            val = 52\n            var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7\n            if (\n              dec31 == 4 ||\n              (dec31 == 5 && __isLeapYear((date.tm_year % 400) - 1))\n            ) {\n              val++\n            }\n          } else if (val == 53) {\n            var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7\n            if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) val = 1\n          }\n          return leadingNulls(val, 2)\n        },\n        '%w': function(date) {\n          return date.tm_wday\n        },\n        '%W': function(date) {\n          var days = date.tm_yday + 7 - ((date.tm_wday + 6) % 7)\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%y': function(date) {\n          return (date.tm_year + 1900).toString().substring(2)\n        },\n        '%Y': function(date) {\n          return date.tm_year + 1900\n        },\n        '%z': function(date) {\n          var off = date.tm_gmtoff\n          var ahead = off >= 0\n          off = Math.abs(off) / 60\n          off = (off / 60) * 100 + (off % 60)\n          return (ahead ? '+' : '-') + String('0000' + off).slice(-4)\n        },\n        '%Z': function(date) {\n          return date.tm_zone\n        },\n        '%%': function() {\n          return '%'\n        },\n      }\n      pattern = pattern.replace(/%%/g, '\\0\\0')\n      for (var rule in EXPANSION_RULES_2) {\n        if (pattern.includes(rule)) {\n          pattern = pattern.replace(\n            new RegExp(rule, 'g'),\n            EXPANSION_RULES_2[rule](date)\n          )\n        }\n      }\n      pattern = pattern.replace(/\\0\\0/g, '%')\n      var bytes = intArrayFromString(pattern, false)\n      if (bytes.length > maxsize) {\n        return 0\n      }\n      writeArrayToMemory(bytes, s)\n      return bytes.length - 1\n    }\n    function _strftime_l(s, maxsize, format, tm, loc) {\n      return _strftime(s, maxsize, format, tm)\n    }\n    function handleException(e) {\n      if (e instanceof ExitStatus || e == 'unwind') {\n        return EXITSTATUS\n      }\n      quit_(1, e)\n    }\n    function allocateUTF8OnStack(str) {\n      var size = lengthBytesUTF8(str) + 1\n      var ret = stackAlloc(size)\n      stringToUTF8Array(str, HEAP8, ret, size)\n      return ret\n    }\n    function getCFunc(ident) {\n      var func = Module['_' + ident]\n      return func\n    }\n    function ccall(ident, returnType, argTypes, args, opts) {\n      var toC = {\n        string: str => {\n          var ret = 0\n          if (str !== null && str !== undefined && str !== 0) {\n            var len = (str.length << 2) + 1\n            ret = stackAlloc(len)\n            stringToUTF8(str, ret, len)\n          }\n          return ret\n        },\n        array: arr => {\n          var ret = stackAlloc(arr.length)\n          writeArrayToMemory(arr, ret)\n          return ret\n        },\n      }\n      function convertReturnValue(ret) {\n        if (returnType === 'string') {\n          return UTF8ToString(ret)\n        }\n        if (returnType === 'boolean') return Boolean(ret)\n        return ret\n      }\n      var func = getCFunc(ident)\n      var cArgs = []\n      var stack = 0\n      if (args) {\n        for (var i = 0; i < args.length; i++) {\n          var converter = toC[argTypes[i]]\n          if (converter) {\n            if (stack === 0) stack = stackSave()\n            cArgs[i] = converter(args[i])\n          } else {\n            cArgs[i] = args[i]\n          }\n        }\n      }\n      var ret = func.apply(null, cArgs)\n      function onDone(ret) {\n        if (stack !== 0) stackRestore(stack)\n        return convertReturnValue(ret)\n      }\n      ret = onDone(ret)\n      return ret\n    }\n    function cwrap(ident, returnType, argTypes, opts) {\n      argTypes = argTypes || []\n      var numericArgs = argTypes.every(\n        type => type === 'number' || type === 'boolean'\n      )\n      var numericRet = returnType !== 'string'\n      if (numericRet && numericArgs && !opts) {\n        return getCFunc(ident)\n      }\n      return function() {\n        return ccall(ident, returnType, argTypes, arguments, opts)\n      }\n    }\n    function AsciiToString(ptr) {\n      var str = ''\n      while (1) {\n        var ch = HEAPU8[ptr++ >> 0]\n        if (!ch) return str\n        str += String.fromCharCode(ch)\n      }\n    }\n    var FSNode = function(parent, name, mode, rdev) {\n      if (!parent) {\n        parent = this\n      }\n      this.parent = parent\n      this.mount = parent.mount\n      this.mounted = null\n      this.id = FS.nextInode++\n      this.name = name\n      this.mode = mode\n      this.node_ops = {}\n      this.stream_ops = {}\n      this.rdev = rdev\n    }\n    var readMode = 292 | 73\n    var writeMode = 146\n    Object.defineProperties(FSNode.prototype, {\n      read: {\n        get: function() {\n          return (this.mode & readMode) === readMode\n        },\n        set: function(val) {\n          val ? (this.mode |= readMode) : (this.mode &= ~readMode)\n        },\n      },\n      write: {\n        get: function() {\n          return (this.mode & writeMode) === writeMode\n        },\n        set: function(val) {\n          val ? (this.mode |= writeMode) : (this.mode &= ~writeMode)\n        },\n      },\n      isFolder: {\n        get: function() {\n          return FS.isDir(this.mode)\n        },\n      },\n      isDevice: {\n        get: function() {\n          return FS.isChrdev(this.mode)\n        },\n      },\n    })\n    FS.FSNode = FSNode\n    FS.staticInit()\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_unlink'] = FS.unlink\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    if (ENVIRONMENT_IS_NODE) {\n      NODEFS.staticInit()\n    }\n    ERRNO_CODES = {\n      EPERM: 63,\n      ENOENT: 44,\n      ESRCH: 71,\n      EINTR: 27,\n      EIO: 29,\n      ENXIO: 60,\n      E2BIG: 1,\n      ENOEXEC: 45,\n      EBADF: 8,\n      ECHILD: 12,\n      EAGAIN: 6,\n      EWOULDBLOCK: 6,\n      ENOMEM: 48,\n      EACCES: 2,\n      EFAULT: 21,\n      ENOTBLK: 105,\n      EBUSY: 10,\n      EEXIST: 20,\n      EXDEV: 75,\n      ENODEV: 43,\n      ENOTDIR: 54,\n      EISDIR: 31,\n      EINVAL: 28,\n      ENFILE: 41,\n      EMFILE: 33,\n      ENOTTY: 59,\n      ETXTBSY: 74,\n      EFBIG: 22,\n      ENOSPC: 51,\n      ESPIPE: 70,\n      EROFS: 69,\n      EMLINK: 34,\n      EPIPE: 64,\n      EDOM: 18,\n      ERANGE: 68,\n      ENOMSG: 49,\n      EIDRM: 24,\n      ECHRNG: 106,\n      EL2NSYNC: 156,\n      EL3HLT: 107,\n      EL3RST: 108,\n      ELNRNG: 109,\n      EUNATCH: 110,\n      ENOCSI: 111,\n      EL2HLT: 112,\n      EDEADLK: 16,\n      ENOLCK: 46,\n      EBADE: 113,\n      EBADR: 114,\n      EXFULL: 115,\n      ENOANO: 104,\n      EBADRQC: 103,\n      EBADSLT: 102,\n      EDEADLOCK: 16,\n      EBFONT: 101,\n      ENOSTR: 100,\n      ENODATA: 116,\n      ETIME: 117,\n      ENOSR: 118,\n      ENONET: 119,\n      ENOPKG: 120,\n      EREMOTE: 121,\n      ENOLINK: 47,\n      EADV: 122,\n      ESRMNT: 123,\n      ECOMM: 124,\n      EPROTO: 65,\n      EMULTIHOP: 36,\n      EDOTDOT: 125,\n      EBADMSG: 9,\n      ENOTUNIQ: 126,\n      EBADFD: 127,\n      EREMCHG: 128,\n      ELIBACC: 129,\n      ELIBBAD: 130,\n      ELIBSCN: 131,\n      ELIBMAX: 132,\n      ELIBEXEC: 133,\n      ENOSYS: 52,\n      ENOTEMPTY: 55,\n      ENAMETOOLONG: 37,\n      ELOOP: 32,\n      EOPNOTSUPP: 138,\n      EPFNOSUPPORT: 139,\n      ECONNRESET: 15,\n      ENOBUFS: 42,\n      EAFNOSUPPORT: 5,\n      EPROTOTYPE: 67,\n      ENOTSOCK: 57,\n      ENOPROTOOPT: 50,\n      ESHUTDOWN: 140,\n      ECONNREFUSED: 14,\n      EADDRINUSE: 3,\n      ECONNABORTED: 13,\n      ENETUNREACH: 40,\n      ENETDOWN: 38,\n      ETIMEDOUT: 73,\n      EHOSTDOWN: 142,\n      EHOSTUNREACH: 23,\n      EINPROGRESS: 26,\n      EALREADY: 7,\n      EDESTADDRREQ: 17,\n      EMSGSIZE: 35,\n      EPROTONOSUPPORT: 66,\n      ESOCKTNOSUPPORT: 137,\n      EADDRNOTAVAIL: 4,\n      ENETRESET: 39,\n      EISCONN: 30,\n      ENOTCONN: 53,\n      ETOOMANYREFS: 141,\n      EUSERS: 136,\n      EDQUOT: 19,\n      ESTALE: 72,\n      ENOTSUP: 138,\n      ENOMEDIUM: 148,\n      EILSEQ: 25,\n      EOVERFLOW: 61,\n      ECANCELED: 11,\n      ENOTRECOVERABLE: 56,\n      EOWNERDEAD: 62,\n      ESTRPIPE: 135,\n    }\n    var asmLibraryArg = {\n      a: ___cxa_throw,\n      d: ___syscall_fcntl64,\n      r: ___syscall_getcwd,\n      i: ___syscall_ioctl,\n      j: ___syscall_openat,\n      n: ___syscall_readlinkat,\n      o: ___syscall_stat64,\n      b: _abort,\n      f: _emscripten_memcpy_big,\n      m: _emscripten_resize_heap,\n      p: _environ_get,\n      q: _environ_sizes_get,\n      c: _exit,\n      e: _fd_close,\n      h: _fd_read,\n      k: _fd_seek,\n      g: _fd_write,\n      l: _strftime_l,\n    }\n    var asm = createWasm()\n    var ___wasm_call_ctors = (Module['___wasm_call_ctors'] = function() {\n      return (___wasm_call_ctors = Module['___wasm_call_ctors'] =\n        Module['asm']['t']).apply(null, arguments)\n    })\n    var _main = (Module['_main'] = function() {\n      return (_main = Module['_main'] = Module['asm']['u']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___errno_location = (Module['___errno_location'] = function() {\n      return (___errno_location = Module['___errno_location'] =\n        Module['asm']['v']).apply(null, arguments)\n    })\n    var _itk_wasm_input_array_alloc = (Module[\n      '_itk_wasm_input_array_alloc'\n    ] = function() {\n      return (_itk_wasm_input_array_alloc = Module[\n        '_itk_wasm_input_array_alloc'\n      ] = Module['asm']['w']).apply(null, arguments)\n    })\n    var _itk_wasm_input_json_alloc = (Module[\n      '_itk_wasm_input_json_alloc'\n    ] = function() {\n      return (_itk_wasm_input_json_alloc = Module[\n        '_itk_wasm_input_json_alloc'\n      ] = Module['asm']['x']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_address = (Module[\n      '_itk_wasm_output_json_address'\n    ] = function() {\n      return (_itk_wasm_output_json_address = Module[\n        '_itk_wasm_output_json_address'\n      ] = Module['asm']['y']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_size = (Module[\n      '_itk_wasm_output_json_size'\n    ] = function() {\n      return (_itk_wasm_output_json_size = Module[\n        '_itk_wasm_output_json_size'\n      ] = Module['asm']['z']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_address = (Module[\n      '_itk_wasm_output_array_address'\n    ] = function() {\n      return (_itk_wasm_output_array_address = Module[\n        '_itk_wasm_output_array_address'\n      ] = Module['asm']['A']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_size = (Module[\n      '_itk_wasm_output_array_size'\n    ] = function() {\n      return (_itk_wasm_output_array_size = Module[\n        '_itk_wasm_output_array_size'\n      ] = Module['asm']['B']).apply(null, arguments)\n    })\n    var _itk_wasm_free_all = (Module['_itk_wasm_free_all'] = function() {\n      return (_itk_wasm_free_all = Module['_itk_wasm_free_all'] =\n        Module['asm']['C']).apply(null, arguments)\n    })\n    var stackSave = (Module['stackSave'] = function() {\n      return (stackSave = Module['stackSave'] = Module['asm']['E']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackRestore = (Module['stackRestore'] = function() {\n      return (stackRestore = Module['stackRestore'] = Module['asm']['F']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackAlloc = (Module['stackAlloc'] = function() {\n      return (stackAlloc = Module['stackAlloc'] = Module['asm']['G']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___cxa_is_pointer_type = (Module[\n      '___cxa_is_pointer_type'\n    ] = function() {\n      return (___cxa_is_pointer_type = Module['___cxa_is_pointer_type'] =\n        Module['asm']['H']).apply(null, arguments)\n    })\n    Module['addRunDependency'] = addRunDependency\n    Module['removeRunDependency'] = removeRunDependency\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    Module['FS_unlink'] = FS.unlink\n    Module['callMain'] = callMain\n    Module['ccall'] = ccall\n    Module['cwrap'] = cwrap\n    Module['AsciiToString'] = AsciiToString\n    Module['writeArrayToMemory'] = writeArrayToMemory\n    Module['writeAsciiToMemory'] = writeAsciiToMemory\n    var calledRun\n    dependenciesFulfilled = function runCaller() {\n      if (!calledRun) run()\n      if (!calledRun) dependenciesFulfilled = runCaller\n    }\n    function callMain(args) {\n      var entryFunction = Module['_main']\n      args = args || []\n      args.unshift(thisProgram)\n      var argc = args.length\n      var argv = stackAlloc((argc + 1) * 4)\n      var argv_ptr = argv >> 2\n      args.forEach(arg => {\n        HEAP32[argv_ptr++] = allocateUTF8OnStack(arg)\n      })\n      HEAP32[argv_ptr] = 0\n      try {\n        var ret = entryFunction(argc, argv)\n        exitJS(ret, true)\n        return ret\n      } catch (e) {\n        return handleException(e)\n      }\n    }\n    function run(args) {\n      args = args || arguments_\n      if (runDependencies > 0) {\n        return\n      }\n      preRun()\n      if (runDependencies > 0) {\n        return\n      }\n      function doRun() {\n        if (calledRun) return\n        calledRun = true\n        Module['calledRun'] = true\n        if (ABORT) return\n        initRuntime()\n        preMain()\n        readyPromiseResolve(Module)\n        if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']()\n        if (shouldRunNow) callMain(args)\n        postRun()\n      }\n      if (Module['setStatus']) {\n        Module['setStatus']('Running...')\n        setTimeout(function() {\n          setTimeout(function() {\n            Module['setStatus']('')\n          }, 1)\n          doRun()\n        }, 1)\n      } else {\n        doRun()\n      }\n    }\n    if (Module['preInit']) {\n      if (typeof Module['preInit'] == 'function')\n        Module['preInit'] = [Module['preInit']]\n      while (Module['preInit'].length > 0) {\n        Module['preInit'].pop()()\n      }\n    }\n    var shouldRunNow = false\n    if (Module['noInitialRun']) shouldRunNow = false\n    run()\n    Module.mountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      if (FS.isDir(containingDir) || containingDir === '/') {\n        return\n      }\n      var currentDir = '/'\n      var splitContainingDir = containingDir.split(path.sep)\n      for (var ii = 1; ii < splitContainingDir.length; ii++) {\n        currentDir += splitContainingDir[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n      FS.mount(NODEFS, { root: containingDir }, currentDir)\n      return currentDir + path.basename(filePath)\n    }\n    Module.unmountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      FS.unmount(containingDir)\n    }\n    Module.fs_mkdirs = function(dirs) {\n      var currentDir = '/'\n      var splitDirs = dirs.split('/')\n      for (var ii = 1; ii < splitDirs.length; ++ii) {\n        currentDir += splitDirs[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n    }\n    Module.fs_readFile = function(path, opts) {\n      return FS.readFile(path, opts)\n    }\n    Module.fs_writeFile = function(path, data, opts) {\n      return FS.writeFile(path, data, opts)\n    }\n    Module.fs_unlink = function(path) {\n      return FS.unlink(path)\n    }\n    Module.fs_open = function(path, flags, mode) {\n      return FS.open(path, flags, mode)\n    }\n    Module.fs_stat = function(path) {\n      return FS.stat(path)\n    }\n    Module.fs_read = function(stream, buffer, offset, length, position) {\n      return FS.read(stream, buffer, offset, length, position)\n    }\n    Module.fs_close = function(stream) {\n      return FS.close(stream)\n    }\n\n    return Downsample.ready\n  }\n})()\nexport default Downsample\n"
  },
  {
    "path": "src/IO/Downsample/emscripten-build/Downsample.umd.js",
    "content": "var Downsample = (() => {\n  var _scriptDir =\n    typeof document !== 'undefined' && document.currentScript\n      ? document.currentScript.src\n      : undefined\n  if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename\n  return function(Downsample) {\n    Downsample = Downsample || {}\n\n    var Module = typeof Downsample != 'undefined' ? Downsample : {}\n    var readyPromiseResolve, readyPromiseReject\n    Module['ready'] = new Promise(function(resolve, reject) {\n      readyPromiseResolve = resolve\n      readyPromiseReject = reject\n    })\n    var mStdout = null\n    var mStderr = null\n    Module['resetModuleStdout'] = function() {\n      mStdout = ''\n    }\n    Module['resetModuleStderr'] = function() {\n      mStderr = ''\n    }\n    Module['print'] = function(text) {\n      console.log(text)\n      mStdout += text + '\\n'\n    }\n    Module['printErr'] = function(text) {\n      console.error(text)\n      mStderr += text + '\\n'\n    }\n    Module['getModuleStdout'] = function() {\n      return mStdout\n    }\n    Module['getModuleStderr'] = function() {\n      return mStderr\n    }\n    var moduleOverrides = Object.assign({}, Module)\n    var arguments_ = []\n    var thisProgram = './this.program'\n    var quit_ = (status, toThrow) => {\n      throw toThrow\n    }\n    var ENVIRONMENT_IS_WEB = typeof window == 'object'\n    var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'\n    var ENVIRONMENT_IS_NODE =\n      typeof process == 'object' &&\n      typeof process.versions == 'object' &&\n      typeof process.versions.node == 'string'\n    var scriptDirectory = ''\n    function locateFile(path) {\n      if (Module['locateFile']) {\n        return Module['locateFile'](path, scriptDirectory)\n      }\n      return scriptDirectory + path\n    }\n    var read_, readAsync, readBinary, setWindowTitle\n    function logExceptionOnExit(e) {\n      if (e instanceof ExitStatus) return\n      let toLog = e\n      err('exiting due to exception: ' + toLog)\n    }\n    if (ENVIRONMENT_IS_NODE) {\n      var fs = require('fs')\n      var nodePath = require('path')\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = nodePath.dirname(scriptDirectory) + '/'\n      } else {\n        scriptDirectory = __dirname + '/'\n      }\n      read_ = (filename, binary) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        return fs.readFileSync(filename, binary ? undefined : 'utf8')\n      }\n      readBinary = filename => {\n        var ret = read_(filename, true)\n        if (!ret.buffer) {\n          ret = new Uint8Array(ret)\n        }\n        return ret\n      }\n      readAsync = (filename, onload, onerror) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        fs.readFile(filename, function(err, data) {\n          if (err) onerror(err)\n          else onload(data.buffer)\n        })\n      }\n      if (process['argv'].length > 1) {\n        thisProgram = process['argv'][1].replace(/\\\\/g, '/')\n      }\n      arguments_ = process['argv'].slice(2)\n      process['on']('uncaughtException', function(ex) {\n        if (!(ex instanceof ExitStatus)) {\n          throw ex\n        }\n      })\n      process['on']('unhandledRejection', function(reason) {\n        throw reason\n      })\n      quit_ = (status, toThrow) => {\n        if (keepRuntimeAlive()) {\n          process['exitCode'] = status\n          throw toThrow\n        }\n        logExceptionOnExit(toThrow)\n        process['exit'](status)\n      }\n      Module['inspect'] = function() {\n        return '[Emscripten Module object]'\n      }\n    } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = self.location.href\n      } else if (typeof document != 'undefined' && document.currentScript) {\n        scriptDirectory = document.currentScript.src\n      }\n      if (_scriptDir) {\n        scriptDirectory = _scriptDir\n      }\n      if (scriptDirectory.indexOf('blob:') !== 0) {\n        scriptDirectory = scriptDirectory.substr(\n          0,\n          scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1\n        )\n      } else {\n        scriptDirectory = ''\n      }\n      {\n        read_ = url => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, false)\n          xhr.send(null)\n          return xhr.responseText\n        }\n        if (ENVIRONMENT_IS_WORKER) {\n          readBinary = url => {\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            xhr.responseType = 'arraybuffer'\n            xhr.send(null)\n            return new Uint8Array(xhr.response)\n          }\n        }\n        readAsync = (url, onload, onerror) => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, true)\n          xhr.responseType = 'arraybuffer'\n          xhr.onload = () => {\n            if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n              onload(xhr.response)\n              return\n            }\n            onerror()\n          }\n          xhr.onerror = onerror\n          xhr.send(null)\n        }\n      }\n      setWindowTitle = title => (document.title = title)\n    } else {\n    }\n    var out = Module['print'] || console.log.bind(console)\n    var err = Module['printErr'] || console.warn.bind(console)\n    Object.assign(Module, moduleOverrides)\n    moduleOverrides = null\n    if (Module['arguments']) arguments_ = Module['arguments']\n    if (Module['thisProgram']) thisProgram = Module['thisProgram']\n    if (Module['quit']) quit_ = Module['quit']\n    var wasmBinary\n    if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']\n    var noExitRuntime = Module['noExitRuntime'] || true\n    if (typeof WebAssembly != 'object') {\n      abort('no native wasm support detected')\n    }\n    var wasmMemory\n    var ABORT = false\n    var EXITSTATUS\n    function assert(condition, text) {\n      if (!condition) {\n        abort(text)\n      }\n    }\n    var UTF8Decoder =\n      typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined\n    function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {\n      var endIdx = idx + maxBytesToRead\n      var endPtr = idx\n      while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr\n      if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {\n        return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr))\n      }\n      var str = ''\n      while (idx < endPtr) {\n        var u0 = heapOrArray[idx++]\n        if (!(u0 & 128)) {\n          str += String.fromCharCode(u0)\n          continue\n        }\n        var u1 = heapOrArray[idx++] & 63\n        if ((u0 & 224) == 192) {\n          str += String.fromCharCode(((u0 & 31) << 6) | u1)\n          continue\n        }\n        var u2 = heapOrArray[idx++] & 63\n        if ((u0 & 240) == 224) {\n          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2\n        } else {\n          u0 =\n            ((u0 & 7) << 18) |\n            (u1 << 12) |\n            (u2 << 6) |\n            (heapOrArray[idx++] & 63)\n        }\n        if (u0 < 65536) {\n          str += String.fromCharCode(u0)\n        } else {\n          var ch = u0 - 65536\n          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023))\n        }\n      }\n      return str\n    }\n    function UTF8ToString(ptr, maxBytesToRead) {\n      return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''\n    }\n    function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {\n      if (!(maxBytesToWrite > 0)) return 0\n      var startIdx = outIdx\n      var endIdx = outIdx + maxBytesToWrite - 1\n      for (var i = 0; i < str.length; ++i) {\n        var u = str.charCodeAt(i)\n        if (u >= 55296 && u <= 57343) {\n          var u1 = str.charCodeAt(++i)\n          u = (65536 + ((u & 1023) << 10)) | (u1 & 1023)\n        }\n        if (u <= 127) {\n          if (outIdx >= endIdx) break\n          heap[outIdx++] = u\n        } else if (u <= 2047) {\n          if (outIdx + 1 >= endIdx) break\n          heap[outIdx++] = 192 | (u >> 6)\n          heap[outIdx++] = 128 | (u & 63)\n        } else if (u <= 65535) {\n          if (outIdx + 2 >= endIdx) break\n          heap[outIdx++] = 224 | (u >> 12)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        } else {\n          if (outIdx + 3 >= endIdx) break\n          heap[outIdx++] = 240 | (u >> 18)\n          heap[outIdx++] = 128 | ((u >> 12) & 63)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        }\n      }\n      heap[outIdx] = 0\n      return outIdx - startIdx\n    }\n    function stringToUTF8(str, outPtr, maxBytesToWrite) {\n      return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite)\n    }\n    function lengthBytesUTF8(str) {\n      var len = 0\n      for (var i = 0; i < str.length; ++i) {\n        var c = str.charCodeAt(i)\n        if (c <= 127) {\n          len++\n        } else if (c <= 2047) {\n          len += 2\n        } else if (c >= 55296 && c <= 57343) {\n          len += 4\n          ++i\n        } else {\n          len += 3\n        }\n      }\n      return len\n    }\n    var buffer,\n      HEAP8,\n      HEAPU8,\n      HEAP16,\n      HEAPU16,\n      HEAP32,\n      HEAPU32,\n      HEAPF32,\n      HEAPF64\n    function updateGlobalBufferAndViews(buf) {\n      buffer = buf\n      Module['HEAP8'] = HEAP8 = new Int8Array(buf)\n      Module['HEAP16'] = HEAP16 = new Int16Array(buf)\n      Module['HEAP32'] = HEAP32 = new Int32Array(buf)\n      Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf)\n      Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf)\n      Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf)\n      Module['HEAPF32'] = HEAPF32 = new Float32Array(buf)\n      Module['HEAPF64'] = HEAPF64 = new Float64Array(buf)\n    }\n    var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216\n    var wasmTable\n    var __ATPRERUN__ = []\n    var __ATINIT__ = []\n    var __ATMAIN__ = []\n    var __ATPOSTRUN__ = []\n    var runtimeInitialized = false\n    function keepRuntimeAlive() {\n      return noExitRuntime\n    }\n    function preRun() {\n      if (Module['preRun']) {\n        if (typeof Module['preRun'] == 'function')\n          Module['preRun'] = [Module['preRun']]\n        while (Module['preRun'].length) {\n          addOnPreRun(Module['preRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPRERUN__)\n    }\n    function initRuntime() {\n      runtimeInitialized = true\n      if (!Module['noFSInit'] && !FS.init.initialized) FS.init()\n      FS.ignorePermissions = false\n      TTY.init()\n      callRuntimeCallbacks(__ATINIT__)\n    }\n    function preMain() {\n      callRuntimeCallbacks(__ATMAIN__)\n    }\n    function postRun() {\n      if (Module['postRun']) {\n        if (typeof Module['postRun'] == 'function')\n          Module['postRun'] = [Module['postRun']]\n        while (Module['postRun'].length) {\n          addOnPostRun(Module['postRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPOSTRUN__)\n    }\n    function addOnPreRun(cb) {\n      __ATPRERUN__.unshift(cb)\n    }\n    function addOnInit(cb) {\n      __ATINIT__.unshift(cb)\n    }\n    function addOnPostRun(cb) {\n      __ATPOSTRUN__.unshift(cb)\n    }\n    var runDependencies = 0\n    var runDependencyWatcher = null\n    var dependenciesFulfilled = null\n    function getUniqueRunDependency(id) {\n      return id\n    }\n    function addRunDependency(id) {\n      runDependencies++\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n    }\n    function removeRunDependency(id) {\n      runDependencies--\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n      if (runDependencies == 0) {\n        if (runDependencyWatcher !== null) {\n          clearInterval(runDependencyWatcher)\n          runDependencyWatcher = null\n        }\n        if (dependenciesFulfilled) {\n          var callback = dependenciesFulfilled\n          dependenciesFulfilled = null\n          callback()\n        }\n      }\n    }\n    function abort(what) {\n      if (Module['onAbort']) {\n        Module['onAbort'](what)\n      }\n      what = 'Aborted(' + what + ')'\n      err(what)\n      ABORT = true\n      EXITSTATUS = 1\n      what += '. Build with -sASSERTIONS for more info.'\n      var e = new WebAssembly.RuntimeError(what)\n      readyPromiseReject(e)\n      throw e\n    }\n    var dataURIPrefix = 'data:application/octet-stream;base64,'\n    function isDataURI(filename) {\n      return filename.startsWith(dataURIPrefix)\n    }\n    function isFileURI(filename) {\n      return filename.startsWith('file://')\n    }\n    var wasmBinaryFile\n    wasmBinaryFile = 'Downsample.umd.wasm'\n    if (!isDataURI(wasmBinaryFile)) {\n      wasmBinaryFile = locateFile(wasmBinaryFile)\n    }\n    function getBinary(file) {\n      try {\n        if (file == wasmBinaryFile && wasmBinary) {\n          return new Uint8Array(wasmBinary)\n        }\n        if (readBinary) {\n          return readBinary(file)\n        }\n        throw 'both async and sync fetching of the wasm failed'\n      } catch (err) {\n        abort(err)\n      }\n    }\n    function getBinaryPromise() {\n      if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {\n        if (typeof fetch == 'function' && !isFileURI(wasmBinaryFile)) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' })\n            .then(function(response) {\n              if (!response['ok']) {\n                throw \"failed to load wasm binary file at '\" +\n                  wasmBinaryFile +\n                  \"'\"\n              }\n              return response['arrayBuffer']()\n            })\n            .catch(function() {\n              return getBinary(wasmBinaryFile)\n            })\n        } else {\n          if (readAsync) {\n            return new Promise(function(resolve, reject) {\n              readAsync(\n                wasmBinaryFile,\n                function(response) {\n                  resolve(new Uint8Array(response))\n                },\n                reject\n              )\n            })\n          }\n        }\n      }\n      return Promise.resolve().then(function() {\n        return getBinary(wasmBinaryFile)\n      })\n    }\n    function createWasm() {\n      var info = { a: asmLibraryArg }\n      function receiveInstance(instance, module) {\n        var exports = instance.exports\n        Module['asm'] = exports\n        wasmMemory = Module['asm']['s']\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        wasmTable = Module['asm']['D']\n        addOnInit(Module['asm']['t'])\n        removeRunDependency('wasm-instantiate')\n      }\n      addRunDependency('wasm-instantiate')\n      function receiveInstantiationResult(result) {\n        receiveInstance(result['instance'])\n      }\n      function instantiateArrayBuffer(receiver) {\n        return getBinaryPromise()\n          .then(function(binary) {\n            return WebAssembly.instantiate(binary, info)\n          })\n          .then(function(instance) {\n            return instance\n          })\n          .then(receiver, function(reason) {\n            err('failed to asynchronously prepare wasm: ' + reason)\n            abort(reason)\n          })\n      }\n      function instantiateAsync() {\n        if (\n          !wasmBinary &&\n          typeof WebAssembly.instantiateStreaming == 'function' &&\n          !isDataURI(wasmBinaryFile) &&\n          !isFileURI(wasmBinaryFile) &&\n          !ENVIRONMENT_IS_NODE &&\n          typeof fetch == 'function'\n        ) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(\n            function(response) {\n              var result = WebAssembly.instantiateStreaming(response, info)\n              return result.then(receiveInstantiationResult, function(reason) {\n                err('wasm streaming compile failed: ' + reason)\n                err('falling back to ArrayBuffer instantiation')\n                return instantiateArrayBuffer(receiveInstantiationResult)\n              })\n            }\n          )\n        } else {\n          return instantiateArrayBuffer(receiveInstantiationResult)\n        }\n      }\n      if (Module['instantiateWasm']) {\n        try {\n          var exports = Module['instantiateWasm'](info, receiveInstance)\n          return exports\n        } catch (e) {\n          err('Module.instantiateWasm callback failed with error: ' + e)\n          readyPromiseReject(e)\n        }\n      }\n      instantiateAsync().catch(readyPromiseReject)\n      return {}\n    }\n    var tempDouble\n    var tempI64\n    function ExitStatus(status) {\n      this.name = 'ExitStatus'\n      this.message = 'Program terminated with exit(' + status + ')'\n      this.status = status\n    }\n    function callRuntimeCallbacks(callbacks) {\n      while (callbacks.length > 0) {\n        callbacks.shift()(Module)\n      }\n    }\n    function ExceptionInfo(excPtr) {\n      this.excPtr = excPtr\n      this.ptr = excPtr - 24\n      this.set_type = function(type) {\n        HEAPU32[(this.ptr + 4) >> 2] = type\n      }\n      this.get_type = function() {\n        return HEAPU32[(this.ptr + 4) >> 2]\n      }\n      this.set_destructor = function(destructor) {\n        HEAPU32[(this.ptr + 8) >> 2] = destructor\n      }\n      this.get_destructor = function() {\n        return HEAPU32[(this.ptr + 8) >> 2]\n      }\n      this.set_refcount = function(refcount) {\n        HEAP32[this.ptr >> 2] = refcount\n      }\n      this.set_caught = function(caught) {\n        caught = caught ? 1 : 0\n        HEAP8[(this.ptr + 12) >> 0] = caught\n      }\n      this.get_caught = function() {\n        return HEAP8[(this.ptr + 12) >> 0] != 0\n      }\n      this.set_rethrown = function(rethrown) {\n        rethrown = rethrown ? 1 : 0\n        HEAP8[(this.ptr + 13) >> 0] = rethrown\n      }\n      this.get_rethrown = function() {\n        return HEAP8[(this.ptr + 13) >> 0] != 0\n      }\n      this.init = function(type, destructor) {\n        this.set_adjusted_ptr(0)\n        this.set_type(type)\n        this.set_destructor(destructor)\n        this.set_refcount(0)\n        this.set_caught(false)\n        this.set_rethrown(false)\n      }\n      this.add_ref = function() {\n        var value = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = value + 1\n      }\n      this.release_ref = function() {\n        var prev = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = prev - 1\n        return prev === 1\n      }\n      this.set_adjusted_ptr = function(adjustedPtr) {\n        HEAPU32[(this.ptr + 16) >> 2] = adjustedPtr\n      }\n      this.get_adjusted_ptr = function() {\n        return HEAPU32[(this.ptr + 16) >> 2]\n      }\n      this.get_exception_ptr = function() {\n        var isPointer = ___cxa_is_pointer_type(this.get_type())\n        if (isPointer) {\n          return HEAPU32[this.excPtr >> 2]\n        }\n        var adjusted = this.get_adjusted_ptr()\n        if (adjusted !== 0) return adjusted\n        return this.excPtr\n      }\n    }\n    var exceptionLast = 0\n    var uncaughtExceptionCount = 0\n    function ___cxa_throw(ptr, type, destructor) {\n      var info = new ExceptionInfo(ptr)\n      info.init(type, destructor)\n      exceptionLast = ptr\n      uncaughtExceptionCount++\n      throw ptr\n    }\n    function setErrNo(value) {\n      HEAP32[___errno_location() >> 2] = value\n      return value\n    }\n    var PATH = {\n      isAbs: path => path.charAt(0) === '/',\n      splitPath: filename => {\n        var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/\n        return splitPathRe.exec(filename).slice(1)\n      },\n      normalizeArray: (parts, allowAboveRoot) => {\n        var up = 0\n        for (var i = parts.length - 1; i >= 0; i--) {\n          var last = parts[i]\n          if (last === '.') {\n            parts.splice(i, 1)\n          } else if (last === '..') {\n            parts.splice(i, 1)\n            up++\n          } else if (up) {\n            parts.splice(i, 1)\n            up--\n          }\n        }\n        if (allowAboveRoot) {\n          for (; up; up--) {\n            parts.unshift('..')\n          }\n        }\n        return parts\n      },\n      normalize: path => {\n        var isAbsolute = PATH.isAbs(path),\n          trailingSlash = path.substr(-1) === '/'\n        path = PATH.normalizeArray(\n          path.split('/').filter(p => !!p),\n          !isAbsolute\n        ).join('/')\n        if (!path && !isAbsolute) {\n          path = '.'\n        }\n        if (path && trailingSlash) {\n          path += '/'\n        }\n        return (isAbsolute ? '/' : '') + path\n      },\n      dirname: path => {\n        var result = PATH.splitPath(path),\n          root = result[0],\n          dir = result[1]\n        if (!root && !dir) {\n          return '.'\n        }\n        if (dir) {\n          dir = dir.substr(0, dir.length - 1)\n        }\n        return root + dir\n      },\n      basename: path => {\n        if (path === '/') return '/'\n        path = PATH.normalize(path)\n        path = path.replace(/\\/$/, '')\n        var lastSlash = path.lastIndexOf('/')\n        if (lastSlash === -1) return path\n        return path.substr(lastSlash + 1)\n      },\n      join: function() {\n        var paths = Array.prototype.slice.call(arguments)\n        return PATH.normalize(paths.join('/'))\n      },\n      join2: (l, r) => {\n        return PATH.normalize(l + '/' + r)\n      },\n    }\n    function getRandomDevice() {\n      if (\n        typeof crypto == 'object' &&\n        typeof crypto['getRandomValues'] == 'function'\n      ) {\n        var randomBuffer = new Uint8Array(1)\n        return () => {\n          crypto.getRandomValues(randomBuffer)\n          return randomBuffer[0]\n        }\n      } else if (ENVIRONMENT_IS_NODE) {\n        try {\n          var crypto_module = require('crypto')\n          return () => crypto_module['randomBytes'](1)[0]\n        } catch (e) {}\n      }\n      return () => abort('randomDevice')\n    }\n    var PATH_FS = {\n      resolve: function() {\n        var resolvedPath = '',\n          resolvedAbsolute = false\n        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n          var path = i >= 0 ? arguments[i] : FS.cwd()\n          if (typeof path != 'string') {\n            throw new TypeError('Arguments to path.resolve must be strings')\n          } else if (!path) {\n            return ''\n          }\n          resolvedPath = path + '/' + resolvedPath\n          resolvedAbsolute = PATH.isAbs(path)\n        }\n        resolvedPath = PATH.normalizeArray(\n          resolvedPath.split('/').filter(p => !!p),\n          !resolvedAbsolute\n        ).join('/')\n        return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'\n      },\n      relative: (from, to) => {\n        from = PATH_FS.resolve(from).substr(1)\n        to = PATH_FS.resolve(to).substr(1)\n        function trim(arr) {\n          var start = 0\n          for (; start < arr.length; start++) {\n            if (arr[start] !== '') break\n          }\n          var end = arr.length - 1\n          for (; end >= 0; end--) {\n            if (arr[end] !== '') break\n          }\n          if (start > end) return []\n          return arr.slice(start, end - start + 1)\n        }\n        var fromParts = trim(from.split('/'))\n        var toParts = trim(to.split('/'))\n        var length = Math.min(fromParts.length, toParts.length)\n        var samePartsLength = length\n        for (var i = 0; i < length; i++) {\n          if (fromParts[i] !== toParts[i]) {\n            samePartsLength = i\n            break\n          }\n        }\n        var outputParts = []\n        for (var i = samePartsLength; i < fromParts.length; i++) {\n          outputParts.push('..')\n        }\n        outputParts = outputParts.concat(toParts.slice(samePartsLength))\n        return outputParts.join('/')\n      },\n    }\n    function intArrayFromString(stringy, dontAddNull, length) {\n      var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1\n      var u8array = new Array(len)\n      var numBytesWritten = stringToUTF8Array(\n        stringy,\n        u8array,\n        0,\n        u8array.length\n      )\n      if (dontAddNull) u8array.length = numBytesWritten\n      return u8array\n    }\n    var TTY = {\n      ttys: [],\n      init: function() {},\n      shutdown: function() {},\n      register: function(dev, ops) {\n        TTY.ttys[dev] = { input: [], output: [], ops: ops }\n        FS.registerDevice(dev, TTY.stream_ops)\n      },\n      stream_ops: {\n        open: function(stream) {\n          var tty = TTY.ttys[stream.node.rdev]\n          if (!tty) {\n            throw new FS.ErrnoError(43)\n          }\n          stream.tty = tty\n          stream.seekable = false\n        },\n        close: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        fsync: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        read: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.get_char) {\n            throw new FS.ErrnoError(60)\n          }\n          var bytesRead = 0\n          for (var i = 0; i < length; i++) {\n            var result\n            try {\n              result = stream.tty.ops.get_char(stream.tty)\n            } catch (e) {\n              throw new FS.ErrnoError(29)\n            }\n            if (result === undefined && bytesRead === 0) {\n              throw new FS.ErrnoError(6)\n            }\n            if (result === null || result === undefined) break\n            bytesRead++\n            buffer[offset + i] = result\n          }\n          if (bytesRead) {\n            stream.node.timestamp = Date.now()\n          }\n          return bytesRead\n        },\n        write: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.put_char) {\n            throw new FS.ErrnoError(60)\n          }\n          try {\n            for (var i = 0; i < length; i++) {\n              stream.tty.ops.put_char(stream.tty, buffer[offset + i])\n            }\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n          if (length) {\n            stream.node.timestamp = Date.now()\n          }\n          return i\n        },\n      },\n      default_tty_ops: {\n        get_char: function(tty) {\n          if (!tty.input.length) {\n            var result = null\n            if (ENVIRONMENT_IS_NODE) {\n              var BUFSIZE = 256\n              var buf = Buffer.alloc(BUFSIZE)\n              var bytesRead = 0\n              try {\n                bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, -1)\n              } catch (e) {\n                if (e.toString().includes('EOF')) bytesRead = 0\n                else throw e\n              }\n              if (bytesRead > 0) {\n                result = buf.slice(0, bytesRead).toString('utf-8')\n              } else {\n                result = null\n              }\n            } else if (\n              typeof window != 'undefined' &&\n              typeof window.prompt == 'function'\n            ) {\n              result = window.prompt('Input: ')\n              if (result !== null) {\n                result += '\\n'\n              }\n            } else if (typeof readline == 'function') {\n              result = readline()\n              if (result !== null) {\n                result += '\\n'\n              }\n            }\n            if (!result) {\n              return null\n            }\n            tty.input = intArrayFromString(result, true)\n          }\n          return tty.input.shift()\n        },\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n      default_tty1_ops: {\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n    }\n    function mmapAlloc(size) {\n      abort()\n    }\n    var MEMFS = {\n      ops_table: null,\n      mount: function(mount) {\n        return MEMFS.createNode(null, '/', 16384 | 511, 0)\n      },\n      createNode: function(parent, name, mode, dev) {\n        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n          throw new FS.ErrnoError(63)\n        }\n        if (!MEMFS.ops_table) {\n          MEMFS.ops_table = {\n            dir: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                lookup: MEMFS.node_ops.lookup,\n                mknod: MEMFS.node_ops.mknod,\n                rename: MEMFS.node_ops.rename,\n                unlink: MEMFS.node_ops.unlink,\n                rmdir: MEMFS.node_ops.rmdir,\n                readdir: MEMFS.node_ops.readdir,\n                symlink: MEMFS.node_ops.symlink,\n              },\n              stream: { llseek: MEMFS.stream_ops.llseek },\n            },\n            file: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: {\n                llseek: MEMFS.stream_ops.llseek,\n                read: MEMFS.stream_ops.read,\n                write: MEMFS.stream_ops.write,\n                allocate: MEMFS.stream_ops.allocate,\n                mmap: MEMFS.stream_ops.mmap,\n                msync: MEMFS.stream_ops.msync,\n              },\n            },\n            link: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                readlink: MEMFS.node_ops.readlink,\n              },\n              stream: {},\n            },\n            chrdev: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: FS.chrdev_stream_ops,\n            },\n          }\n        }\n        var node = FS.createNode(parent, name, mode, dev)\n        if (FS.isDir(node.mode)) {\n          node.node_ops = MEMFS.ops_table.dir.node\n          node.stream_ops = MEMFS.ops_table.dir.stream\n          node.contents = {}\n        } else if (FS.isFile(node.mode)) {\n          node.node_ops = MEMFS.ops_table.file.node\n          node.stream_ops = MEMFS.ops_table.file.stream\n          node.usedBytes = 0\n          node.contents = null\n        } else if (FS.isLink(node.mode)) {\n          node.node_ops = MEMFS.ops_table.link.node\n          node.stream_ops = MEMFS.ops_table.link.stream\n        } else if (FS.isChrdev(node.mode)) {\n          node.node_ops = MEMFS.ops_table.chrdev.node\n          node.stream_ops = MEMFS.ops_table.chrdev.stream\n        }\n        node.timestamp = Date.now()\n        if (parent) {\n          parent.contents[name] = node\n          parent.timestamp = node.timestamp\n        }\n        return node\n      },\n      getFileDataAsTypedArray: function(node) {\n        if (!node.contents) return new Uint8Array(0)\n        if (node.contents.subarray)\n          return node.contents.subarray(0, node.usedBytes)\n        return new Uint8Array(node.contents)\n      },\n      expandFileStorage: function(node, newCapacity) {\n        var prevCapacity = node.contents ? node.contents.length : 0\n        if (prevCapacity >= newCapacity) return\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024\n        newCapacity = Math.max(\n          newCapacity,\n          (prevCapacity *\n            (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>>\n            0\n        )\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256)\n        var oldContents = node.contents\n        node.contents = new Uint8Array(newCapacity)\n        if (node.usedBytes > 0)\n          node.contents.set(oldContents.subarray(0, node.usedBytes), 0)\n      },\n      resizeFileStorage: function(node, newSize) {\n        if (node.usedBytes == newSize) return\n        if (newSize == 0) {\n          node.contents = null\n          node.usedBytes = 0\n        } else {\n          var oldContents = node.contents\n          node.contents = new Uint8Array(newSize)\n          if (oldContents) {\n            node.contents.set(\n              oldContents.subarray(0, Math.min(newSize, node.usedBytes))\n            )\n          }\n          node.usedBytes = newSize\n        }\n      },\n      node_ops: {\n        getattr: function(node) {\n          var attr = {}\n          attr.dev = FS.isChrdev(node.mode) ? node.id : 1\n          attr.ino = node.id\n          attr.mode = node.mode\n          attr.nlink = 1\n          attr.uid = 0\n          attr.gid = 0\n          attr.rdev = node.rdev\n          if (FS.isDir(node.mode)) {\n            attr.size = 4096\n          } else if (FS.isFile(node.mode)) {\n            attr.size = node.usedBytes\n          } else if (FS.isLink(node.mode)) {\n            attr.size = node.link.length\n          } else {\n            attr.size = 0\n          }\n          attr.atime = new Date(node.timestamp)\n          attr.mtime = new Date(node.timestamp)\n          attr.ctime = new Date(node.timestamp)\n          attr.blksize = 4096\n          attr.blocks = Math.ceil(attr.size / attr.blksize)\n          return attr\n        },\n        setattr: function(node, attr) {\n          if (attr.mode !== undefined) {\n            node.mode = attr.mode\n          }\n          if (attr.timestamp !== undefined) {\n            node.timestamp = attr.timestamp\n          }\n          if (attr.size !== undefined) {\n            MEMFS.resizeFileStorage(node, attr.size)\n          }\n        },\n        lookup: function(parent, name) {\n          throw FS.genericErrors[44]\n        },\n        mknod: function(parent, name, mode, dev) {\n          return MEMFS.createNode(parent, name, mode, dev)\n        },\n        rename: function(old_node, new_dir, new_name) {\n          if (FS.isDir(old_node.mode)) {\n            var new_node\n            try {\n              new_node = FS.lookupNode(new_dir, new_name)\n            } catch (e) {}\n            if (new_node) {\n              for (var i in new_node.contents) {\n                throw new FS.ErrnoError(55)\n              }\n            }\n          }\n          delete old_node.parent.contents[old_node.name]\n          old_node.parent.timestamp = Date.now()\n          old_node.name = new_name\n          new_dir.contents[new_name] = old_node\n          new_dir.timestamp = old_node.parent.timestamp\n          old_node.parent = new_dir\n        },\n        unlink: function(parent, name) {\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        rmdir: function(parent, name) {\n          var node = FS.lookupNode(parent, name)\n          for (var i in node.contents) {\n            throw new FS.ErrnoError(55)\n          }\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        readdir: function(node) {\n          var entries = ['.', '..']\n          for (var key in node.contents) {\n            if (!node.contents.hasOwnProperty(key)) {\n              continue\n            }\n            entries.push(key)\n          }\n          return entries\n        },\n        symlink: function(parent, newname, oldpath) {\n          var node = MEMFS.createNode(parent, newname, 511 | 40960, 0)\n          node.link = oldpath\n          return node\n        },\n        readlink: function(node) {\n          if (!FS.isLink(node.mode)) {\n            throw new FS.ErrnoError(28)\n          }\n          return node.link\n        },\n      },\n      stream_ops: {\n        read: function(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= stream.node.usedBytes) return 0\n          var size = Math.min(stream.node.usedBytes - position, length)\n          if (size > 8 && contents.subarray) {\n            buffer.set(contents.subarray(position, position + size), offset)\n          } else {\n            for (var i = 0; i < size; i++)\n              buffer[offset + i] = contents[position + i]\n          }\n          return size\n        },\n        write: function(stream, buffer, offset, length, position, canOwn) {\n          if (buffer.buffer === HEAP8.buffer) {\n            canOwn = false\n          }\n          if (!length) return 0\n          var node = stream.node\n          node.timestamp = Date.now()\n          if (buffer.subarray && (!node.contents || node.contents.subarray)) {\n            if (canOwn) {\n              node.contents = buffer.subarray(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (node.usedBytes === 0 && position === 0) {\n              node.contents = buffer.slice(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (position + length <= node.usedBytes) {\n              node.contents.set(\n                buffer.subarray(offset, offset + length),\n                position\n              )\n              return length\n            }\n          }\n          MEMFS.expandFileStorage(node, position + length)\n          if (node.contents.subarray && buffer.subarray) {\n            node.contents.set(\n              buffer.subarray(offset, offset + length),\n              position\n            )\n          } else {\n            for (var i = 0; i < length; i++) {\n              node.contents[position + i] = buffer[offset + i]\n            }\n          }\n          node.usedBytes = Math.max(node.usedBytes, position + length)\n          return length\n        },\n        llseek: function(stream, offset, whence) {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              position += stream.node.usedBytes\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        allocate: function(stream, offset, length) {\n          MEMFS.expandFileStorage(stream.node, offset + length)\n          stream.node.usedBytes = Math.max(\n            stream.node.usedBytes,\n            offset + length\n          )\n        },\n        mmap: function(stream, length, position, prot, flags) {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr\n          var allocated\n          var contents = stream.node.contents\n          if (!(flags & 2) && contents.buffer === buffer) {\n            allocated = false\n            ptr = contents.byteOffset\n          } else {\n            if (position > 0 || position + length < contents.length) {\n              if (contents.subarray) {\n                contents = contents.subarray(position, position + length)\n              } else {\n                contents = Array.prototype.slice.call(\n                  contents,\n                  position,\n                  position + length\n                )\n              }\n            }\n            allocated = true\n            ptr = mmapAlloc(length)\n            if (!ptr) {\n              throw new FS.ErrnoError(48)\n            }\n            HEAP8.set(contents, ptr)\n          }\n          return { ptr: ptr, allocated: allocated }\n        },\n        msync: function(stream, buffer, offset, length, mmapFlags) {\n          MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    function asyncLoad(url, onload, onerror, noRunDep) {\n      var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''\n      readAsync(\n        url,\n        arrayBuffer => {\n          assert(\n            arrayBuffer,\n            'Loading data file \"' + url + '\" failed (no arrayBuffer).'\n          )\n          onload(new Uint8Array(arrayBuffer))\n          if (dep) removeRunDependency(dep)\n        },\n        event => {\n          if (onerror) {\n            onerror()\n          } else {\n            throw 'Loading data file \"' + url + '\" failed.'\n          }\n        }\n      )\n      if (dep) addRunDependency(dep)\n    }\n    var ERRNO_CODES = {}\n    var NODEFS = {\n      isWindows: false,\n      staticInit: () => {\n        NODEFS.isWindows = !!process.platform.match(/^win/)\n        var flags = process['binding']('constants')\n        if (flags['fs']) {\n          flags = flags['fs']\n        }\n        NODEFS.flagsForNodeMap = {\n          1024: flags['O_APPEND'],\n          64: flags['O_CREAT'],\n          128: flags['O_EXCL'],\n          256: flags['O_NOCTTY'],\n          0: flags['O_RDONLY'],\n          2: flags['O_RDWR'],\n          4096: flags['O_SYNC'],\n          512: flags['O_TRUNC'],\n          1: flags['O_WRONLY'],\n          131072: flags['O_NOFOLLOW'],\n        }\n      },\n      convertNodeCode: e => {\n        var code = e.code\n        return ERRNO_CODES[code]\n      },\n      mount: mount => {\n        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0)\n      },\n      createNode: (parent, name, mode, dev) => {\n        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = FS.createNode(parent, name, mode)\n        node.node_ops = NODEFS.node_ops\n        node.stream_ops = NODEFS.stream_ops\n        return node\n      },\n      getMode: path => {\n        var stat\n        try {\n          stat = fs.lstatSync(path)\n          if (NODEFS.isWindows) {\n            stat.mode = stat.mode | ((stat.mode & 292) >> 2)\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n        }\n        return stat.mode\n      },\n      realPath: node => {\n        var parts = []\n        while (node.parent !== node) {\n          parts.push(node.name)\n          node = node.parent\n        }\n        parts.push(node.mount.opts.root)\n        parts.reverse()\n        return PATH.join.apply(null, parts)\n      },\n      flagsForNode: flags => {\n        flags &= ~2097152\n        flags &= ~2048\n        flags &= ~32768\n        flags &= ~524288\n        flags &= ~65536\n        var newFlags = 0\n        for (var k in NODEFS.flagsForNodeMap) {\n          if (flags & k) {\n            newFlags |= NODEFS.flagsForNodeMap[k]\n            flags ^= k\n          }\n        }\n        if (flags) {\n          throw new FS.ErrnoError(28)\n        }\n        return newFlags\n      },\n      node_ops: {\n        getattr: node => {\n          var path = NODEFS.realPath(node)\n          var stat\n          try {\n            stat = fs.lstatSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          if (NODEFS.isWindows && !stat.blksize) {\n            stat.blksize = 4096\n          }\n          if (NODEFS.isWindows && !stat.blocks) {\n            stat.blocks = ((stat.size + stat.blksize - 1) / stat.blksize) | 0\n          }\n          return {\n            dev: stat.dev,\n            ino: stat.ino,\n            mode: stat.mode,\n            nlink: stat.nlink,\n            uid: stat.uid,\n            gid: stat.gid,\n            rdev: stat.rdev,\n            size: stat.size,\n            atime: stat.atime,\n            mtime: stat.mtime,\n            ctime: stat.ctime,\n            blksize: stat.blksize,\n            blocks: stat.blocks,\n          }\n        },\n        setattr: (node, attr) => {\n          var path = NODEFS.realPath(node)\n          try {\n            if (attr.mode !== undefined) {\n              fs.chmodSync(path, attr.mode)\n              node.mode = attr.mode\n            }\n            if (attr.timestamp !== undefined) {\n              var date = new Date(attr.timestamp)\n              fs.utimesSync(path, date, date)\n            }\n            if (attr.size !== undefined) {\n              fs.truncateSync(path, attr.size)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        lookup: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          var mode = NODEFS.getMode(path)\n          return NODEFS.createNode(parent, name, mode)\n        },\n        mknod: (parent, name, mode, dev) => {\n          var node = NODEFS.createNode(parent, name, mode, dev)\n          var path = NODEFS.realPath(node)\n          try {\n            if (FS.isDir(node.mode)) {\n              fs.mkdirSync(path, node.mode)\n            } else {\n              fs.writeFileSync(path, '', { mode: node.mode })\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          return node\n        },\n        rename: (oldNode, newDir, newName) => {\n          var oldPath = NODEFS.realPath(oldNode)\n          var newPath = PATH.join2(NODEFS.realPath(newDir), newName)\n          try {\n            fs.renameSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          oldNode.name = newName\n        },\n        unlink: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.unlinkSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        rmdir: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.rmdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readdir: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            return fs.readdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        symlink: (parent, newName, oldPath) => {\n          var newPath = PATH.join2(NODEFS.realPath(parent), newName)\n          try {\n            fs.symlinkSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readlink: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            path = fs.readlinkSync(path)\n            path = nodePath.relative(\n              nodePath.resolve(node.mount.opts.root),\n              path\n            )\n            return path\n          } catch (e) {\n            if (!e.code) throw e\n            if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28)\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n      },\n      stream_ops: {\n        open: stream => {\n          var path = NODEFS.realPath(stream.node)\n          try {\n            if (FS.isFile(stream.node.mode)) {\n              stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags))\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        close: stream => {\n          try {\n            if (FS.isFile(stream.node.mode) && stream.nfd) {\n              fs.closeSync(stream.nfd)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        read: (stream, buffer, offset, length, position) => {\n          if (length === 0) return 0\n          try {\n            return fs.readSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        write: (stream, buffer, offset, length, position) => {\n          try {\n            return fs.writeSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        llseek: (stream, offset, whence) => {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              try {\n                var stat = fs.fstatSync(stream.nfd)\n                position += stat.size\n              } catch (e) {\n                throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n              }\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        mmap: (stream, length, position, prot, flags) => {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr = mmapAlloc(length)\n          NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        },\n        msync: (stream, buffer, offset, length, mmapFlags) => {\n          NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    var FS = {\n      root: null,\n      mounts: [],\n      devices: {},\n      streams: [],\n      nextInode: 1,\n      nameTable: null,\n      currentPath: '/',\n      initialized: false,\n      ignorePermissions: true,\n      ErrnoError: null,\n      genericErrors: {},\n      filesystems: null,\n      syncFSRequests: 0,\n      lookupPath: (path, opts = {}) => {\n        path = PATH_FS.resolve(path)\n        if (!path) return { path: '', node: null }\n        var defaults = { follow_mount: true, recurse_count: 0 }\n        opts = Object.assign(defaults, opts)\n        if (opts.recurse_count > 8) {\n          throw new FS.ErrnoError(32)\n        }\n        var parts = path.split('/').filter(p => !!p)\n        var current = FS.root\n        var current_path = '/'\n        for (var i = 0; i < parts.length; i++) {\n          var islast = i === parts.length - 1\n          if (islast && opts.parent) {\n            break\n          }\n          current = FS.lookupNode(current, parts[i])\n          current_path = PATH.join2(current_path, parts[i])\n          if (FS.isMountpoint(current)) {\n            if (!islast || (islast && opts.follow_mount)) {\n              current = current.mounted.root\n            }\n          }\n          if (!islast || opts.follow) {\n            var count = 0\n            while (FS.isLink(current.mode)) {\n              var link = FS.readlink(current_path)\n              current_path = PATH_FS.resolve(PATH.dirname(current_path), link)\n              var lookup = FS.lookupPath(current_path, {\n                recurse_count: opts.recurse_count + 1,\n              })\n              current = lookup.node\n              if (count++ > 40) {\n                throw new FS.ErrnoError(32)\n              }\n            }\n          }\n        }\n        return { path: current_path, node: current }\n      },\n      getPath: node => {\n        var path\n        while (true) {\n          if (FS.isRoot(node)) {\n            var mount = node.mount.mountpoint\n            if (!path) return mount\n            return mount[mount.length - 1] !== '/'\n              ? mount + '/' + path\n              : mount + path\n          }\n          path = path ? node.name + '/' + path : node.name\n          node = node.parent\n        }\n      },\n      hashName: (parentid, name) => {\n        var hash = 0\n        for (var i = 0; i < name.length; i++) {\n          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0\n        }\n        return ((parentid + hash) >>> 0) % FS.nameTable.length\n      },\n      hashAddNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        node.name_next = FS.nameTable[hash]\n        FS.nameTable[hash] = node\n      },\n      hashRemoveNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        if (FS.nameTable[hash] === node) {\n          FS.nameTable[hash] = node.name_next\n        } else {\n          var current = FS.nameTable[hash]\n          while (current) {\n            if (current.name_next === node) {\n              current.name_next = node.name_next\n              break\n            }\n            current = current.name_next\n          }\n        }\n      },\n      lookupNode: (parent, name) => {\n        var errCode = FS.mayLookup(parent)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode, parent)\n        }\n        var hash = FS.hashName(parent.id, name)\n        for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n          var nodeName = node.name\n          if (node.parent.id === parent.id && nodeName === name) {\n            return node\n          }\n        }\n        return FS.lookup(parent, name)\n      },\n      createNode: (parent, name, mode, rdev) => {\n        var node = new FS.FSNode(parent, name, mode, rdev)\n        FS.hashAddNode(node)\n        return node\n      },\n      destroyNode: node => {\n        FS.hashRemoveNode(node)\n      },\n      isRoot: node => {\n        return node === node.parent\n      },\n      isMountpoint: node => {\n        return !!node.mounted\n      },\n      isFile: mode => {\n        return (mode & 61440) === 32768\n      },\n      isDir: mode => {\n        return (mode & 61440) === 16384\n      },\n      isLink: mode => {\n        return (mode & 61440) === 40960\n      },\n      isChrdev: mode => {\n        return (mode & 61440) === 8192\n      },\n      isBlkdev: mode => {\n        return (mode & 61440) === 24576\n      },\n      isFIFO: mode => {\n        return (mode & 61440) === 4096\n      },\n      isSocket: mode => {\n        return (mode & 49152) === 49152\n      },\n      flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 },\n      modeStringToFlags: str => {\n        var flags = FS.flagModes[str]\n        if (typeof flags == 'undefined') {\n          throw new Error('Unknown file open mode: ' + str)\n        }\n        return flags\n      },\n      flagsToPermissionString: flag => {\n        var perms = ['r', 'w', 'rw'][flag & 3]\n        if (flag & 512) {\n          perms += 'w'\n        }\n        return perms\n      },\n      nodePermissions: (node, perms) => {\n        if (FS.ignorePermissions) {\n          return 0\n        }\n        if (perms.includes('r') && !(node.mode & 292)) {\n          return 2\n        } else if (perms.includes('w') && !(node.mode & 146)) {\n          return 2\n        } else if (perms.includes('x') && !(node.mode & 73)) {\n          return 2\n        }\n        return 0\n      },\n      mayLookup: dir => {\n        var errCode = FS.nodePermissions(dir, 'x')\n        if (errCode) return errCode\n        if (!dir.node_ops.lookup) return 2\n        return 0\n      },\n      mayCreate: (dir, name) => {\n        try {\n          var node = FS.lookupNode(dir, name)\n          return 20\n        } catch (e) {}\n        return FS.nodePermissions(dir, 'wx')\n      },\n      mayDelete: (dir, name, isdir) => {\n        var node\n        try {\n          node = FS.lookupNode(dir, name)\n        } catch (e) {\n          return e.errno\n        }\n        var errCode = FS.nodePermissions(dir, 'wx')\n        if (errCode) {\n          return errCode\n        }\n        if (isdir) {\n          if (!FS.isDir(node.mode)) {\n            return 54\n          }\n          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n            return 10\n          }\n        } else {\n          if (FS.isDir(node.mode)) {\n            return 31\n          }\n        }\n        return 0\n      },\n      mayOpen: (node, flags) => {\n        if (!node) {\n          return 44\n        }\n        if (FS.isLink(node.mode)) {\n          return 32\n        } else if (FS.isDir(node.mode)) {\n          if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) {\n            return 31\n          }\n        }\n        return FS.nodePermissions(node, FS.flagsToPermissionString(flags))\n      },\n      MAX_OPEN_FDS: 4096,\n      nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => {\n        for (var fd = fd_start; fd <= fd_end; fd++) {\n          if (!FS.streams[fd]) {\n            return fd\n          }\n        }\n        throw new FS.ErrnoError(33)\n      },\n      getStream: fd => FS.streams[fd],\n      createStream: (stream, fd_start, fd_end) => {\n        if (!FS.FSStream) {\n          FS.FSStream = function() {\n            this.shared = {}\n          }\n          FS.FSStream.prototype = {}\n          Object.defineProperties(FS.FSStream.prototype, {\n            object: {\n              get: function() {\n                return this.node\n              },\n              set: function(val) {\n                this.node = val\n              },\n            },\n            isRead: {\n              get: function() {\n                return (this.flags & 2097155) !== 1\n              },\n            },\n            isWrite: {\n              get: function() {\n                return (this.flags & 2097155) !== 0\n              },\n            },\n            isAppend: {\n              get: function() {\n                return this.flags & 1024\n              },\n            },\n            flags: {\n              get: function() {\n                return this.shared.flags\n              },\n              set: function(val) {\n                this.shared.flags = val\n              },\n            },\n            position: {\n              get: function() {\n                return this.shared.position\n              },\n              set: function(val) {\n                this.shared.position = val\n              },\n            },\n          })\n        }\n        stream = Object.assign(new FS.FSStream(), stream)\n        var fd = FS.nextfd(fd_start, fd_end)\n        stream.fd = fd\n        FS.streams[fd] = stream\n        return stream\n      },\n      closeStream: fd => {\n        FS.streams[fd] = null\n      },\n      chrdev_stream_ops: {\n        open: stream => {\n          var device = FS.getDevice(stream.node.rdev)\n          stream.stream_ops = device.stream_ops\n          if (stream.stream_ops.open) {\n            stream.stream_ops.open(stream)\n          }\n        },\n        llseek: () => {\n          throw new FS.ErrnoError(70)\n        },\n      },\n      major: dev => dev >> 8,\n      minor: dev => dev & 255,\n      makedev: (ma, mi) => (ma << 8) | mi,\n      registerDevice: (dev, ops) => {\n        FS.devices[dev] = { stream_ops: ops }\n      },\n      getDevice: dev => FS.devices[dev],\n      getMounts: mount => {\n        var mounts = []\n        var check = [mount]\n        while (check.length) {\n          var m = check.pop()\n          mounts.push(m)\n          check.push.apply(check, m.mounts)\n        }\n        return mounts\n      },\n      syncfs: (populate, callback) => {\n        if (typeof populate == 'function') {\n          callback = populate\n          populate = false\n        }\n        FS.syncFSRequests++\n        if (FS.syncFSRequests > 1) {\n          err(\n            'warning: ' +\n              FS.syncFSRequests +\n              ' FS.syncfs operations in flight at once, probably just doing extra work'\n          )\n        }\n        var mounts = FS.getMounts(FS.root.mount)\n        var completed = 0\n        function doCallback(errCode) {\n          FS.syncFSRequests--\n          return callback(errCode)\n        }\n        function done(errCode) {\n          if (errCode) {\n            if (!done.errored) {\n              done.errored = true\n              return doCallback(errCode)\n            }\n            return\n          }\n          if (++completed >= mounts.length) {\n            doCallback(null)\n          }\n        }\n        mounts.forEach(mount => {\n          if (!mount.type.syncfs) {\n            return done(null)\n          }\n          mount.type.syncfs(mount, populate, done)\n        })\n      },\n      mount: (type, opts, mountpoint) => {\n        var root = mountpoint === '/'\n        var pseudo = !mountpoint\n        var node\n        if (root && FS.root) {\n          throw new FS.ErrnoError(10)\n        } else if (!root && !pseudo) {\n          var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n          mountpoint = lookup.path\n          node = lookup.node\n          if (FS.isMountpoint(node)) {\n            throw new FS.ErrnoError(10)\n          }\n          if (!FS.isDir(node.mode)) {\n            throw new FS.ErrnoError(54)\n          }\n        }\n        var mount = {\n          type: type,\n          opts: opts,\n          mountpoint: mountpoint,\n          mounts: [],\n        }\n        var mountRoot = type.mount(mount)\n        mountRoot.mount = mount\n        mount.root = mountRoot\n        if (root) {\n          FS.root = mountRoot\n        } else if (node) {\n          node.mounted = mount\n          if (node.mount) {\n            node.mount.mounts.push(mount)\n          }\n        }\n        return mountRoot\n      },\n      unmount: mountpoint => {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n        if (!FS.isMountpoint(lookup.node)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = lookup.node\n        var mount = node.mounted\n        var mounts = FS.getMounts(mount)\n        Object.keys(FS.nameTable).forEach(hash => {\n          var current = FS.nameTable[hash]\n          while (current) {\n            var next = current.name_next\n            if (mounts.includes(current.mount)) {\n              FS.destroyNode(current)\n            }\n            current = next\n          }\n        })\n        node.mounted = null\n        var idx = node.mount.mounts.indexOf(mount)\n        node.mount.mounts.splice(idx, 1)\n      },\n      lookup: (parent, name) => {\n        return parent.node_ops.lookup(parent, name)\n      },\n      mknod: (path, mode, dev) => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        if (!name || name === '.' || name === '..') {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.mayCreate(parent, name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.mknod) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.mknod(parent, name, mode, dev)\n      },\n      create: (path, mode) => {\n        mode = mode !== undefined ? mode : 438\n        mode &= 4095\n        mode |= 32768\n        return FS.mknod(path, mode, 0)\n      },\n      mkdir: (path, mode) => {\n        mode = mode !== undefined ? mode : 511\n        mode &= 511 | 512\n        mode |= 16384\n        return FS.mknod(path, mode, 0)\n      },\n      mkdirTree: (path, mode) => {\n        var dirs = path.split('/')\n        var d = ''\n        for (var i = 0; i < dirs.length; ++i) {\n          if (!dirs[i]) continue\n          d += '/' + dirs[i]\n          try {\n            FS.mkdir(d, mode)\n          } catch (e) {\n            if (e.errno != 20) throw e\n          }\n        }\n      },\n      mkdev: (path, mode, dev) => {\n        if (typeof dev == 'undefined') {\n          dev = mode\n          mode = 438\n        }\n        mode |= 8192\n        return FS.mknod(path, mode, dev)\n      },\n      symlink: (oldpath, newpath) => {\n        if (!PATH_FS.resolve(oldpath)) {\n          throw new FS.ErrnoError(44)\n        }\n        var lookup = FS.lookupPath(newpath, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var newname = PATH.basename(newpath)\n        var errCode = FS.mayCreate(parent, newname)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.symlink) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.symlink(parent, newname, oldpath)\n      },\n      rename: (old_path, new_path) => {\n        var old_dirname = PATH.dirname(old_path)\n        var new_dirname = PATH.dirname(new_path)\n        var old_name = PATH.basename(old_path)\n        var new_name = PATH.basename(new_path)\n        var lookup, old_dir, new_dir\n        lookup = FS.lookupPath(old_path, { parent: true })\n        old_dir = lookup.node\n        lookup = FS.lookupPath(new_path, { parent: true })\n        new_dir = lookup.node\n        if (!old_dir || !new_dir) throw new FS.ErrnoError(44)\n        if (old_dir.mount !== new_dir.mount) {\n          throw new FS.ErrnoError(75)\n        }\n        var old_node = FS.lookupNode(old_dir, old_name)\n        var relative = PATH_FS.relative(old_path, new_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(28)\n        }\n        relative = PATH_FS.relative(new_path, old_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(55)\n        }\n        var new_node\n        try {\n          new_node = FS.lookupNode(new_dir, new_name)\n        } catch (e) {}\n        if (old_node === new_node) {\n          return\n        }\n        var isdir = FS.isDir(old_node.mode)\n        var errCode = FS.mayDelete(old_dir, old_name, isdir)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        errCode = new_node\n          ? FS.mayDelete(new_dir, new_name, isdir)\n          : FS.mayCreate(new_dir, new_name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!old_dir.node_ops.rename) {\n          throw new FS.ErrnoError(63)\n        }\n        if (\n          FS.isMountpoint(old_node) ||\n          (new_node && FS.isMountpoint(new_node))\n        ) {\n          throw new FS.ErrnoError(10)\n        }\n        if (new_dir !== old_dir) {\n          errCode = FS.nodePermissions(old_dir, 'w')\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        FS.hashRemoveNode(old_node)\n        try {\n          old_dir.node_ops.rename(old_node, new_dir, new_name)\n        } catch (e) {\n          throw e\n        } finally {\n          FS.hashAddNode(old_node)\n        }\n      },\n      rmdir: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, true)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.rmdir) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.rmdir(parent, name)\n        FS.destroyNode(node)\n      },\n      readdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        if (!node.node_ops.readdir) {\n          throw new FS.ErrnoError(54)\n        }\n        return node.node_ops.readdir(node)\n      },\n      unlink: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, false)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.unlink) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.unlink(parent, name)\n        FS.destroyNode(node)\n      },\n      readlink: path => {\n        var lookup = FS.lookupPath(path)\n        var link = lookup.node\n        if (!link) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!link.node_ops.readlink) {\n          throw new FS.ErrnoError(28)\n        }\n        return PATH_FS.resolve(\n          FS.getPath(link.parent),\n          link.node_ops.readlink(link)\n        )\n      },\n      stat: (path, dontFollow) => {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow })\n        var node = lookup.node\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!node.node_ops.getattr) {\n          throw new FS.ErrnoError(63)\n        }\n        return node.node_ops.getattr(node)\n      },\n      lstat: path => {\n        return FS.stat(path, true)\n      },\n      chmod: (path, mode, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, {\n          mode: (mode & 4095) | (node.mode & ~4095),\n          timestamp: Date.now(),\n        })\n      },\n      lchmod: (path, mode) => {\n        FS.chmod(path, mode, true)\n      },\n      fchmod: (fd, mode) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chmod(stream.node, mode)\n      },\n      chown: (path, uid, gid, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, { timestamp: Date.now() })\n      },\n      lchown: (path, uid, gid) => {\n        FS.chown(path, uid, gid, true)\n      },\n      fchown: (fd, uid, gid) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chown(stream.node, uid, gid)\n      },\n      truncate: (path, len) => {\n        if (len < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: true })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!FS.isFile(node.mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.nodePermissions(node, 'w')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        node.node_ops.setattr(node, { size: len, timestamp: Date.now() })\n      },\n      ftruncate: (fd, len) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(28)\n        }\n        FS.truncate(stream.node, len)\n      },\n      utime: (path, atime, mtime) => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) })\n      },\n      open: (path, flags, mode) => {\n        if (path === '') {\n          throw new FS.ErrnoError(44)\n        }\n        flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags\n        mode = typeof mode == 'undefined' ? 438 : mode\n        if (flags & 64) {\n          mode = (mode & 4095) | 32768\n        } else {\n          mode = 0\n        }\n        var node\n        if (typeof path == 'object') {\n          node = path\n        } else {\n          path = PATH.normalize(path)\n          try {\n            var lookup = FS.lookupPath(path, { follow: !(flags & 131072) })\n            node = lookup.node\n          } catch (e) {}\n        }\n        var created = false\n        if (flags & 64) {\n          if (node) {\n            if (flags & 128) {\n              throw new FS.ErrnoError(20)\n            }\n          } else {\n            node = FS.mknod(path, mode, 0)\n            created = true\n          }\n        }\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (FS.isChrdev(node.mode)) {\n          flags &= ~512\n        }\n        if (flags & 65536 && !FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        if (!created) {\n          var errCode = FS.mayOpen(node, flags)\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        if (flags & 512 && !created) {\n          FS.truncate(node, 0)\n        }\n        flags &= ~(128 | 512 | 131072)\n        var stream = FS.createStream({\n          node: node,\n          path: FS.getPath(node),\n          flags: flags,\n          seekable: true,\n          position: 0,\n          stream_ops: node.stream_ops,\n          ungotten: [],\n          error: false,\n        })\n        if (stream.stream_ops.open) {\n          stream.stream_ops.open(stream)\n        }\n        if (Module['logReadFiles'] && !(flags & 1)) {\n          if (!FS.readFiles) FS.readFiles = {}\n          if (!(path in FS.readFiles)) {\n            FS.readFiles[path] = 1\n          }\n        }\n        return stream\n      },\n      close: stream => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (stream.getdents) stream.getdents = null\n        try {\n          if (stream.stream_ops.close) {\n            stream.stream_ops.close(stream)\n          }\n        } catch (e) {\n          throw e\n        } finally {\n          FS.closeStream(stream.fd)\n        }\n        stream.fd = null\n      },\n      isClosed: stream => {\n        return stream.fd === null\n      },\n      llseek: (stream, offset, whence) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!stream.seekable || !stream.stream_ops.llseek) {\n          throw new FS.ErrnoError(70)\n        }\n        if (whence != 0 && whence != 1 && whence != 2) {\n          throw new FS.ErrnoError(28)\n        }\n        stream.position = stream.stream_ops.llseek(stream, offset, whence)\n        stream.ungotten = []\n        return stream.position\n      },\n      read: (stream, buffer, offset, length, position) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.read) {\n          throw new FS.ErrnoError(28)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesRead = stream.stream_ops.read(\n          stream,\n          buffer,\n          offset,\n          length,\n          position\n        )\n        if (!seeking) stream.position += bytesRead\n        return bytesRead\n      },\n      write: (stream, buffer, offset, length, position, canOwn) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.write) {\n          throw new FS.ErrnoError(28)\n        }\n        if (stream.seekable && stream.flags & 1024) {\n          FS.llseek(stream, 0, 2)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesWritten = stream.stream_ops.write(\n          stream,\n          buffer,\n          offset,\n          length,\n          position,\n          canOwn\n        )\n        if (!seeking) stream.position += bytesWritten\n        return bytesWritten\n      },\n      allocate: (stream, offset, length) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (offset < 0 || length <= 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (!stream.stream_ops.allocate) {\n          throw new FS.ErrnoError(138)\n        }\n        stream.stream_ops.allocate(stream, offset, length)\n      },\n      mmap: (stream, length, position, prot, flags) => {\n        if (\n          (prot & 2) !== 0 &&\n          (flags & 2) === 0 &&\n          (stream.flags & 2097155) !== 2\n        ) {\n          throw new FS.ErrnoError(2)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(2)\n        }\n        if (!stream.stream_ops.mmap) {\n          throw new FS.ErrnoError(43)\n        }\n        return stream.stream_ops.mmap(stream, length, position, prot, flags)\n      },\n      msync: (stream, buffer, offset, length, mmapFlags) => {\n        if (!stream.stream_ops.msync) {\n          return 0\n        }\n        return stream.stream_ops.msync(\n          stream,\n          buffer,\n          offset,\n          length,\n          mmapFlags\n        )\n      },\n      munmap: stream => 0,\n      ioctl: (stream, cmd, arg) => {\n        if (!stream.stream_ops.ioctl) {\n          throw new FS.ErrnoError(59)\n        }\n        return stream.stream_ops.ioctl(stream, cmd, arg)\n      },\n      readFile: (path, opts = {}) => {\n        opts.flags = opts.flags || 0\n        opts.encoding = opts.encoding || 'binary'\n        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {\n          throw new Error('Invalid encoding type \"' + opts.encoding + '\"')\n        }\n        var ret\n        var stream = FS.open(path, opts.flags)\n        var stat = FS.stat(path)\n        var length = stat.size\n        var buf = new Uint8Array(length)\n        FS.read(stream, buf, 0, length, 0)\n        if (opts.encoding === 'utf8') {\n          ret = UTF8ArrayToString(buf, 0)\n        } else if (opts.encoding === 'binary') {\n          ret = buf\n        }\n        FS.close(stream)\n        return ret\n      },\n      writeFile: (path, data, opts = {}) => {\n        opts.flags = opts.flags || 577\n        var stream = FS.open(path, opts.flags, opts.mode)\n        if (typeof data == 'string') {\n          var buf = new Uint8Array(lengthBytesUTF8(data) + 1)\n          var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length)\n          FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn)\n        } else if (ArrayBuffer.isView(data)) {\n          FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn)\n        } else {\n          throw new Error('Unsupported data type')\n        }\n        FS.close(stream)\n      },\n      cwd: () => FS.currentPath,\n      chdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        if (lookup.node === null) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!FS.isDir(lookup.node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        var errCode = FS.nodePermissions(lookup.node, 'x')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        FS.currentPath = lookup.path\n      },\n      createDefaultDirectories: () => {\n        FS.mkdir('/tmp')\n        FS.mkdir('/home')\n        FS.mkdir('/home/web_user')\n      },\n      createDefaultDevices: () => {\n        FS.mkdir('/dev')\n        FS.registerDevice(FS.makedev(1, 3), {\n          read: () => 0,\n          write: (stream, buffer, offset, length, pos) => length,\n        })\n        FS.mkdev('/dev/null', FS.makedev(1, 3))\n        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops)\n        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops)\n        FS.mkdev('/dev/tty', FS.makedev(5, 0))\n        FS.mkdev('/dev/tty1', FS.makedev(6, 0))\n        var random_device = getRandomDevice()\n        FS.createDevice('/dev', 'random', random_device)\n        FS.createDevice('/dev', 'urandom', random_device)\n        FS.mkdir('/dev/shm')\n        FS.mkdir('/dev/shm/tmp')\n      },\n      createSpecialDirectories: () => {\n        FS.mkdir('/proc')\n        var proc_self = FS.mkdir('/proc/self')\n        FS.mkdir('/proc/self/fd')\n        FS.mount(\n          {\n            mount: () => {\n              var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73)\n              node.node_ops = {\n                lookup: (parent, name) => {\n                  var fd = +name\n                  var stream = FS.getStream(fd)\n                  if (!stream) throw new FS.ErrnoError(8)\n                  var ret = {\n                    parent: null,\n                    mount: { mountpoint: 'fake' },\n                    node_ops: { readlink: () => stream.path },\n                  }\n                  ret.parent = ret\n                  return ret\n                },\n              }\n              return node\n            },\n          },\n          {},\n          '/proc/self/fd'\n        )\n      },\n      createStandardStreams: () => {\n        if (Module['stdin']) {\n          FS.createDevice('/dev', 'stdin', Module['stdin'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdin')\n        }\n        if (Module['stdout']) {\n          FS.createDevice('/dev', 'stdout', null, Module['stdout'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdout')\n        }\n        if (Module['stderr']) {\n          FS.createDevice('/dev', 'stderr', null, Module['stderr'])\n        } else {\n          FS.symlink('/dev/tty1', '/dev/stderr')\n        }\n        var stdin = FS.open('/dev/stdin', 0)\n        var stdout = FS.open('/dev/stdout', 1)\n        var stderr = FS.open('/dev/stderr', 1)\n      },\n      ensureErrnoError: () => {\n        if (FS.ErrnoError) return\n        FS.ErrnoError = function ErrnoError(errno, node) {\n          this.node = node\n          this.setErrno = function(errno) {\n            this.errno = errno\n          }\n          this.setErrno(errno)\n          this.message = 'FS error'\n        }\n        FS.ErrnoError.prototype = new Error()\n        FS.ErrnoError.prototype.constructor = FS.ErrnoError\n        ;[44].forEach(code => {\n          FS.genericErrors[code] = new FS.ErrnoError(code)\n          FS.genericErrors[code].stack = '<generic error, no stack>'\n        })\n      },\n      staticInit: () => {\n        FS.ensureErrnoError()\n        FS.nameTable = new Array(4096)\n        FS.mount(MEMFS, {}, '/')\n        FS.createDefaultDirectories()\n        FS.createDefaultDevices()\n        FS.createSpecialDirectories()\n        FS.filesystems = { MEMFS: MEMFS, NODEFS: NODEFS }\n      },\n      init: (input, output, error) => {\n        FS.init.initialized = true\n        FS.ensureErrnoError()\n        Module['stdin'] = input || Module['stdin']\n        Module['stdout'] = output || Module['stdout']\n        Module['stderr'] = error || Module['stderr']\n        FS.createStandardStreams()\n      },\n      quit: () => {\n        FS.init.initialized = false\n        for (var i = 0; i < FS.streams.length; i++) {\n          var stream = FS.streams[i]\n          if (!stream) {\n            continue\n          }\n          FS.close(stream)\n        }\n      },\n      getMode: (canRead, canWrite) => {\n        var mode = 0\n        if (canRead) mode |= 292 | 73\n        if (canWrite) mode |= 146\n        return mode\n      },\n      findObject: (path, dontResolveLastLink) => {\n        var ret = FS.analyzePath(path, dontResolveLastLink)\n        if (!ret.exists) {\n          return null\n        }\n        return ret.object\n      },\n      analyzePath: (path, dontResolveLastLink) => {\n        try {\n          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          path = lookup.path\n        } catch (e) {}\n        var ret = {\n          isRoot: false,\n          exists: false,\n          error: 0,\n          name: null,\n          path: null,\n          object: null,\n          parentExists: false,\n          parentPath: null,\n          parentObject: null,\n        }\n        try {\n          var lookup = FS.lookupPath(path, { parent: true })\n          ret.parentExists = true\n          ret.parentPath = lookup.path\n          ret.parentObject = lookup.node\n          ret.name = PATH.basename(path)\n          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          ret.exists = true\n          ret.path = lookup.path\n          ret.object = lookup.node\n          ret.name = lookup.node.name\n          ret.isRoot = lookup.path === '/'\n        } catch (e) {\n          ret.error = e.errno\n        }\n        return ret\n      },\n      createPath: (parent, path, canRead, canWrite) => {\n        parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n        var parts = path.split('/').reverse()\n        while (parts.length) {\n          var part = parts.pop()\n          if (!part) continue\n          var current = PATH.join2(parent, part)\n          try {\n            FS.mkdir(current)\n          } catch (e) {}\n          parent = current\n        }\n        return current\n      },\n      createFile: (parent, name, properties, canRead, canWrite) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(canRead, canWrite)\n        return FS.create(path, mode)\n      },\n      createDataFile: (parent, name, data, canRead, canWrite, canOwn) => {\n        var path = name\n        if (parent) {\n          parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n          path = name ? PATH.join2(parent, name) : parent\n        }\n        var mode = FS.getMode(canRead, canWrite)\n        var node = FS.create(path, mode)\n        if (data) {\n          if (typeof data == 'string') {\n            var arr = new Array(data.length)\n            for (var i = 0, len = data.length; i < len; ++i)\n              arr[i] = data.charCodeAt(i)\n            data = arr\n          }\n          FS.chmod(node, mode | 146)\n          var stream = FS.open(node, 577)\n          FS.write(stream, data, 0, data.length, 0, canOwn)\n          FS.close(stream)\n          FS.chmod(node, mode)\n        }\n        return node\n      },\n      createDevice: (parent, name, input, output) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(!!input, !!output)\n        if (!FS.createDevice.major) FS.createDevice.major = 64\n        var dev = FS.makedev(FS.createDevice.major++, 0)\n        FS.registerDevice(dev, {\n          open: stream => {\n            stream.seekable = false\n          },\n          close: stream => {\n            if (output && output.buffer && output.buffer.length) {\n              output(10)\n            }\n          },\n          read: (stream, buffer, offset, length, pos) => {\n            var bytesRead = 0\n            for (var i = 0; i < length; i++) {\n              var result\n              try {\n                result = input()\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n              if (result === undefined && bytesRead === 0) {\n                throw new FS.ErrnoError(6)\n              }\n              if (result === null || result === undefined) break\n              bytesRead++\n              buffer[offset + i] = result\n            }\n            if (bytesRead) {\n              stream.node.timestamp = Date.now()\n            }\n            return bytesRead\n          },\n          write: (stream, buffer, offset, length, pos) => {\n            for (var i = 0; i < length; i++) {\n              try {\n                output(buffer[offset + i])\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n            }\n            if (length) {\n              stream.node.timestamp = Date.now()\n            }\n            return i\n          },\n        })\n        return FS.mkdev(path, mode, dev)\n      },\n      forceLoadFile: obj => {\n        if (obj.isDevice || obj.isFolder || obj.link || obj.contents)\n          return true\n        if (typeof XMLHttpRequest != 'undefined') {\n          throw new Error(\n            'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.'\n          )\n        } else if (read_) {\n          try {\n            obj.contents = intArrayFromString(read_(obj.url), true)\n            obj.usedBytes = obj.contents.length\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n        } else {\n          throw new Error('Cannot load without read() or XMLHttpRequest.')\n        }\n      },\n      createLazyFile: (parent, name, url, canRead, canWrite) => {\n        function LazyUint8Array() {\n          this.lengthKnown = false\n          this.chunks = []\n        }\n        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n          if (idx > this.length - 1 || idx < 0) {\n            return undefined\n          }\n          var chunkOffset = idx % this.chunkSize\n          var chunkNum = (idx / this.chunkSize) | 0\n          return this.getter(chunkNum)[chunkOffset]\n        }\n        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(\n          getter\n        ) {\n          this.getter = getter\n        }\n        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n          var xhr = new XMLHttpRequest()\n          xhr.open('HEAD', url, false)\n          xhr.send(null)\n          if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n            throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n          var datalength = Number(xhr.getResponseHeader('Content-length'))\n          var header\n          var hasByteServing =\n            (header = xhr.getResponseHeader('Accept-Ranges')) &&\n            header === 'bytes'\n          var usesGzip =\n            (header = xhr.getResponseHeader('Content-Encoding')) &&\n            header === 'gzip'\n          var chunkSize = 1024 * 1024\n          if (!hasByteServing) chunkSize = datalength\n          var doXHR = (from, to) => {\n            if (from > to)\n              throw new Error(\n                'invalid range (' +\n                  from +\n                  ', ' +\n                  to +\n                  ') or no bytes requested!'\n              )\n            if (to > datalength - 1)\n              throw new Error(\n                'only ' + datalength + ' bytes available! programmer error!'\n              )\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            if (datalength !== chunkSize)\n              xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to)\n            xhr.responseType = 'arraybuffer'\n            if (xhr.overrideMimeType) {\n              xhr.overrideMimeType('text/plain; charset=x-user-defined')\n            }\n            xhr.send(null)\n            if (\n              !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)\n            )\n              throw new Error(\n                \"Couldn't load \" + url + '. Status: ' + xhr.status\n              )\n            if (xhr.response !== undefined) {\n              return new Uint8Array(xhr.response || [])\n            }\n            return intArrayFromString(xhr.responseText || '', true)\n          }\n          var lazyArray = this\n          lazyArray.setDataGetter(chunkNum => {\n            var start = chunkNum * chunkSize\n            var end = (chunkNum + 1) * chunkSize - 1\n            end = Math.min(end, datalength - 1)\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined') {\n              lazyArray.chunks[chunkNum] = doXHR(start, end)\n            }\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined')\n              throw new Error('doXHR failed!')\n            return lazyArray.chunks[chunkNum]\n          })\n          if (usesGzip || !datalength) {\n            chunkSize = datalength = 1\n            datalength = this.getter(0).length\n            chunkSize = datalength\n            out(\n              'LazyFiles on gzip forces download of the whole file when length is accessed'\n            )\n          }\n          this._length = datalength\n          this._chunkSize = chunkSize\n          this.lengthKnown = true\n        }\n        if (typeof XMLHttpRequest != 'undefined') {\n          if (!ENVIRONMENT_IS_WORKER)\n            throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'\n          var lazyArray = new LazyUint8Array()\n          Object.defineProperties(lazyArray, {\n            length: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._length\n              },\n            },\n            chunkSize: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._chunkSize\n              },\n            },\n          })\n          var properties = { isDevice: false, contents: lazyArray }\n        } else {\n          var properties = { isDevice: false, url: url }\n        }\n        var node = FS.createFile(parent, name, properties, canRead, canWrite)\n        if (properties.contents) {\n          node.contents = properties.contents\n        } else if (properties.url) {\n          node.contents = null\n          node.url = properties.url\n        }\n        Object.defineProperties(node, {\n          usedBytes: {\n            get: function() {\n              return this.contents.length\n            },\n          },\n        })\n        var stream_ops = {}\n        var keys = Object.keys(node.stream_ops)\n        keys.forEach(key => {\n          var fn = node.stream_ops[key]\n          stream_ops[key] = function forceLoadLazyFile() {\n            FS.forceLoadFile(node)\n            return fn.apply(null, arguments)\n          }\n        })\n        function writeChunks(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= contents.length) return 0\n          var size = Math.min(contents.length - position, length)\n          if (contents.slice) {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents[position + i]\n            }\n          } else {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents.get(position + i)\n            }\n          }\n          return size\n        }\n        stream_ops.read = (stream, buffer, offset, length, position) => {\n          FS.forceLoadFile(node)\n          return writeChunks(stream, buffer, offset, length, position)\n        }\n        stream_ops.mmap = (stream, length, position, prot, flags) => {\n          FS.forceLoadFile(node)\n          var ptr = mmapAlloc(length)\n          if (!ptr) {\n            throw new FS.ErrnoError(48)\n          }\n          writeChunks(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        }\n        node.stream_ops = stream_ops\n        return node\n      },\n      createPreloadedFile: (\n        parent,\n        name,\n        url,\n        canRead,\n        canWrite,\n        onload,\n        onerror,\n        dontCreateFile,\n        canOwn,\n        preFinish\n      ) => {\n        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent\n        var dep = getUniqueRunDependency('cp ' + fullname)\n        function processData(byteArray) {\n          function finish(byteArray) {\n            if (preFinish) preFinish()\n            if (!dontCreateFile) {\n              FS.createDataFile(\n                parent,\n                name,\n                byteArray,\n                canRead,\n                canWrite,\n                canOwn\n              )\n            }\n            if (onload) onload()\n            removeRunDependency(dep)\n          }\n          if (\n            Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => {\n              if (onerror) onerror()\n              removeRunDependency(dep)\n            })\n          ) {\n            return\n          }\n          finish(byteArray)\n        }\n        addRunDependency(dep)\n        if (typeof url == 'string') {\n          asyncLoad(url, byteArray => processData(byteArray), onerror)\n        } else {\n          processData(url)\n        }\n      },\n      indexedDB: () => {\n        return (\n          window.indexedDB ||\n          window.mozIndexedDB ||\n          window.webkitIndexedDB ||\n          window.msIndexedDB\n        )\n      },\n      DB_NAME: () => {\n        return 'EM_FS_' + window.location.pathname\n      },\n      DB_VERSION: 20,\n      DB_STORE_NAME: 'FILE_DATA',\n      saveFilesToDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = () => {\n          out('creating db')\n          var db = openRequest.result\n          db.createObjectStore(FS.DB_STORE_NAME)\n        }\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite')\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var putRequest = files.put(\n              FS.analyzePath(path).object.contents,\n              path\n            )\n            putRequest.onsuccess = () => {\n              ok++\n              if (ok + fail == total) finish()\n            }\n            putRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n      loadFilesFromDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = onerror\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          try {\n            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly')\n          } catch (e) {\n            onerror(e)\n            return\n          }\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var getRequest = files.get(path)\n            getRequest.onsuccess = () => {\n              if (FS.analyzePath(path).exists) {\n                FS.unlink(path)\n              }\n              FS.createDataFile(\n                PATH.dirname(path),\n                PATH.basename(path),\n                getRequest.result,\n                true,\n                true,\n                true\n              )\n              ok++\n              if (ok + fail == total) finish()\n            }\n            getRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n    }\n    var SYSCALLS = {\n      DEFAULT_POLLMASK: 5,\n      calculateAt: function(dirfd, path, allowEmpty) {\n        if (PATH.isAbs(path)) {\n          return path\n        }\n        var dir\n        if (dirfd === -100) {\n          dir = FS.cwd()\n        } else {\n          var dirstream = SYSCALLS.getStreamFromFD(dirfd)\n          dir = dirstream.path\n        }\n        if (path.length == 0) {\n          if (!allowEmpty) {\n            throw new FS.ErrnoError(44)\n          }\n          return dir\n        }\n        return PATH.join2(dir, path)\n      },\n      doStat: function(func, path, buf) {\n        try {\n          var stat = func(path)\n        } catch (e) {\n          if (\n            e &&\n            e.node &&\n            PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))\n          ) {\n            return -54\n          }\n          throw e\n        }\n        HEAP32[buf >> 2] = stat.dev\n        HEAP32[(buf + 8) >> 2] = stat.ino\n        HEAP32[(buf + 12) >> 2] = stat.mode\n        HEAPU32[(buf + 16) >> 2] = stat.nlink\n        HEAP32[(buf + 20) >> 2] = stat.uid\n        HEAP32[(buf + 24) >> 2] = stat.gid\n        HEAP32[(buf + 28) >> 2] = stat.rdev\n        ;(tempI64 = [\n          stat.size >>> 0,\n          ((tempDouble = stat.size),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 40) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 44) >> 2] = tempI64[1])\n        HEAP32[(buf + 48) >> 2] = 4096\n        HEAP32[(buf + 52) >> 2] = stat.blocks\n        var atime = stat.atime.getTime()\n        var mtime = stat.mtime.getTime()\n        var ctime = stat.ctime.getTime()\n        ;(tempI64 = [\n          Math.floor(atime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(atime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 56) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 60) >> 2] = tempI64[1])\n        HEAPU32[(buf + 64) >> 2] = (atime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(mtime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(mtime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 72) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 76) >> 2] = tempI64[1])\n        HEAPU32[(buf + 80) >> 2] = (mtime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(ctime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(ctime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 88) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 92) >> 2] = tempI64[1])\n        HEAPU32[(buf + 96) >> 2] = (ctime % 1e3) * 1e3\n        ;(tempI64 = [\n          stat.ino >>> 0,\n          ((tempDouble = stat.ino),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 104) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 108) >> 2] = tempI64[1])\n        return 0\n      },\n      doMsync: function(addr, stream, len, flags, offset) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (flags & 2) {\n          return 0\n        }\n        var buffer = HEAPU8.slice(addr, addr + len)\n        FS.msync(stream, buffer, offset, len, flags)\n      },\n      varargs: undefined,\n      get: function() {\n        SYSCALLS.varargs += 4\n        var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]\n        return ret\n      },\n      getStr: function(ptr) {\n        var ret = UTF8ToString(ptr)\n        return ret\n      },\n      getStreamFromFD: function(fd) {\n        var stream = FS.getStream(fd)\n        if (!stream) throw new FS.ErrnoError(8)\n        return stream\n      },\n    }\n    function ___syscall_fcntl64(fd, cmd, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (cmd) {\n          case 0: {\n            var arg = SYSCALLS.get()\n            if (arg < 0) {\n              return -28\n            }\n            var newStream\n            newStream = FS.createStream(stream, arg)\n            return newStream.fd\n          }\n          case 1:\n          case 2:\n            return 0\n          case 3:\n            return stream.flags\n          case 4: {\n            var arg = SYSCALLS.get()\n            stream.flags |= arg\n            return 0\n          }\n          case 5: {\n            var arg = SYSCALLS.get()\n            var offset = 0\n            HEAP16[(arg + offset) >> 1] = 2\n            return 0\n          }\n          case 6:\n          case 7:\n            return 0\n          case 16:\n          case 8:\n            return -28\n          case 9:\n            setErrNo(28)\n            return -1\n          default: {\n            return -28\n          }\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_getcwd(buf, size) {\n      try {\n        if (size === 0) return -28\n        var cwd = FS.cwd()\n        var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1\n        if (size < cwdLengthInBytes) return -68\n        stringToUTF8(cwd, buf, size)\n        return cwdLengthInBytes\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_ioctl(fd, op, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (op) {\n          case 21509:\n          case 21505: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21510:\n          case 21511:\n          case 21512:\n          case 21506:\n          case 21507:\n          case 21508: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21519: {\n            if (!stream.tty) return -59\n            var argp = SYSCALLS.get()\n            HEAP32[argp >> 2] = 0\n            return 0\n          }\n          case 21520: {\n            if (!stream.tty) return -59\n            return -28\n          }\n          case 21531: {\n            var argp = SYSCALLS.get()\n            return FS.ioctl(stream, op, argp)\n          }\n          case 21523: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21524: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          default:\n            return -28\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_openat(dirfd, path, flags, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        var mode = varargs ? SYSCALLS.get() : 0\n        return FS.open(path, flags, mode).fd\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_readlinkat(dirfd, path, buf, bufsize) {\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        if (bufsize <= 0) return -28\n        var ret = FS.readlink(path)\n        var len = Math.min(bufsize, lengthBytesUTF8(ret))\n        var endChar = HEAP8[buf + len]\n        stringToUTF8(ret, buf, bufsize + 1)\n        HEAP8[buf + len] = endChar\n        return len\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_stat64(path, buf) {\n      try {\n        path = SYSCALLS.getStr(path)\n        return SYSCALLS.doStat(FS.stat, path, buf)\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function _abort() {\n      abort('')\n    }\n    function _emscripten_memcpy_big(dest, src, num) {\n      HEAPU8.copyWithin(dest, src, src + num)\n    }\n    function getHeapMax() {\n      return 2147483648\n    }\n    function emscripten_realloc_buffer(size) {\n      try {\n        wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16)\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        return 1\n      } catch (e) {}\n    }\n    function _emscripten_resize_heap(requestedSize) {\n      var oldSize = HEAPU8.length\n      requestedSize = requestedSize >>> 0\n      var maxHeapSize = getHeapMax()\n      if (requestedSize > maxHeapSize) {\n        return false\n      }\n      let alignUp = (x, multiple) =>\n        x + ((multiple - (x % multiple)) % multiple)\n      for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {\n        var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown)\n        overGrownHeapSize = Math.min(\n          overGrownHeapSize,\n          requestedSize + 100663296\n        )\n        var newSize = Math.min(\n          maxHeapSize,\n          alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)\n        )\n        var replacement = emscripten_realloc_buffer(newSize)\n        if (replacement) {\n          return true\n        }\n      }\n      return false\n    }\n    var ENV = {}\n    function getExecutableName() {\n      return thisProgram || './this.program'\n    }\n    function getEnvStrings() {\n      if (!getEnvStrings.strings) {\n        var lang =\n          (\n            (typeof navigator == 'object' &&\n              navigator.languages &&\n              navigator.languages[0]) ||\n            'C'\n          ).replace('-', '_') + '.UTF-8'\n        var env = {\n          USER: 'web_user',\n          LOGNAME: 'web_user',\n          PATH: '/',\n          PWD: '/',\n          HOME: '/home/web_user',\n          LANG: lang,\n          _: getExecutableName(),\n        }\n        for (var x in ENV) {\n          if (ENV[x] === undefined) delete env[x]\n          else env[x] = ENV[x]\n        }\n        var strings = []\n        for (var x in env) {\n          strings.push(x + '=' + env[x])\n        }\n        getEnvStrings.strings = strings\n      }\n      return getEnvStrings.strings\n    }\n    function writeAsciiToMemory(str, buffer, dontAddNull) {\n      for (var i = 0; i < str.length; ++i) {\n        HEAP8[buffer++ >> 0] = str.charCodeAt(i)\n      }\n      if (!dontAddNull) HEAP8[buffer >> 0] = 0\n    }\n    function _environ_get(__environ, environ_buf) {\n      var bufSize = 0\n      getEnvStrings().forEach(function(string, i) {\n        var ptr = environ_buf + bufSize\n        HEAPU32[(__environ + i * 4) >> 2] = ptr\n        writeAsciiToMemory(string, ptr)\n        bufSize += string.length + 1\n      })\n      return 0\n    }\n    function _environ_sizes_get(penviron_count, penviron_buf_size) {\n      var strings = getEnvStrings()\n      HEAPU32[penviron_count >> 2] = strings.length\n      var bufSize = 0\n      strings.forEach(function(string) {\n        bufSize += string.length + 1\n      })\n      HEAPU32[penviron_buf_size >> 2] = bufSize\n      return 0\n    }\n    function _proc_exit(code) {\n      EXITSTATUS = code\n      if (!keepRuntimeAlive()) {\n        if (Module['onExit']) Module['onExit'](code)\n        ABORT = true\n      }\n      quit_(code, new ExitStatus(code))\n    }\n    function exitJS(status, implicit) {\n      EXITSTATUS = status\n      _proc_exit(status)\n    }\n    var _exit = exitJS\n    function _fd_close(fd) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.close(stream)\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doReadv(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.read(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n        if (curr < len) break\n      }\n      return ret\n    }\n    function _fd_read(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doReadv(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function convertI32PairToI53Checked(lo, hi) {\n      return (hi + 2097152) >>> 0 < 4194305 - !!lo\n        ? (lo >>> 0) + hi * 4294967296\n        : NaN\n    }\n    function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {\n      try {\n        var offset = convertI32PairToI53Checked(offset_low, offset_high)\n        if (isNaN(offset)) return 61\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.llseek(stream, offset, whence)\n        ;(tempI64 = [\n          stream.position >>> 0,\n          ((tempDouble = stream.position),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[newOffset >> 2] = tempI64[0]),\n          (HEAP32[(newOffset + 4) >> 2] = tempI64[1])\n        if (stream.getdents && offset === 0 && whence === 0)\n          stream.getdents = null\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doWritev(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.write(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n      }\n      return ret\n    }\n    function _fd_write(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doWritev(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function __isLeapYear(year) {\n      return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n    }\n    function __arraySum(array, index) {\n      var sum = 0\n      for (var i = 0; i <= index; sum += array[i++]) {}\n      return sum\n    }\n    var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    function __addDays(date, days) {\n      var newDate = new Date(date.getTime())\n      while (days > 0) {\n        var leap = __isLeapYear(newDate.getFullYear())\n        var currentMonth = newDate.getMonth()\n        var daysInCurrentMonth = (leap\n          ? __MONTH_DAYS_LEAP\n          : __MONTH_DAYS_REGULAR)[currentMonth]\n        if (days > daysInCurrentMonth - newDate.getDate()) {\n          days -= daysInCurrentMonth - newDate.getDate() + 1\n          newDate.setDate(1)\n          if (currentMonth < 11) {\n            newDate.setMonth(currentMonth + 1)\n          } else {\n            newDate.setMonth(0)\n            newDate.setFullYear(newDate.getFullYear() + 1)\n          }\n        } else {\n          newDate.setDate(newDate.getDate() + days)\n          return newDate\n        }\n      }\n      return newDate\n    }\n    function writeArrayToMemory(array, buffer) {\n      HEAP8.set(array, buffer)\n    }\n    function _strftime(s, maxsize, format, tm) {\n      var tm_zone = HEAP32[(tm + 40) >> 2]\n      var date = {\n        tm_sec: HEAP32[tm >> 2],\n        tm_min: HEAP32[(tm + 4) >> 2],\n        tm_hour: HEAP32[(tm + 8) >> 2],\n        tm_mday: HEAP32[(tm + 12) >> 2],\n        tm_mon: HEAP32[(tm + 16) >> 2],\n        tm_year: HEAP32[(tm + 20) >> 2],\n        tm_wday: HEAP32[(tm + 24) >> 2],\n        tm_yday: HEAP32[(tm + 28) >> 2],\n        tm_isdst: HEAP32[(tm + 32) >> 2],\n        tm_gmtoff: HEAP32[(tm + 36) >> 2],\n        tm_zone: tm_zone ? UTF8ToString(tm_zone) : '',\n      }\n      var pattern = UTF8ToString(format)\n      var EXPANSION_RULES_1 = {\n        '%c': '%a %b %d %H:%M:%S %Y',\n        '%D': '%m/%d/%y',\n        '%F': '%Y-%m-%d',\n        '%h': '%b',\n        '%r': '%I:%M:%S %p',\n        '%R': '%H:%M',\n        '%T': '%H:%M:%S',\n        '%x': '%m/%d/%y',\n        '%X': '%H:%M:%S',\n        '%Ec': '%c',\n        '%EC': '%C',\n        '%Ex': '%m/%d/%y',\n        '%EX': '%H:%M:%S',\n        '%Ey': '%y',\n        '%EY': '%Y',\n        '%Od': '%d',\n        '%Oe': '%e',\n        '%OH': '%H',\n        '%OI': '%I',\n        '%Om': '%m',\n        '%OM': '%M',\n        '%OS': '%S',\n        '%Ou': '%u',\n        '%OU': '%U',\n        '%OV': '%V',\n        '%Ow': '%w',\n        '%OW': '%W',\n        '%Oy': '%y',\n      }\n      for (var rule in EXPANSION_RULES_1) {\n        pattern = pattern.replace(\n          new RegExp(rule, 'g'),\n          EXPANSION_RULES_1[rule]\n        )\n      }\n      var WEEKDAYS = [\n        'Sunday',\n        'Monday',\n        'Tuesday',\n        'Wednesday',\n        'Thursday',\n        'Friday',\n        'Saturday',\n      ]\n      var MONTHS = [\n        'January',\n        'February',\n        'March',\n        'April',\n        'May',\n        'June',\n        'July',\n        'August',\n        'September',\n        'October',\n        'November',\n        'December',\n      ]\n      function leadingSomething(value, digits, character) {\n        var str = typeof value == 'number' ? value.toString() : value || ''\n        while (str.length < digits) {\n          str = character[0] + str\n        }\n        return str\n      }\n      function leadingNulls(value, digits) {\n        return leadingSomething(value, digits, '0')\n      }\n      function compareByDay(date1, date2) {\n        function sgn(value) {\n          return value < 0 ? -1 : value > 0 ? 1 : 0\n        }\n        var compare\n        if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) {\n          if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) {\n            compare = sgn(date1.getDate() - date2.getDate())\n          }\n        }\n        return compare\n      }\n      function getFirstWeekStartDate(janFourth) {\n        switch (janFourth.getDay()) {\n          case 0:\n            return new Date(janFourth.getFullYear() - 1, 11, 29)\n          case 1:\n            return janFourth\n          case 2:\n            return new Date(janFourth.getFullYear(), 0, 3)\n          case 3:\n            return new Date(janFourth.getFullYear(), 0, 2)\n          case 4:\n            return new Date(janFourth.getFullYear(), 0, 1)\n          case 5:\n            return new Date(janFourth.getFullYear() - 1, 11, 31)\n          case 6:\n            return new Date(janFourth.getFullYear() - 1, 11, 30)\n        }\n      }\n      function getWeekBasedYear(date) {\n        var thisDate = __addDays(\n          new Date(date.tm_year + 1900, 0, 1),\n          date.tm_yday\n        )\n        var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4)\n        var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4)\n        var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear)\n        var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear)\n        if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {\n          if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {\n            return thisDate.getFullYear() + 1\n          }\n          return thisDate.getFullYear()\n        }\n        return thisDate.getFullYear() - 1\n      }\n      var EXPANSION_RULES_2 = {\n        '%a': function(date) {\n          return WEEKDAYS[date.tm_wday].substring(0, 3)\n        },\n        '%A': function(date) {\n          return WEEKDAYS[date.tm_wday]\n        },\n        '%b': function(date) {\n          return MONTHS[date.tm_mon].substring(0, 3)\n        },\n        '%B': function(date) {\n          return MONTHS[date.tm_mon]\n        },\n        '%C': function(date) {\n          var year = date.tm_year + 1900\n          return leadingNulls((year / 100) | 0, 2)\n        },\n        '%d': function(date) {\n          return leadingNulls(date.tm_mday, 2)\n        },\n        '%e': function(date) {\n          return leadingSomething(date.tm_mday, 2, ' ')\n        },\n        '%g': function(date) {\n          return getWeekBasedYear(date)\n            .toString()\n            .substring(2)\n        },\n        '%G': function(date) {\n          return getWeekBasedYear(date)\n        },\n        '%H': function(date) {\n          return leadingNulls(date.tm_hour, 2)\n        },\n        '%I': function(date) {\n          var twelveHour = date.tm_hour\n          if (twelveHour == 0) twelveHour = 12\n          else if (twelveHour > 12) twelveHour -= 12\n          return leadingNulls(twelveHour, 2)\n        },\n        '%j': function(date) {\n          return leadingNulls(\n            date.tm_mday +\n              __arraySum(\n                __isLeapYear(date.tm_year + 1900)\n                  ? __MONTH_DAYS_LEAP\n                  : __MONTH_DAYS_REGULAR,\n                date.tm_mon - 1\n              ),\n            3\n          )\n        },\n        '%m': function(date) {\n          return leadingNulls(date.tm_mon + 1, 2)\n        },\n        '%M': function(date) {\n          return leadingNulls(date.tm_min, 2)\n        },\n        '%n': function() {\n          return '\\n'\n        },\n        '%p': function(date) {\n          if (date.tm_hour >= 0 && date.tm_hour < 12) {\n            return 'AM'\n          }\n          return 'PM'\n        },\n        '%S': function(date) {\n          return leadingNulls(date.tm_sec, 2)\n        },\n        '%t': function() {\n          return '\\t'\n        },\n        '%u': function(date) {\n          return date.tm_wday || 7\n        },\n        '%U': function(date) {\n          var days = date.tm_yday + 7 - date.tm_wday\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%V': function(date) {\n          var val = Math.floor(\n            (date.tm_yday + 7 - ((date.tm_wday + 6) % 7)) / 7\n          )\n          if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) {\n            val++\n          }\n          if (!val) {\n            val = 52\n            var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7\n            if (\n              dec31 == 4 ||\n              (dec31 == 5 && __isLeapYear((date.tm_year % 400) - 1))\n            ) {\n              val++\n            }\n          } else if (val == 53) {\n            var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7\n            if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) val = 1\n          }\n          return leadingNulls(val, 2)\n        },\n        '%w': function(date) {\n          return date.tm_wday\n        },\n        '%W': function(date) {\n          var days = date.tm_yday + 7 - ((date.tm_wday + 6) % 7)\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%y': function(date) {\n          return (date.tm_year + 1900).toString().substring(2)\n        },\n        '%Y': function(date) {\n          return date.tm_year + 1900\n        },\n        '%z': function(date) {\n          var off = date.tm_gmtoff\n          var ahead = off >= 0\n          off = Math.abs(off) / 60\n          off = (off / 60) * 100 + (off % 60)\n          return (ahead ? '+' : '-') + String('0000' + off).slice(-4)\n        },\n        '%Z': function(date) {\n          return date.tm_zone\n        },\n        '%%': function() {\n          return '%'\n        },\n      }\n      pattern = pattern.replace(/%%/g, '\\0\\0')\n      for (var rule in EXPANSION_RULES_2) {\n        if (pattern.includes(rule)) {\n          pattern = pattern.replace(\n            new RegExp(rule, 'g'),\n            EXPANSION_RULES_2[rule](date)\n          )\n        }\n      }\n      pattern = pattern.replace(/\\0\\0/g, '%')\n      var bytes = intArrayFromString(pattern, false)\n      if (bytes.length > maxsize) {\n        return 0\n      }\n      writeArrayToMemory(bytes, s)\n      return bytes.length - 1\n    }\n    function _strftime_l(s, maxsize, format, tm, loc) {\n      return _strftime(s, maxsize, format, tm)\n    }\n    function handleException(e) {\n      if (e instanceof ExitStatus || e == 'unwind') {\n        return EXITSTATUS\n      }\n      quit_(1, e)\n    }\n    function allocateUTF8OnStack(str) {\n      var size = lengthBytesUTF8(str) + 1\n      var ret = stackAlloc(size)\n      stringToUTF8Array(str, HEAP8, ret, size)\n      return ret\n    }\n    function getCFunc(ident) {\n      var func = Module['_' + ident]\n      return func\n    }\n    function ccall(ident, returnType, argTypes, args, opts) {\n      var toC = {\n        string: str => {\n          var ret = 0\n          if (str !== null && str !== undefined && str !== 0) {\n            var len = (str.length << 2) + 1\n            ret = stackAlloc(len)\n            stringToUTF8(str, ret, len)\n          }\n          return ret\n        },\n        array: arr => {\n          var ret = stackAlloc(arr.length)\n          writeArrayToMemory(arr, ret)\n          return ret\n        },\n      }\n      function convertReturnValue(ret) {\n        if (returnType === 'string') {\n          return UTF8ToString(ret)\n        }\n        if (returnType === 'boolean') return Boolean(ret)\n        return ret\n      }\n      var func = getCFunc(ident)\n      var cArgs = []\n      var stack = 0\n      if (args) {\n        for (var i = 0; i < args.length; i++) {\n          var converter = toC[argTypes[i]]\n          if (converter) {\n            if (stack === 0) stack = stackSave()\n            cArgs[i] = converter(args[i])\n          } else {\n            cArgs[i] = args[i]\n          }\n        }\n      }\n      var ret = func.apply(null, cArgs)\n      function onDone(ret) {\n        if (stack !== 0) stackRestore(stack)\n        return convertReturnValue(ret)\n      }\n      ret = onDone(ret)\n      return ret\n    }\n    function cwrap(ident, returnType, argTypes, opts) {\n      argTypes = argTypes || []\n      var numericArgs = argTypes.every(\n        type => type === 'number' || type === 'boolean'\n      )\n      var numericRet = returnType !== 'string'\n      if (numericRet && numericArgs && !opts) {\n        return getCFunc(ident)\n      }\n      return function() {\n        return ccall(ident, returnType, argTypes, arguments, opts)\n      }\n    }\n    function AsciiToString(ptr) {\n      var str = ''\n      while (1) {\n        var ch = HEAPU8[ptr++ >> 0]\n        if (!ch) return str\n        str += String.fromCharCode(ch)\n      }\n    }\n    var FSNode = function(parent, name, mode, rdev) {\n      if (!parent) {\n        parent = this\n      }\n      this.parent = parent\n      this.mount = parent.mount\n      this.mounted = null\n      this.id = FS.nextInode++\n      this.name = name\n      this.mode = mode\n      this.node_ops = {}\n      this.stream_ops = {}\n      this.rdev = rdev\n    }\n    var readMode = 292 | 73\n    var writeMode = 146\n    Object.defineProperties(FSNode.prototype, {\n      read: {\n        get: function() {\n          return (this.mode & readMode) === readMode\n        },\n        set: function(val) {\n          val ? (this.mode |= readMode) : (this.mode &= ~readMode)\n        },\n      },\n      write: {\n        get: function() {\n          return (this.mode & writeMode) === writeMode\n        },\n        set: function(val) {\n          val ? (this.mode |= writeMode) : (this.mode &= ~writeMode)\n        },\n      },\n      isFolder: {\n        get: function() {\n          return FS.isDir(this.mode)\n        },\n      },\n      isDevice: {\n        get: function() {\n          return FS.isChrdev(this.mode)\n        },\n      },\n    })\n    FS.FSNode = FSNode\n    FS.staticInit()\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_unlink'] = FS.unlink\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    if (ENVIRONMENT_IS_NODE) {\n      NODEFS.staticInit()\n    }\n    ERRNO_CODES = {\n      EPERM: 63,\n      ENOENT: 44,\n      ESRCH: 71,\n      EINTR: 27,\n      EIO: 29,\n      ENXIO: 60,\n      E2BIG: 1,\n      ENOEXEC: 45,\n      EBADF: 8,\n      ECHILD: 12,\n      EAGAIN: 6,\n      EWOULDBLOCK: 6,\n      ENOMEM: 48,\n      EACCES: 2,\n      EFAULT: 21,\n      ENOTBLK: 105,\n      EBUSY: 10,\n      EEXIST: 20,\n      EXDEV: 75,\n      ENODEV: 43,\n      ENOTDIR: 54,\n      EISDIR: 31,\n      EINVAL: 28,\n      ENFILE: 41,\n      EMFILE: 33,\n      ENOTTY: 59,\n      ETXTBSY: 74,\n      EFBIG: 22,\n      ENOSPC: 51,\n      ESPIPE: 70,\n      EROFS: 69,\n      EMLINK: 34,\n      EPIPE: 64,\n      EDOM: 18,\n      ERANGE: 68,\n      ENOMSG: 49,\n      EIDRM: 24,\n      ECHRNG: 106,\n      EL2NSYNC: 156,\n      EL3HLT: 107,\n      EL3RST: 108,\n      ELNRNG: 109,\n      EUNATCH: 110,\n      ENOCSI: 111,\n      EL2HLT: 112,\n      EDEADLK: 16,\n      ENOLCK: 46,\n      EBADE: 113,\n      EBADR: 114,\n      EXFULL: 115,\n      ENOANO: 104,\n      EBADRQC: 103,\n      EBADSLT: 102,\n      EDEADLOCK: 16,\n      EBFONT: 101,\n      ENOSTR: 100,\n      ENODATA: 116,\n      ETIME: 117,\n      ENOSR: 118,\n      ENONET: 119,\n      ENOPKG: 120,\n      EREMOTE: 121,\n      ENOLINK: 47,\n      EADV: 122,\n      ESRMNT: 123,\n      ECOMM: 124,\n      EPROTO: 65,\n      EMULTIHOP: 36,\n      EDOTDOT: 125,\n      EBADMSG: 9,\n      ENOTUNIQ: 126,\n      EBADFD: 127,\n      EREMCHG: 128,\n      ELIBACC: 129,\n      ELIBBAD: 130,\n      ELIBSCN: 131,\n      ELIBMAX: 132,\n      ELIBEXEC: 133,\n      ENOSYS: 52,\n      ENOTEMPTY: 55,\n      ENAMETOOLONG: 37,\n      ELOOP: 32,\n      EOPNOTSUPP: 138,\n      EPFNOSUPPORT: 139,\n      ECONNRESET: 15,\n      ENOBUFS: 42,\n      EAFNOSUPPORT: 5,\n      EPROTOTYPE: 67,\n      ENOTSOCK: 57,\n      ENOPROTOOPT: 50,\n      ESHUTDOWN: 140,\n      ECONNREFUSED: 14,\n      EADDRINUSE: 3,\n      ECONNABORTED: 13,\n      ENETUNREACH: 40,\n      ENETDOWN: 38,\n      ETIMEDOUT: 73,\n      EHOSTDOWN: 142,\n      EHOSTUNREACH: 23,\n      EINPROGRESS: 26,\n      EALREADY: 7,\n      EDESTADDRREQ: 17,\n      EMSGSIZE: 35,\n      EPROTONOSUPPORT: 66,\n      ESOCKTNOSUPPORT: 137,\n      EADDRNOTAVAIL: 4,\n      ENETRESET: 39,\n      EISCONN: 30,\n      ENOTCONN: 53,\n      ETOOMANYREFS: 141,\n      EUSERS: 136,\n      EDQUOT: 19,\n      ESTALE: 72,\n      ENOTSUP: 138,\n      ENOMEDIUM: 148,\n      EILSEQ: 25,\n      EOVERFLOW: 61,\n      ECANCELED: 11,\n      ENOTRECOVERABLE: 56,\n      EOWNERDEAD: 62,\n      ESTRPIPE: 135,\n    }\n    var asmLibraryArg = {\n      a: ___cxa_throw,\n      d: ___syscall_fcntl64,\n      r: ___syscall_getcwd,\n      i: ___syscall_ioctl,\n      j: ___syscall_openat,\n      n: ___syscall_readlinkat,\n      o: ___syscall_stat64,\n      b: _abort,\n      f: _emscripten_memcpy_big,\n      m: _emscripten_resize_heap,\n      p: _environ_get,\n      q: _environ_sizes_get,\n      c: _exit,\n      e: _fd_close,\n      h: _fd_read,\n      k: _fd_seek,\n      g: _fd_write,\n      l: _strftime_l,\n    }\n    var asm = createWasm()\n    var ___wasm_call_ctors = (Module['___wasm_call_ctors'] = function() {\n      return (___wasm_call_ctors = Module['___wasm_call_ctors'] =\n        Module['asm']['t']).apply(null, arguments)\n    })\n    var _main = (Module['_main'] = function() {\n      return (_main = Module['_main'] = Module['asm']['u']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___errno_location = (Module['___errno_location'] = function() {\n      return (___errno_location = Module['___errno_location'] =\n        Module['asm']['v']).apply(null, arguments)\n    })\n    var _itk_wasm_input_array_alloc = (Module[\n      '_itk_wasm_input_array_alloc'\n    ] = function() {\n      return (_itk_wasm_input_array_alloc = Module[\n        '_itk_wasm_input_array_alloc'\n      ] = Module['asm']['w']).apply(null, arguments)\n    })\n    var _itk_wasm_input_json_alloc = (Module[\n      '_itk_wasm_input_json_alloc'\n    ] = function() {\n      return (_itk_wasm_input_json_alloc = Module[\n        '_itk_wasm_input_json_alloc'\n      ] = Module['asm']['x']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_address = (Module[\n      '_itk_wasm_output_json_address'\n    ] = function() {\n      return (_itk_wasm_output_json_address = Module[\n        '_itk_wasm_output_json_address'\n      ] = Module['asm']['y']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_size = (Module[\n      '_itk_wasm_output_json_size'\n    ] = function() {\n      return (_itk_wasm_output_json_size = Module[\n        '_itk_wasm_output_json_size'\n      ] = Module['asm']['z']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_address = (Module[\n      '_itk_wasm_output_array_address'\n    ] = function() {\n      return (_itk_wasm_output_array_address = Module[\n        '_itk_wasm_output_array_address'\n      ] = Module['asm']['A']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_size = (Module[\n      '_itk_wasm_output_array_size'\n    ] = function() {\n      return (_itk_wasm_output_array_size = Module[\n        '_itk_wasm_output_array_size'\n      ] = Module['asm']['B']).apply(null, arguments)\n    })\n    var _itk_wasm_free_all = (Module['_itk_wasm_free_all'] = function() {\n      return (_itk_wasm_free_all = Module['_itk_wasm_free_all'] =\n        Module['asm']['C']).apply(null, arguments)\n    })\n    var stackSave = (Module['stackSave'] = function() {\n      return (stackSave = Module['stackSave'] = Module['asm']['E']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackRestore = (Module['stackRestore'] = function() {\n      return (stackRestore = Module['stackRestore'] = Module['asm']['F']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackAlloc = (Module['stackAlloc'] = function() {\n      return (stackAlloc = Module['stackAlloc'] = Module['asm']['G']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___cxa_is_pointer_type = (Module[\n      '___cxa_is_pointer_type'\n    ] = function() {\n      return (___cxa_is_pointer_type = Module['___cxa_is_pointer_type'] =\n        Module['asm']['H']).apply(null, arguments)\n    })\n    Module['addRunDependency'] = addRunDependency\n    Module['removeRunDependency'] = removeRunDependency\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    Module['FS_unlink'] = FS.unlink\n    Module['callMain'] = callMain\n    Module['ccall'] = ccall\n    Module['cwrap'] = cwrap\n    Module['AsciiToString'] = AsciiToString\n    Module['writeArrayToMemory'] = writeArrayToMemory\n    Module['writeAsciiToMemory'] = writeAsciiToMemory\n    var calledRun\n    dependenciesFulfilled = function runCaller() {\n      if (!calledRun) run()\n      if (!calledRun) dependenciesFulfilled = runCaller\n    }\n    function callMain(args) {\n      var entryFunction = Module['_main']\n      args = args || []\n      args.unshift(thisProgram)\n      var argc = args.length\n      var argv = stackAlloc((argc + 1) * 4)\n      var argv_ptr = argv >> 2\n      args.forEach(arg => {\n        HEAP32[argv_ptr++] = allocateUTF8OnStack(arg)\n      })\n      HEAP32[argv_ptr] = 0\n      try {\n        var ret = entryFunction(argc, argv)\n        exitJS(ret, true)\n        return ret\n      } catch (e) {\n        return handleException(e)\n      }\n    }\n    function run(args) {\n      args = args || arguments_\n      if (runDependencies > 0) {\n        return\n      }\n      preRun()\n      if (runDependencies > 0) {\n        return\n      }\n      function doRun() {\n        if (calledRun) return\n        calledRun = true\n        Module['calledRun'] = true\n        if (ABORT) return\n        initRuntime()\n        preMain()\n        readyPromiseResolve(Module)\n        if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']()\n        if (shouldRunNow) callMain(args)\n        postRun()\n      }\n      if (Module['setStatus']) {\n        Module['setStatus']('Running...')\n        setTimeout(function() {\n          setTimeout(function() {\n            Module['setStatus']('')\n          }, 1)\n          doRun()\n        }, 1)\n      } else {\n        doRun()\n      }\n    }\n    if (Module['preInit']) {\n      if (typeof Module['preInit'] == 'function')\n        Module['preInit'] = [Module['preInit']]\n      while (Module['preInit'].length > 0) {\n        Module['preInit'].pop()()\n      }\n    }\n    var shouldRunNow = false\n    if (Module['noInitialRun']) shouldRunNow = false\n    run()\n    Module.mountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      if (FS.isDir(containingDir) || containingDir === '/') {\n        return\n      }\n      var currentDir = '/'\n      var splitContainingDir = containingDir.split(path.sep)\n      for (var ii = 1; ii < splitContainingDir.length; ii++) {\n        currentDir += splitContainingDir[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n      FS.mount(NODEFS, { root: containingDir }, currentDir)\n      return currentDir + path.basename(filePath)\n    }\n    Module.unmountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      FS.unmount(containingDir)\n    }\n    Module.fs_mkdirs = function(dirs) {\n      var currentDir = '/'\n      var splitDirs = dirs.split('/')\n      for (var ii = 1; ii < splitDirs.length; ++ii) {\n        currentDir += splitDirs[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n    }\n    Module.fs_readFile = function(path, opts) {\n      return FS.readFile(path, opts)\n    }\n    Module.fs_writeFile = function(path, data, opts) {\n      return FS.writeFile(path, data, opts)\n    }\n    Module.fs_unlink = function(path) {\n      return FS.unlink(path)\n    }\n    Module.fs_open = function(path, flags, mode) {\n      return FS.open(path, flags, mode)\n    }\n    Module.fs_stat = function(path) {\n      return FS.stat(path)\n    }\n    Module.fs_read = function(stream, buffer, offset, length, position) {\n      return FS.read(stream, buffer, offset, length, position)\n    }\n    Module.fs_close = function(stream) {\n      return FS.close(stream)\n    }\n\n    return Downsample.ready\n  }\n})()\nif (typeof exports === 'object' && typeof module === 'object')\n  module.exports = Downsample\nelse if (typeof define === 'function' && define['amd'])\n  define([], function() {\n    return Downsample\n  })\nelse if (typeof exports === 'object') exports['Downsample'] = Downsample\n"
  },
  {
    "path": "src/IO/Downsample/emscripten-build/DownsampleLabelImage.js",
    "content": "var DownsampleLabelImage = (() => {\n  var _scriptDir = import.meta.url\n\n  return async function(DownsampleLabelImage) {\n    DownsampleLabelImage = DownsampleLabelImage || {}\n\n    var Module =\n      typeof DownsampleLabelImage != 'undefined' ? DownsampleLabelImage : {}\n    var readyPromiseResolve, readyPromiseReject\n    Module['ready'] = new Promise(function(resolve, reject) {\n      readyPromiseResolve = resolve\n      readyPromiseReject = reject\n    })\n    var mStdout = null\n    var mStderr = null\n    Module['resetModuleStdout'] = function() {\n      mStdout = ''\n    }\n    Module['resetModuleStderr'] = function() {\n      mStderr = ''\n    }\n    Module['print'] = function(text) {\n      console.log(text)\n      mStdout += text + '\\n'\n    }\n    Module['printErr'] = function(text) {\n      console.error(text)\n      mStderr += text + '\\n'\n    }\n    Module['getModuleStdout'] = function() {\n      return mStdout\n    }\n    Module['getModuleStderr'] = function() {\n      return mStderr\n    }\n    var moduleOverrides = Object.assign({}, Module)\n    var arguments_ = []\n    var thisProgram = './this.program'\n    var quit_ = (status, toThrow) => {\n      throw toThrow\n    }\n    var ENVIRONMENT_IS_WEB = typeof window == 'object'\n    var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'\n    var ENVIRONMENT_IS_NODE =\n      typeof process == 'object' &&\n      typeof process.versions == 'object' &&\n      typeof process.versions.node == 'string'\n    var scriptDirectory = ''\n    function locateFile(path) {\n      if (Module['locateFile']) {\n        return Module['locateFile'](path, scriptDirectory)\n      }\n      return scriptDirectory + path\n    }\n    var read_, readAsync, readBinary, setWindowTitle\n    function logExceptionOnExit(e) {\n      if (e instanceof ExitStatus) return\n      let toLog = e\n      err('exiting due to exception: ' + toLog)\n    }\n    if (ENVIRONMENT_IS_NODE) {\n      const { createRequire: createRequire } = await import('module')\n      var require = createRequire(import.meta.url)\n      var fs = require('fs')\n      var nodePath = require('path')\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = nodePath.dirname(scriptDirectory) + '/'\n      } else {\n        scriptDirectory = require('url').fileURLToPath(\n          new URL('./', import.meta.url)\n        )\n      }\n      read_ = (filename, binary) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        return fs.readFileSync(filename, binary ? undefined : 'utf8')\n      }\n      readBinary = filename => {\n        var ret = read_(filename, true)\n        if (!ret.buffer) {\n          ret = new Uint8Array(ret)\n        }\n        return ret\n      }\n      readAsync = (filename, onload, onerror) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        fs.readFile(filename, function(err, data) {\n          if (err) onerror(err)\n          else onload(data.buffer)\n        })\n      }\n      if (process['argv'].length > 1) {\n        thisProgram = process['argv'][1].replace(/\\\\/g, '/')\n      }\n      arguments_ = process['argv'].slice(2)\n      process['on']('uncaughtException', function(ex) {\n        if (!(ex instanceof ExitStatus)) {\n          throw ex\n        }\n      })\n      process['on']('unhandledRejection', function(reason) {\n        throw reason\n      })\n      quit_ = (status, toThrow) => {\n        if (keepRuntimeAlive()) {\n          process['exitCode'] = status\n          throw toThrow\n        }\n        logExceptionOnExit(toThrow)\n        process['exit'](status)\n      }\n      Module['inspect'] = function() {\n        return '[Emscripten Module object]'\n      }\n    } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = self.location.href\n      } else if (typeof document != 'undefined' && document.currentScript) {\n        scriptDirectory = document.currentScript.src\n      }\n      if (_scriptDir) {\n        scriptDirectory = _scriptDir\n      }\n      if (scriptDirectory.indexOf('blob:') !== 0) {\n        scriptDirectory = scriptDirectory.substr(\n          0,\n          scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1\n        )\n      } else {\n        scriptDirectory = ''\n      }\n      {\n        read_ = url => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, false)\n          xhr.send(null)\n          return xhr.responseText\n        }\n        if (ENVIRONMENT_IS_WORKER) {\n          readBinary = url => {\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            xhr.responseType = 'arraybuffer'\n            xhr.send(null)\n            return new Uint8Array(xhr.response)\n          }\n        }\n        readAsync = (url, onload, onerror) => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, true)\n          xhr.responseType = 'arraybuffer'\n          xhr.onload = () => {\n            if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n              onload(xhr.response)\n              return\n            }\n            onerror()\n          }\n          xhr.onerror = onerror\n          xhr.send(null)\n        }\n      }\n      setWindowTitle = title => (document.title = title)\n    } else {\n    }\n    var out = Module['print'] || console.log.bind(console)\n    var err = Module['printErr'] || console.warn.bind(console)\n    Object.assign(Module, moduleOverrides)\n    moduleOverrides = null\n    if (Module['arguments']) arguments_ = Module['arguments']\n    if (Module['thisProgram']) thisProgram = Module['thisProgram']\n    if (Module['quit']) quit_ = Module['quit']\n    var wasmBinary\n    if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']\n    var noExitRuntime = Module['noExitRuntime'] || true\n    if (typeof WebAssembly != 'object') {\n      abort('no native wasm support detected')\n    }\n    var wasmMemory\n    var ABORT = false\n    var EXITSTATUS\n    function assert(condition, text) {\n      if (!condition) {\n        abort(text)\n      }\n    }\n    var UTF8Decoder =\n      typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined\n    function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {\n      var endIdx = idx + maxBytesToRead\n      var endPtr = idx\n      while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr\n      if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {\n        return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr))\n      }\n      var str = ''\n      while (idx < endPtr) {\n        var u0 = heapOrArray[idx++]\n        if (!(u0 & 128)) {\n          str += String.fromCharCode(u0)\n          continue\n        }\n        var u1 = heapOrArray[idx++] & 63\n        if ((u0 & 224) == 192) {\n          str += String.fromCharCode(((u0 & 31) << 6) | u1)\n          continue\n        }\n        var u2 = heapOrArray[idx++] & 63\n        if ((u0 & 240) == 224) {\n          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2\n        } else {\n          u0 =\n            ((u0 & 7) << 18) |\n            (u1 << 12) |\n            (u2 << 6) |\n            (heapOrArray[idx++] & 63)\n        }\n        if (u0 < 65536) {\n          str += String.fromCharCode(u0)\n        } else {\n          var ch = u0 - 65536\n          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023))\n        }\n      }\n      return str\n    }\n    function UTF8ToString(ptr, maxBytesToRead) {\n      return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''\n    }\n    function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {\n      if (!(maxBytesToWrite > 0)) return 0\n      var startIdx = outIdx\n      var endIdx = outIdx + maxBytesToWrite - 1\n      for (var i = 0; i < str.length; ++i) {\n        var u = str.charCodeAt(i)\n        if (u >= 55296 && u <= 57343) {\n          var u1 = str.charCodeAt(++i)\n          u = (65536 + ((u & 1023) << 10)) | (u1 & 1023)\n        }\n        if (u <= 127) {\n          if (outIdx >= endIdx) break\n          heap[outIdx++] = u\n        } else if (u <= 2047) {\n          if (outIdx + 1 >= endIdx) break\n          heap[outIdx++] = 192 | (u >> 6)\n          heap[outIdx++] = 128 | (u & 63)\n        } else if (u <= 65535) {\n          if (outIdx + 2 >= endIdx) break\n          heap[outIdx++] = 224 | (u >> 12)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        } else {\n          if (outIdx + 3 >= endIdx) break\n          heap[outIdx++] = 240 | (u >> 18)\n          heap[outIdx++] = 128 | ((u >> 12) & 63)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        }\n      }\n      heap[outIdx] = 0\n      return outIdx - startIdx\n    }\n    function stringToUTF8(str, outPtr, maxBytesToWrite) {\n      return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite)\n    }\n    function lengthBytesUTF8(str) {\n      var len = 0\n      for (var i = 0; i < str.length; ++i) {\n        var c = str.charCodeAt(i)\n        if (c <= 127) {\n          len++\n        } else if (c <= 2047) {\n          len += 2\n        } else if (c >= 55296 && c <= 57343) {\n          len += 4\n          ++i\n        } else {\n          len += 3\n        }\n      }\n      return len\n    }\n    var buffer,\n      HEAP8,\n      HEAPU8,\n      HEAP16,\n      HEAPU16,\n      HEAP32,\n      HEAPU32,\n      HEAPF32,\n      HEAPF64\n    function updateGlobalBufferAndViews(buf) {\n      buffer = buf\n      Module['HEAP8'] = HEAP8 = new Int8Array(buf)\n      Module['HEAP16'] = HEAP16 = new Int16Array(buf)\n      Module['HEAP32'] = HEAP32 = new Int32Array(buf)\n      Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf)\n      Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf)\n      Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf)\n      Module['HEAPF32'] = HEAPF32 = new Float32Array(buf)\n      Module['HEAPF64'] = HEAPF64 = new Float64Array(buf)\n    }\n    var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216\n    var wasmTable\n    var __ATPRERUN__ = []\n    var __ATINIT__ = []\n    var __ATMAIN__ = []\n    var __ATPOSTRUN__ = []\n    var runtimeInitialized = false\n    function keepRuntimeAlive() {\n      return noExitRuntime\n    }\n    function preRun() {\n      if (Module['preRun']) {\n        if (typeof Module['preRun'] == 'function')\n          Module['preRun'] = [Module['preRun']]\n        while (Module['preRun'].length) {\n          addOnPreRun(Module['preRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPRERUN__)\n    }\n    function initRuntime() {\n      runtimeInitialized = true\n      if (!Module['noFSInit'] && !FS.init.initialized) FS.init()\n      FS.ignorePermissions = false\n      TTY.init()\n      callRuntimeCallbacks(__ATINIT__)\n    }\n    function preMain() {\n      callRuntimeCallbacks(__ATMAIN__)\n    }\n    function postRun() {\n      if (Module['postRun']) {\n        if (typeof Module['postRun'] == 'function')\n          Module['postRun'] = [Module['postRun']]\n        while (Module['postRun'].length) {\n          addOnPostRun(Module['postRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPOSTRUN__)\n    }\n    function addOnPreRun(cb) {\n      __ATPRERUN__.unshift(cb)\n    }\n    function addOnInit(cb) {\n      __ATINIT__.unshift(cb)\n    }\n    function addOnPostRun(cb) {\n      __ATPOSTRUN__.unshift(cb)\n    }\n    var runDependencies = 0\n    var runDependencyWatcher = null\n    var dependenciesFulfilled = null\n    function getUniqueRunDependency(id) {\n      return id\n    }\n    function addRunDependency(id) {\n      runDependencies++\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n    }\n    function removeRunDependency(id) {\n      runDependencies--\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n      if (runDependencies == 0) {\n        if (runDependencyWatcher !== null) {\n          clearInterval(runDependencyWatcher)\n          runDependencyWatcher = null\n        }\n        if (dependenciesFulfilled) {\n          var callback = dependenciesFulfilled\n          dependenciesFulfilled = null\n          callback()\n        }\n      }\n    }\n    function abort(what) {\n      if (Module['onAbort']) {\n        Module['onAbort'](what)\n      }\n      what = 'Aborted(' + what + ')'\n      err(what)\n      ABORT = true\n      EXITSTATUS = 1\n      what += '. Build with -sASSERTIONS for more info.'\n      var e = new WebAssembly.RuntimeError(what)\n      readyPromiseReject(e)\n      throw e\n    }\n    var dataURIPrefix = 'data:application/octet-stream;base64,'\n    function isDataURI(filename) {\n      return filename.startsWith(dataURIPrefix)\n    }\n    function isFileURI(filename) {\n      return filename.startsWith('file://')\n    }\n    var wasmBinaryFile\n    if (Module['locateFile']) {\n      wasmBinaryFile = 'DownsampleLabelImage.wasm'\n      if (!isDataURI(wasmBinaryFile)) {\n        wasmBinaryFile = locateFile(wasmBinaryFile)\n      }\n    } else {\n      wasmBinaryFile = new URL('DownsampleLabelImage.wasm', import.meta.url)\n        .href\n    }\n    function getBinary(file) {\n      try {\n        if (file == wasmBinaryFile && wasmBinary) {\n          return new Uint8Array(wasmBinary)\n        }\n        if (readBinary) {\n          return readBinary(file)\n        }\n        throw 'both async and sync fetching of the wasm failed'\n      } catch (err) {\n        abort(err)\n      }\n    }\n    function getBinaryPromise() {\n      if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {\n        if (typeof fetch == 'function' && !isFileURI(wasmBinaryFile)) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' })\n            .then(function(response) {\n              if (!response['ok']) {\n                throw \"failed to load wasm binary file at '\" +\n                  wasmBinaryFile +\n                  \"'\"\n              }\n              return response['arrayBuffer']()\n            })\n            .catch(function() {\n              return getBinary(wasmBinaryFile)\n            })\n        } else {\n          if (readAsync) {\n            return new Promise(function(resolve, reject) {\n              readAsync(\n                wasmBinaryFile,\n                function(response) {\n                  resolve(new Uint8Array(response))\n                },\n                reject\n              )\n            })\n          }\n        }\n      }\n      return Promise.resolve().then(function() {\n        return getBinary(wasmBinaryFile)\n      })\n    }\n    function createWasm() {\n      var info = { a: asmLibraryArg }\n      function receiveInstance(instance, module) {\n        var exports = instance.exports\n        Module['asm'] = exports\n        wasmMemory = Module['asm']['s']\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        wasmTable = Module['asm']['D']\n        addOnInit(Module['asm']['t'])\n        removeRunDependency('wasm-instantiate')\n      }\n      addRunDependency('wasm-instantiate')\n      function receiveInstantiationResult(result) {\n        receiveInstance(result['instance'])\n      }\n      function instantiateArrayBuffer(receiver) {\n        return getBinaryPromise()\n          .then(function(binary) {\n            return WebAssembly.instantiate(binary, info)\n          })\n          .then(function(instance) {\n            return instance\n          })\n          .then(receiver, function(reason) {\n            err('failed to asynchronously prepare wasm: ' + reason)\n            abort(reason)\n          })\n      }\n      function instantiateAsync() {\n        if (\n          !wasmBinary &&\n          typeof WebAssembly.instantiateStreaming == 'function' &&\n          !isDataURI(wasmBinaryFile) &&\n          !isFileURI(wasmBinaryFile) &&\n          !ENVIRONMENT_IS_NODE &&\n          typeof fetch == 'function'\n        ) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(\n            function(response) {\n              var result = WebAssembly.instantiateStreaming(response, info)\n              return result.then(receiveInstantiationResult, function(reason) {\n                err('wasm streaming compile failed: ' + reason)\n                err('falling back to ArrayBuffer instantiation')\n                return instantiateArrayBuffer(receiveInstantiationResult)\n              })\n            }\n          )\n        } else {\n          return instantiateArrayBuffer(receiveInstantiationResult)\n        }\n      }\n      if (Module['instantiateWasm']) {\n        try {\n          var exports = Module['instantiateWasm'](info, receiveInstance)\n          return exports\n        } catch (e) {\n          err('Module.instantiateWasm callback failed with error: ' + e)\n          readyPromiseReject(e)\n        }\n      }\n      instantiateAsync().catch(readyPromiseReject)\n      return {}\n    }\n    var tempDouble\n    var tempI64\n    function ExitStatus(status) {\n      this.name = 'ExitStatus'\n      this.message = 'Program terminated with exit(' + status + ')'\n      this.status = status\n    }\n    function callRuntimeCallbacks(callbacks) {\n      while (callbacks.length > 0) {\n        callbacks.shift()(Module)\n      }\n    }\n    function ExceptionInfo(excPtr) {\n      this.excPtr = excPtr\n      this.ptr = excPtr - 24\n      this.set_type = function(type) {\n        HEAPU32[(this.ptr + 4) >> 2] = type\n      }\n      this.get_type = function() {\n        return HEAPU32[(this.ptr + 4) >> 2]\n      }\n      this.set_destructor = function(destructor) {\n        HEAPU32[(this.ptr + 8) >> 2] = destructor\n      }\n      this.get_destructor = function() {\n        return HEAPU32[(this.ptr + 8) >> 2]\n      }\n      this.set_refcount = function(refcount) {\n        HEAP32[this.ptr >> 2] = refcount\n      }\n      this.set_caught = function(caught) {\n        caught = caught ? 1 : 0\n        HEAP8[(this.ptr + 12) >> 0] = caught\n      }\n      this.get_caught = function() {\n        return HEAP8[(this.ptr + 12) >> 0] != 0\n      }\n      this.set_rethrown = function(rethrown) {\n        rethrown = rethrown ? 1 : 0\n        HEAP8[(this.ptr + 13) >> 0] = rethrown\n      }\n      this.get_rethrown = function() {\n        return HEAP8[(this.ptr + 13) >> 0] != 0\n      }\n      this.init = function(type, destructor) {\n        this.set_adjusted_ptr(0)\n        this.set_type(type)\n        this.set_destructor(destructor)\n        this.set_refcount(0)\n        this.set_caught(false)\n        this.set_rethrown(false)\n      }\n      this.add_ref = function() {\n        var value = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = value + 1\n      }\n      this.release_ref = function() {\n        var prev = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = prev - 1\n        return prev === 1\n      }\n      this.set_adjusted_ptr = function(adjustedPtr) {\n        HEAPU32[(this.ptr + 16) >> 2] = adjustedPtr\n      }\n      this.get_adjusted_ptr = function() {\n        return HEAPU32[(this.ptr + 16) >> 2]\n      }\n      this.get_exception_ptr = function() {\n        var isPointer = ___cxa_is_pointer_type(this.get_type())\n        if (isPointer) {\n          return HEAPU32[this.excPtr >> 2]\n        }\n        var adjusted = this.get_adjusted_ptr()\n        if (adjusted !== 0) return adjusted\n        return this.excPtr\n      }\n    }\n    var exceptionLast = 0\n    var uncaughtExceptionCount = 0\n    function ___cxa_throw(ptr, type, destructor) {\n      var info = new ExceptionInfo(ptr)\n      info.init(type, destructor)\n      exceptionLast = ptr\n      uncaughtExceptionCount++\n      throw ptr\n    }\n    function setErrNo(value) {\n      HEAP32[___errno_location() >> 2] = value\n      return value\n    }\n    var PATH = {\n      isAbs: path => path.charAt(0) === '/',\n      splitPath: filename => {\n        var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/\n        return splitPathRe.exec(filename).slice(1)\n      },\n      normalizeArray: (parts, allowAboveRoot) => {\n        var up = 0\n        for (var i = parts.length - 1; i >= 0; i--) {\n          var last = parts[i]\n          if (last === '.') {\n            parts.splice(i, 1)\n          } else if (last === '..') {\n            parts.splice(i, 1)\n            up++\n          } else if (up) {\n            parts.splice(i, 1)\n            up--\n          }\n        }\n        if (allowAboveRoot) {\n          for (; up; up--) {\n            parts.unshift('..')\n          }\n        }\n        return parts\n      },\n      normalize: path => {\n        var isAbsolute = PATH.isAbs(path),\n          trailingSlash = path.substr(-1) === '/'\n        path = PATH.normalizeArray(\n          path.split('/').filter(p => !!p),\n          !isAbsolute\n        ).join('/')\n        if (!path && !isAbsolute) {\n          path = '.'\n        }\n        if (path && trailingSlash) {\n          path += '/'\n        }\n        return (isAbsolute ? '/' : '') + path\n      },\n      dirname: path => {\n        var result = PATH.splitPath(path),\n          root = result[0],\n          dir = result[1]\n        if (!root && !dir) {\n          return '.'\n        }\n        if (dir) {\n          dir = dir.substr(0, dir.length - 1)\n        }\n        return root + dir\n      },\n      basename: path => {\n        if (path === '/') return '/'\n        path = PATH.normalize(path)\n        path = path.replace(/\\/$/, '')\n        var lastSlash = path.lastIndexOf('/')\n        if (lastSlash === -1) return path\n        return path.substr(lastSlash + 1)\n      },\n      join: function() {\n        var paths = Array.prototype.slice.call(arguments)\n        return PATH.normalize(paths.join('/'))\n      },\n      join2: (l, r) => {\n        return PATH.normalize(l + '/' + r)\n      },\n    }\n    function getRandomDevice() {\n      if (\n        typeof crypto == 'object' &&\n        typeof crypto['getRandomValues'] == 'function'\n      ) {\n        var randomBuffer = new Uint8Array(1)\n        return () => {\n          crypto.getRandomValues(randomBuffer)\n          return randomBuffer[0]\n        }\n      } else if (ENVIRONMENT_IS_NODE) {\n        try {\n          var crypto_module = require('crypto')\n          return () => crypto_module['randomBytes'](1)[0]\n        } catch (e) {}\n      }\n      return () => abort('randomDevice')\n    }\n    var PATH_FS = {\n      resolve: function() {\n        var resolvedPath = '',\n          resolvedAbsolute = false\n        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n          var path = i >= 0 ? arguments[i] : FS.cwd()\n          if (typeof path != 'string') {\n            throw new TypeError('Arguments to path.resolve must be strings')\n          } else if (!path) {\n            return ''\n          }\n          resolvedPath = path + '/' + resolvedPath\n          resolvedAbsolute = PATH.isAbs(path)\n        }\n        resolvedPath = PATH.normalizeArray(\n          resolvedPath.split('/').filter(p => !!p),\n          !resolvedAbsolute\n        ).join('/')\n        return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'\n      },\n      relative: (from, to) => {\n        from = PATH_FS.resolve(from).substr(1)\n        to = PATH_FS.resolve(to).substr(1)\n        function trim(arr) {\n          var start = 0\n          for (; start < arr.length; start++) {\n            if (arr[start] !== '') break\n          }\n          var end = arr.length - 1\n          for (; end >= 0; end--) {\n            if (arr[end] !== '') break\n          }\n          if (start > end) return []\n          return arr.slice(start, end - start + 1)\n        }\n        var fromParts = trim(from.split('/'))\n        var toParts = trim(to.split('/'))\n        var length = Math.min(fromParts.length, toParts.length)\n        var samePartsLength = length\n        for (var i = 0; i < length; i++) {\n          if (fromParts[i] !== toParts[i]) {\n            samePartsLength = i\n            break\n          }\n        }\n        var outputParts = []\n        for (var i = samePartsLength; i < fromParts.length; i++) {\n          outputParts.push('..')\n        }\n        outputParts = outputParts.concat(toParts.slice(samePartsLength))\n        return outputParts.join('/')\n      },\n    }\n    function intArrayFromString(stringy, dontAddNull, length) {\n      var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1\n      var u8array = new Array(len)\n      var numBytesWritten = stringToUTF8Array(\n        stringy,\n        u8array,\n        0,\n        u8array.length\n      )\n      if (dontAddNull) u8array.length = numBytesWritten\n      return u8array\n    }\n    var TTY = {\n      ttys: [],\n      init: function() {},\n      shutdown: function() {},\n      register: function(dev, ops) {\n        TTY.ttys[dev] = { input: [], output: [], ops: ops }\n        FS.registerDevice(dev, TTY.stream_ops)\n      },\n      stream_ops: {\n        open: function(stream) {\n          var tty = TTY.ttys[stream.node.rdev]\n          if (!tty) {\n            throw new FS.ErrnoError(43)\n          }\n          stream.tty = tty\n          stream.seekable = false\n        },\n        close: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        fsync: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        read: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.get_char) {\n            throw new FS.ErrnoError(60)\n          }\n          var bytesRead = 0\n          for (var i = 0; i < length; i++) {\n            var result\n            try {\n              result = stream.tty.ops.get_char(stream.tty)\n            } catch (e) {\n              throw new FS.ErrnoError(29)\n            }\n            if (result === undefined && bytesRead === 0) {\n              throw new FS.ErrnoError(6)\n            }\n            if (result === null || result === undefined) break\n            bytesRead++\n            buffer[offset + i] = result\n          }\n          if (bytesRead) {\n            stream.node.timestamp = Date.now()\n          }\n          return bytesRead\n        },\n        write: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.put_char) {\n            throw new FS.ErrnoError(60)\n          }\n          try {\n            for (var i = 0; i < length; i++) {\n              stream.tty.ops.put_char(stream.tty, buffer[offset + i])\n            }\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n          if (length) {\n            stream.node.timestamp = Date.now()\n          }\n          return i\n        },\n      },\n      default_tty_ops: {\n        get_char: function(tty) {\n          if (!tty.input.length) {\n            var result = null\n            if (ENVIRONMENT_IS_NODE) {\n              var BUFSIZE = 256\n              var buf = Buffer.alloc(BUFSIZE)\n              var bytesRead = 0\n              try {\n                bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, -1)\n              } catch (e) {\n                if (e.toString().includes('EOF')) bytesRead = 0\n                else throw e\n              }\n              if (bytesRead > 0) {\n                result = buf.slice(0, bytesRead).toString('utf-8')\n              } else {\n                result = null\n              }\n            } else if (\n              typeof window != 'undefined' &&\n              typeof window.prompt == 'function'\n            ) {\n              result = window.prompt('Input: ')\n              if (result !== null) {\n                result += '\\n'\n              }\n            } else if (typeof readline == 'function') {\n              result = readline()\n              if (result !== null) {\n                result += '\\n'\n              }\n            }\n            if (!result) {\n              return null\n            }\n            tty.input = intArrayFromString(result, true)\n          }\n          return tty.input.shift()\n        },\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n      default_tty1_ops: {\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n    }\n    function mmapAlloc(size) {\n      abort()\n    }\n    var MEMFS = {\n      ops_table: null,\n      mount: function(mount) {\n        return MEMFS.createNode(null, '/', 16384 | 511, 0)\n      },\n      createNode: function(parent, name, mode, dev) {\n        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n          throw new FS.ErrnoError(63)\n        }\n        if (!MEMFS.ops_table) {\n          MEMFS.ops_table = {\n            dir: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                lookup: MEMFS.node_ops.lookup,\n                mknod: MEMFS.node_ops.mknod,\n                rename: MEMFS.node_ops.rename,\n                unlink: MEMFS.node_ops.unlink,\n                rmdir: MEMFS.node_ops.rmdir,\n                readdir: MEMFS.node_ops.readdir,\n                symlink: MEMFS.node_ops.symlink,\n              },\n              stream: { llseek: MEMFS.stream_ops.llseek },\n            },\n            file: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: {\n                llseek: MEMFS.stream_ops.llseek,\n                read: MEMFS.stream_ops.read,\n                write: MEMFS.stream_ops.write,\n                allocate: MEMFS.stream_ops.allocate,\n                mmap: MEMFS.stream_ops.mmap,\n                msync: MEMFS.stream_ops.msync,\n              },\n            },\n            link: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                readlink: MEMFS.node_ops.readlink,\n              },\n              stream: {},\n            },\n            chrdev: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: FS.chrdev_stream_ops,\n            },\n          }\n        }\n        var node = FS.createNode(parent, name, mode, dev)\n        if (FS.isDir(node.mode)) {\n          node.node_ops = MEMFS.ops_table.dir.node\n          node.stream_ops = MEMFS.ops_table.dir.stream\n          node.contents = {}\n        } else if (FS.isFile(node.mode)) {\n          node.node_ops = MEMFS.ops_table.file.node\n          node.stream_ops = MEMFS.ops_table.file.stream\n          node.usedBytes = 0\n          node.contents = null\n        } else if (FS.isLink(node.mode)) {\n          node.node_ops = MEMFS.ops_table.link.node\n          node.stream_ops = MEMFS.ops_table.link.stream\n        } else if (FS.isChrdev(node.mode)) {\n          node.node_ops = MEMFS.ops_table.chrdev.node\n          node.stream_ops = MEMFS.ops_table.chrdev.stream\n        }\n        node.timestamp = Date.now()\n        if (parent) {\n          parent.contents[name] = node\n          parent.timestamp = node.timestamp\n        }\n        return node\n      },\n      getFileDataAsTypedArray: function(node) {\n        if (!node.contents) return new Uint8Array(0)\n        if (node.contents.subarray)\n          return node.contents.subarray(0, node.usedBytes)\n        return new Uint8Array(node.contents)\n      },\n      expandFileStorage: function(node, newCapacity) {\n        var prevCapacity = node.contents ? node.contents.length : 0\n        if (prevCapacity >= newCapacity) return\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024\n        newCapacity = Math.max(\n          newCapacity,\n          (prevCapacity *\n            (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>>\n            0\n        )\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256)\n        var oldContents = node.contents\n        node.contents = new Uint8Array(newCapacity)\n        if (node.usedBytes > 0)\n          node.contents.set(oldContents.subarray(0, node.usedBytes), 0)\n      },\n      resizeFileStorage: function(node, newSize) {\n        if (node.usedBytes == newSize) return\n        if (newSize == 0) {\n          node.contents = null\n          node.usedBytes = 0\n        } else {\n          var oldContents = node.contents\n          node.contents = new Uint8Array(newSize)\n          if (oldContents) {\n            node.contents.set(\n              oldContents.subarray(0, Math.min(newSize, node.usedBytes))\n            )\n          }\n          node.usedBytes = newSize\n        }\n      },\n      node_ops: {\n        getattr: function(node) {\n          var attr = {}\n          attr.dev = FS.isChrdev(node.mode) ? node.id : 1\n          attr.ino = node.id\n          attr.mode = node.mode\n          attr.nlink = 1\n          attr.uid = 0\n          attr.gid = 0\n          attr.rdev = node.rdev\n          if (FS.isDir(node.mode)) {\n            attr.size = 4096\n          } else if (FS.isFile(node.mode)) {\n            attr.size = node.usedBytes\n          } else if (FS.isLink(node.mode)) {\n            attr.size = node.link.length\n          } else {\n            attr.size = 0\n          }\n          attr.atime = new Date(node.timestamp)\n          attr.mtime = new Date(node.timestamp)\n          attr.ctime = new Date(node.timestamp)\n          attr.blksize = 4096\n          attr.blocks = Math.ceil(attr.size / attr.blksize)\n          return attr\n        },\n        setattr: function(node, attr) {\n          if (attr.mode !== undefined) {\n            node.mode = attr.mode\n          }\n          if (attr.timestamp !== undefined) {\n            node.timestamp = attr.timestamp\n          }\n          if (attr.size !== undefined) {\n            MEMFS.resizeFileStorage(node, attr.size)\n          }\n        },\n        lookup: function(parent, name) {\n          throw FS.genericErrors[44]\n        },\n        mknod: function(parent, name, mode, dev) {\n          return MEMFS.createNode(parent, name, mode, dev)\n        },\n        rename: function(old_node, new_dir, new_name) {\n          if (FS.isDir(old_node.mode)) {\n            var new_node\n            try {\n              new_node = FS.lookupNode(new_dir, new_name)\n            } catch (e) {}\n            if (new_node) {\n              for (var i in new_node.contents) {\n                throw new FS.ErrnoError(55)\n              }\n            }\n          }\n          delete old_node.parent.contents[old_node.name]\n          old_node.parent.timestamp = Date.now()\n          old_node.name = new_name\n          new_dir.contents[new_name] = old_node\n          new_dir.timestamp = old_node.parent.timestamp\n          old_node.parent = new_dir\n        },\n        unlink: function(parent, name) {\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        rmdir: function(parent, name) {\n          var node = FS.lookupNode(parent, name)\n          for (var i in node.contents) {\n            throw new FS.ErrnoError(55)\n          }\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        readdir: function(node) {\n          var entries = ['.', '..']\n          for (var key in node.contents) {\n            if (!node.contents.hasOwnProperty(key)) {\n              continue\n            }\n            entries.push(key)\n          }\n          return entries\n        },\n        symlink: function(parent, newname, oldpath) {\n          var node = MEMFS.createNode(parent, newname, 511 | 40960, 0)\n          node.link = oldpath\n          return node\n        },\n        readlink: function(node) {\n          if (!FS.isLink(node.mode)) {\n            throw new FS.ErrnoError(28)\n          }\n          return node.link\n        },\n      },\n      stream_ops: {\n        read: function(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= stream.node.usedBytes) return 0\n          var size = Math.min(stream.node.usedBytes - position, length)\n          if (size > 8 && contents.subarray) {\n            buffer.set(contents.subarray(position, position + size), offset)\n          } else {\n            for (var i = 0; i < size; i++)\n              buffer[offset + i] = contents[position + i]\n          }\n          return size\n        },\n        write: function(stream, buffer, offset, length, position, canOwn) {\n          if (buffer.buffer === HEAP8.buffer) {\n            canOwn = false\n          }\n          if (!length) return 0\n          var node = stream.node\n          node.timestamp = Date.now()\n          if (buffer.subarray && (!node.contents || node.contents.subarray)) {\n            if (canOwn) {\n              node.contents = buffer.subarray(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (node.usedBytes === 0 && position === 0) {\n              node.contents = buffer.slice(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (position + length <= node.usedBytes) {\n              node.contents.set(\n                buffer.subarray(offset, offset + length),\n                position\n              )\n              return length\n            }\n          }\n          MEMFS.expandFileStorage(node, position + length)\n          if (node.contents.subarray && buffer.subarray) {\n            node.contents.set(\n              buffer.subarray(offset, offset + length),\n              position\n            )\n          } else {\n            for (var i = 0; i < length; i++) {\n              node.contents[position + i] = buffer[offset + i]\n            }\n          }\n          node.usedBytes = Math.max(node.usedBytes, position + length)\n          return length\n        },\n        llseek: function(stream, offset, whence) {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              position += stream.node.usedBytes\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        allocate: function(stream, offset, length) {\n          MEMFS.expandFileStorage(stream.node, offset + length)\n          stream.node.usedBytes = Math.max(\n            stream.node.usedBytes,\n            offset + length\n          )\n        },\n        mmap: function(stream, length, position, prot, flags) {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr\n          var allocated\n          var contents = stream.node.contents\n          if (!(flags & 2) && contents.buffer === buffer) {\n            allocated = false\n            ptr = contents.byteOffset\n          } else {\n            if (position > 0 || position + length < contents.length) {\n              if (contents.subarray) {\n                contents = contents.subarray(position, position + length)\n              } else {\n                contents = Array.prototype.slice.call(\n                  contents,\n                  position,\n                  position + length\n                )\n              }\n            }\n            allocated = true\n            ptr = mmapAlloc(length)\n            if (!ptr) {\n              throw new FS.ErrnoError(48)\n            }\n            HEAP8.set(contents, ptr)\n          }\n          return { ptr: ptr, allocated: allocated }\n        },\n        msync: function(stream, buffer, offset, length, mmapFlags) {\n          MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    function asyncLoad(url, onload, onerror, noRunDep) {\n      var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''\n      readAsync(\n        url,\n        arrayBuffer => {\n          assert(\n            arrayBuffer,\n            'Loading data file \"' + url + '\" failed (no arrayBuffer).'\n          )\n          onload(new Uint8Array(arrayBuffer))\n          if (dep) removeRunDependency(dep)\n        },\n        event => {\n          if (onerror) {\n            onerror()\n          } else {\n            throw 'Loading data file \"' + url + '\" failed.'\n          }\n        }\n      )\n      if (dep) addRunDependency(dep)\n    }\n    var ERRNO_CODES = {}\n    var NODEFS = {\n      isWindows: false,\n      staticInit: () => {\n        NODEFS.isWindows = !!process.platform.match(/^win/)\n        var flags = process['binding']('constants')\n        if (flags['fs']) {\n          flags = flags['fs']\n        }\n        NODEFS.flagsForNodeMap = {\n          1024: flags['O_APPEND'],\n          64: flags['O_CREAT'],\n          128: flags['O_EXCL'],\n          256: flags['O_NOCTTY'],\n          0: flags['O_RDONLY'],\n          2: flags['O_RDWR'],\n          4096: flags['O_SYNC'],\n          512: flags['O_TRUNC'],\n          1: flags['O_WRONLY'],\n          131072: flags['O_NOFOLLOW'],\n        }\n      },\n      convertNodeCode: e => {\n        var code = e.code\n        return ERRNO_CODES[code]\n      },\n      mount: mount => {\n        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0)\n      },\n      createNode: (parent, name, mode, dev) => {\n        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = FS.createNode(parent, name, mode)\n        node.node_ops = NODEFS.node_ops\n        node.stream_ops = NODEFS.stream_ops\n        return node\n      },\n      getMode: path => {\n        var stat\n        try {\n          stat = fs.lstatSync(path)\n          if (NODEFS.isWindows) {\n            stat.mode = stat.mode | ((stat.mode & 292) >> 2)\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n        }\n        return stat.mode\n      },\n      realPath: node => {\n        var parts = []\n        while (node.parent !== node) {\n          parts.push(node.name)\n          node = node.parent\n        }\n        parts.push(node.mount.opts.root)\n        parts.reverse()\n        return PATH.join.apply(null, parts)\n      },\n      flagsForNode: flags => {\n        flags &= ~2097152\n        flags &= ~2048\n        flags &= ~32768\n        flags &= ~524288\n        flags &= ~65536\n        var newFlags = 0\n        for (var k in NODEFS.flagsForNodeMap) {\n          if (flags & k) {\n            newFlags |= NODEFS.flagsForNodeMap[k]\n            flags ^= k\n          }\n        }\n        if (flags) {\n          throw new FS.ErrnoError(28)\n        }\n        return newFlags\n      },\n      node_ops: {\n        getattr: node => {\n          var path = NODEFS.realPath(node)\n          var stat\n          try {\n            stat = fs.lstatSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          if (NODEFS.isWindows && !stat.blksize) {\n            stat.blksize = 4096\n          }\n          if (NODEFS.isWindows && !stat.blocks) {\n            stat.blocks = ((stat.size + stat.blksize - 1) / stat.blksize) | 0\n          }\n          return {\n            dev: stat.dev,\n            ino: stat.ino,\n            mode: stat.mode,\n            nlink: stat.nlink,\n            uid: stat.uid,\n            gid: stat.gid,\n            rdev: stat.rdev,\n            size: stat.size,\n            atime: stat.atime,\n            mtime: stat.mtime,\n            ctime: stat.ctime,\n            blksize: stat.blksize,\n            blocks: stat.blocks,\n          }\n        },\n        setattr: (node, attr) => {\n          var path = NODEFS.realPath(node)\n          try {\n            if (attr.mode !== undefined) {\n              fs.chmodSync(path, attr.mode)\n              node.mode = attr.mode\n            }\n            if (attr.timestamp !== undefined) {\n              var date = new Date(attr.timestamp)\n              fs.utimesSync(path, date, date)\n            }\n            if (attr.size !== undefined) {\n              fs.truncateSync(path, attr.size)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        lookup: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          var mode = NODEFS.getMode(path)\n          return NODEFS.createNode(parent, name, mode)\n        },\n        mknod: (parent, name, mode, dev) => {\n          var node = NODEFS.createNode(parent, name, mode, dev)\n          var path = NODEFS.realPath(node)\n          try {\n            if (FS.isDir(node.mode)) {\n              fs.mkdirSync(path, node.mode)\n            } else {\n              fs.writeFileSync(path, '', { mode: node.mode })\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          return node\n        },\n        rename: (oldNode, newDir, newName) => {\n          var oldPath = NODEFS.realPath(oldNode)\n          var newPath = PATH.join2(NODEFS.realPath(newDir), newName)\n          try {\n            fs.renameSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          oldNode.name = newName\n        },\n        unlink: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.unlinkSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        rmdir: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.rmdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readdir: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            return fs.readdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        symlink: (parent, newName, oldPath) => {\n          var newPath = PATH.join2(NODEFS.realPath(parent), newName)\n          try {\n            fs.symlinkSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readlink: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            path = fs.readlinkSync(path)\n            path = nodePath.relative(\n              nodePath.resolve(node.mount.opts.root),\n              path\n            )\n            return path\n          } catch (e) {\n            if (!e.code) throw e\n            if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28)\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n      },\n      stream_ops: {\n        open: stream => {\n          var path = NODEFS.realPath(stream.node)\n          try {\n            if (FS.isFile(stream.node.mode)) {\n              stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags))\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        close: stream => {\n          try {\n            if (FS.isFile(stream.node.mode) && stream.nfd) {\n              fs.closeSync(stream.nfd)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        read: (stream, buffer, offset, length, position) => {\n          if (length === 0) return 0\n          try {\n            return fs.readSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        write: (stream, buffer, offset, length, position) => {\n          try {\n            return fs.writeSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        llseek: (stream, offset, whence) => {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              try {\n                var stat = fs.fstatSync(stream.nfd)\n                position += stat.size\n              } catch (e) {\n                throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n              }\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        mmap: (stream, length, position, prot, flags) => {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr = mmapAlloc(length)\n          NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        },\n        msync: (stream, buffer, offset, length, mmapFlags) => {\n          NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    var FS = {\n      root: null,\n      mounts: [],\n      devices: {},\n      streams: [],\n      nextInode: 1,\n      nameTable: null,\n      currentPath: '/',\n      initialized: false,\n      ignorePermissions: true,\n      ErrnoError: null,\n      genericErrors: {},\n      filesystems: null,\n      syncFSRequests: 0,\n      lookupPath: (path, opts = {}) => {\n        path = PATH_FS.resolve(path)\n        if (!path) return { path: '', node: null }\n        var defaults = { follow_mount: true, recurse_count: 0 }\n        opts = Object.assign(defaults, opts)\n        if (opts.recurse_count > 8) {\n          throw new FS.ErrnoError(32)\n        }\n        var parts = path.split('/').filter(p => !!p)\n        var current = FS.root\n        var current_path = '/'\n        for (var i = 0; i < parts.length; i++) {\n          var islast = i === parts.length - 1\n          if (islast && opts.parent) {\n            break\n          }\n          current = FS.lookupNode(current, parts[i])\n          current_path = PATH.join2(current_path, parts[i])\n          if (FS.isMountpoint(current)) {\n            if (!islast || (islast && opts.follow_mount)) {\n              current = current.mounted.root\n            }\n          }\n          if (!islast || opts.follow) {\n            var count = 0\n            while (FS.isLink(current.mode)) {\n              var link = FS.readlink(current_path)\n              current_path = PATH_FS.resolve(PATH.dirname(current_path), link)\n              var lookup = FS.lookupPath(current_path, {\n                recurse_count: opts.recurse_count + 1,\n              })\n              current = lookup.node\n              if (count++ > 40) {\n                throw new FS.ErrnoError(32)\n              }\n            }\n          }\n        }\n        return { path: current_path, node: current }\n      },\n      getPath: node => {\n        var path\n        while (true) {\n          if (FS.isRoot(node)) {\n            var mount = node.mount.mountpoint\n            if (!path) return mount\n            return mount[mount.length - 1] !== '/'\n              ? mount + '/' + path\n              : mount + path\n          }\n          path = path ? node.name + '/' + path : node.name\n          node = node.parent\n        }\n      },\n      hashName: (parentid, name) => {\n        var hash = 0\n        for (var i = 0; i < name.length; i++) {\n          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0\n        }\n        return ((parentid + hash) >>> 0) % FS.nameTable.length\n      },\n      hashAddNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        node.name_next = FS.nameTable[hash]\n        FS.nameTable[hash] = node\n      },\n      hashRemoveNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        if (FS.nameTable[hash] === node) {\n          FS.nameTable[hash] = node.name_next\n        } else {\n          var current = FS.nameTable[hash]\n          while (current) {\n            if (current.name_next === node) {\n              current.name_next = node.name_next\n              break\n            }\n            current = current.name_next\n          }\n        }\n      },\n      lookupNode: (parent, name) => {\n        var errCode = FS.mayLookup(parent)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode, parent)\n        }\n        var hash = FS.hashName(parent.id, name)\n        for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n          var nodeName = node.name\n          if (node.parent.id === parent.id && nodeName === name) {\n            return node\n          }\n        }\n        return FS.lookup(parent, name)\n      },\n      createNode: (parent, name, mode, rdev) => {\n        var node = new FS.FSNode(parent, name, mode, rdev)\n        FS.hashAddNode(node)\n        return node\n      },\n      destroyNode: node => {\n        FS.hashRemoveNode(node)\n      },\n      isRoot: node => {\n        return node === node.parent\n      },\n      isMountpoint: node => {\n        return !!node.mounted\n      },\n      isFile: mode => {\n        return (mode & 61440) === 32768\n      },\n      isDir: mode => {\n        return (mode & 61440) === 16384\n      },\n      isLink: mode => {\n        return (mode & 61440) === 40960\n      },\n      isChrdev: mode => {\n        return (mode & 61440) === 8192\n      },\n      isBlkdev: mode => {\n        return (mode & 61440) === 24576\n      },\n      isFIFO: mode => {\n        return (mode & 61440) === 4096\n      },\n      isSocket: mode => {\n        return (mode & 49152) === 49152\n      },\n      flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 },\n      modeStringToFlags: str => {\n        var flags = FS.flagModes[str]\n        if (typeof flags == 'undefined') {\n          throw new Error('Unknown file open mode: ' + str)\n        }\n        return flags\n      },\n      flagsToPermissionString: flag => {\n        var perms = ['r', 'w', 'rw'][flag & 3]\n        if (flag & 512) {\n          perms += 'w'\n        }\n        return perms\n      },\n      nodePermissions: (node, perms) => {\n        if (FS.ignorePermissions) {\n          return 0\n        }\n        if (perms.includes('r') && !(node.mode & 292)) {\n          return 2\n        } else if (perms.includes('w') && !(node.mode & 146)) {\n          return 2\n        } else if (perms.includes('x') && !(node.mode & 73)) {\n          return 2\n        }\n        return 0\n      },\n      mayLookup: dir => {\n        var errCode = FS.nodePermissions(dir, 'x')\n        if (errCode) return errCode\n        if (!dir.node_ops.lookup) return 2\n        return 0\n      },\n      mayCreate: (dir, name) => {\n        try {\n          var node = FS.lookupNode(dir, name)\n          return 20\n        } catch (e) {}\n        return FS.nodePermissions(dir, 'wx')\n      },\n      mayDelete: (dir, name, isdir) => {\n        var node\n        try {\n          node = FS.lookupNode(dir, name)\n        } catch (e) {\n          return e.errno\n        }\n        var errCode = FS.nodePermissions(dir, 'wx')\n        if (errCode) {\n          return errCode\n        }\n        if (isdir) {\n          if (!FS.isDir(node.mode)) {\n            return 54\n          }\n          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n            return 10\n          }\n        } else {\n          if (FS.isDir(node.mode)) {\n            return 31\n          }\n        }\n        return 0\n      },\n      mayOpen: (node, flags) => {\n        if (!node) {\n          return 44\n        }\n        if (FS.isLink(node.mode)) {\n          return 32\n        } else if (FS.isDir(node.mode)) {\n          if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) {\n            return 31\n          }\n        }\n        return FS.nodePermissions(node, FS.flagsToPermissionString(flags))\n      },\n      MAX_OPEN_FDS: 4096,\n      nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => {\n        for (var fd = fd_start; fd <= fd_end; fd++) {\n          if (!FS.streams[fd]) {\n            return fd\n          }\n        }\n        throw new FS.ErrnoError(33)\n      },\n      getStream: fd => FS.streams[fd],\n      createStream: (stream, fd_start, fd_end) => {\n        if (!FS.FSStream) {\n          FS.FSStream = function() {\n            this.shared = {}\n          }\n          FS.FSStream.prototype = {}\n          Object.defineProperties(FS.FSStream.prototype, {\n            object: {\n              get: function() {\n                return this.node\n              },\n              set: function(val) {\n                this.node = val\n              },\n            },\n            isRead: {\n              get: function() {\n                return (this.flags & 2097155) !== 1\n              },\n            },\n            isWrite: {\n              get: function() {\n                return (this.flags & 2097155) !== 0\n              },\n            },\n            isAppend: {\n              get: function() {\n                return this.flags & 1024\n              },\n            },\n            flags: {\n              get: function() {\n                return this.shared.flags\n              },\n              set: function(val) {\n                this.shared.flags = val\n              },\n            },\n            position: {\n              get: function() {\n                return this.shared.position\n              },\n              set: function(val) {\n                this.shared.position = val\n              },\n            },\n          })\n        }\n        stream = Object.assign(new FS.FSStream(), stream)\n        var fd = FS.nextfd(fd_start, fd_end)\n        stream.fd = fd\n        FS.streams[fd] = stream\n        return stream\n      },\n      closeStream: fd => {\n        FS.streams[fd] = null\n      },\n      chrdev_stream_ops: {\n        open: stream => {\n          var device = FS.getDevice(stream.node.rdev)\n          stream.stream_ops = device.stream_ops\n          if (stream.stream_ops.open) {\n            stream.stream_ops.open(stream)\n          }\n        },\n        llseek: () => {\n          throw new FS.ErrnoError(70)\n        },\n      },\n      major: dev => dev >> 8,\n      minor: dev => dev & 255,\n      makedev: (ma, mi) => (ma << 8) | mi,\n      registerDevice: (dev, ops) => {\n        FS.devices[dev] = { stream_ops: ops }\n      },\n      getDevice: dev => FS.devices[dev],\n      getMounts: mount => {\n        var mounts = []\n        var check = [mount]\n        while (check.length) {\n          var m = check.pop()\n          mounts.push(m)\n          check.push.apply(check, m.mounts)\n        }\n        return mounts\n      },\n      syncfs: (populate, callback) => {\n        if (typeof populate == 'function') {\n          callback = populate\n          populate = false\n        }\n        FS.syncFSRequests++\n        if (FS.syncFSRequests > 1) {\n          err(\n            'warning: ' +\n              FS.syncFSRequests +\n              ' FS.syncfs operations in flight at once, probably just doing extra work'\n          )\n        }\n        var mounts = FS.getMounts(FS.root.mount)\n        var completed = 0\n        function doCallback(errCode) {\n          FS.syncFSRequests--\n          return callback(errCode)\n        }\n        function done(errCode) {\n          if (errCode) {\n            if (!done.errored) {\n              done.errored = true\n              return doCallback(errCode)\n            }\n            return\n          }\n          if (++completed >= mounts.length) {\n            doCallback(null)\n          }\n        }\n        mounts.forEach(mount => {\n          if (!mount.type.syncfs) {\n            return done(null)\n          }\n          mount.type.syncfs(mount, populate, done)\n        })\n      },\n      mount: (type, opts, mountpoint) => {\n        var root = mountpoint === '/'\n        var pseudo = !mountpoint\n        var node\n        if (root && FS.root) {\n          throw new FS.ErrnoError(10)\n        } else if (!root && !pseudo) {\n          var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n          mountpoint = lookup.path\n          node = lookup.node\n          if (FS.isMountpoint(node)) {\n            throw new FS.ErrnoError(10)\n          }\n          if (!FS.isDir(node.mode)) {\n            throw new FS.ErrnoError(54)\n          }\n        }\n        var mount = {\n          type: type,\n          opts: opts,\n          mountpoint: mountpoint,\n          mounts: [],\n        }\n        var mountRoot = type.mount(mount)\n        mountRoot.mount = mount\n        mount.root = mountRoot\n        if (root) {\n          FS.root = mountRoot\n        } else if (node) {\n          node.mounted = mount\n          if (node.mount) {\n            node.mount.mounts.push(mount)\n          }\n        }\n        return mountRoot\n      },\n      unmount: mountpoint => {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n        if (!FS.isMountpoint(lookup.node)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = lookup.node\n        var mount = node.mounted\n        var mounts = FS.getMounts(mount)\n        Object.keys(FS.nameTable).forEach(hash => {\n          var current = FS.nameTable[hash]\n          while (current) {\n            var next = current.name_next\n            if (mounts.includes(current.mount)) {\n              FS.destroyNode(current)\n            }\n            current = next\n          }\n        })\n        node.mounted = null\n        var idx = node.mount.mounts.indexOf(mount)\n        node.mount.mounts.splice(idx, 1)\n      },\n      lookup: (parent, name) => {\n        return parent.node_ops.lookup(parent, name)\n      },\n      mknod: (path, mode, dev) => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        if (!name || name === '.' || name === '..') {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.mayCreate(parent, name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.mknod) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.mknod(parent, name, mode, dev)\n      },\n      create: (path, mode) => {\n        mode = mode !== undefined ? mode : 438\n        mode &= 4095\n        mode |= 32768\n        return FS.mknod(path, mode, 0)\n      },\n      mkdir: (path, mode) => {\n        mode = mode !== undefined ? mode : 511\n        mode &= 511 | 512\n        mode |= 16384\n        return FS.mknod(path, mode, 0)\n      },\n      mkdirTree: (path, mode) => {\n        var dirs = path.split('/')\n        var d = ''\n        for (var i = 0; i < dirs.length; ++i) {\n          if (!dirs[i]) continue\n          d += '/' + dirs[i]\n          try {\n            FS.mkdir(d, mode)\n          } catch (e) {\n            if (e.errno != 20) throw e\n          }\n        }\n      },\n      mkdev: (path, mode, dev) => {\n        if (typeof dev == 'undefined') {\n          dev = mode\n          mode = 438\n        }\n        mode |= 8192\n        return FS.mknod(path, mode, dev)\n      },\n      symlink: (oldpath, newpath) => {\n        if (!PATH_FS.resolve(oldpath)) {\n          throw new FS.ErrnoError(44)\n        }\n        var lookup = FS.lookupPath(newpath, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var newname = PATH.basename(newpath)\n        var errCode = FS.mayCreate(parent, newname)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.symlink) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.symlink(parent, newname, oldpath)\n      },\n      rename: (old_path, new_path) => {\n        var old_dirname = PATH.dirname(old_path)\n        var new_dirname = PATH.dirname(new_path)\n        var old_name = PATH.basename(old_path)\n        var new_name = PATH.basename(new_path)\n        var lookup, old_dir, new_dir\n        lookup = FS.lookupPath(old_path, { parent: true })\n        old_dir = lookup.node\n        lookup = FS.lookupPath(new_path, { parent: true })\n        new_dir = lookup.node\n        if (!old_dir || !new_dir) throw new FS.ErrnoError(44)\n        if (old_dir.mount !== new_dir.mount) {\n          throw new FS.ErrnoError(75)\n        }\n        var old_node = FS.lookupNode(old_dir, old_name)\n        var relative = PATH_FS.relative(old_path, new_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(28)\n        }\n        relative = PATH_FS.relative(new_path, old_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(55)\n        }\n        var new_node\n        try {\n          new_node = FS.lookupNode(new_dir, new_name)\n        } catch (e) {}\n        if (old_node === new_node) {\n          return\n        }\n        var isdir = FS.isDir(old_node.mode)\n        var errCode = FS.mayDelete(old_dir, old_name, isdir)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        errCode = new_node\n          ? FS.mayDelete(new_dir, new_name, isdir)\n          : FS.mayCreate(new_dir, new_name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!old_dir.node_ops.rename) {\n          throw new FS.ErrnoError(63)\n        }\n        if (\n          FS.isMountpoint(old_node) ||\n          (new_node && FS.isMountpoint(new_node))\n        ) {\n          throw new FS.ErrnoError(10)\n        }\n        if (new_dir !== old_dir) {\n          errCode = FS.nodePermissions(old_dir, 'w')\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        FS.hashRemoveNode(old_node)\n        try {\n          old_dir.node_ops.rename(old_node, new_dir, new_name)\n        } catch (e) {\n          throw e\n        } finally {\n          FS.hashAddNode(old_node)\n        }\n      },\n      rmdir: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, true)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.rmdir) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.rmdir(parent, name)\n        FS.destroyNode(node)\n      },\n      readdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        if (!node.node_ops.readdir) {\n          throw new FS.ErrnoError(54)\n        }\n        return node.node_ops.readdir(node)\n      },\n      unlink: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, false)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.unlink) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.unlink(parent, name)\n        FS.destroyNode(node)\n      },\n      readlink: path => {\n        var lookup = FS.lookupPath(path)\n        var link = lookup.node\n        if (!link) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!link.node_ops.readlink) {\n          throw new FS.ErrnoError(28)\n        }\n        return PATH_FS.resolve(\n          FS.getPath(link.parent),\n          link.node_ops.readlink(link)\n        )\n      },\n      stat: (path, dontFollow) => {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow })\n        var node = lookup.node\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!node.node_ops.getattr) {\n          throw new FS.ErrnoError(63)\n        }\n        return node.node_ops.getattr(node)\n      },\n      lstat: path => {\n        return FS.stat(path, true)\n      },\n      chmod: (path, mode, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, {\n          mode: (mode & 4095) | (node.mode & ~4095),\n          timestamp: Date.now(),\n        })\n      },\n      lchmod: (path, mode) => {\n        FS.chmod(path, mode, true)\n      },\n      fchmod: (fd, mode) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chmod(stream.node, mode)\n      },\n      chown: (path, uid, gid, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, { timestamp: Date.now() })\n      },\n      lchown: (path, uid, gid) => {\n        FS.chown(path, uid, gid, true)\n      },\n      fchown: (fd, uid, gid) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chown(stream.node, uid, gid)\n      },\n      truncate: (path, len) => {\n        if (len < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: true })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!FS.isFile(node.mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.nodePermissions(node, 'w')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        node.node_ops.setattr(node, { size: len, timestamp: Date.now() })\n      },\n      ftruncate: (fd, len) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(28)\n        }\n        FS.truncate(stream.node, len)\n      },\n      utime: (path, atime, mtime) => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) })\n      },\n      open: (path, flags, mode) => {\n        if (path === '') {\n          throw new FS.ErrnoError(44)\n        }\n        flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags\n        mode = typeof mode == 'undefined' ? 438 : mode\n        if (flags & 64) {\n          mode = (mode & 4095) | 32768\n        } else {\n          mode = 0\n        }\n        var node\n        if (typeof path == 'object') {\n          node = path\n        } else {\n          path = PATH.normalize(path)\n          try {\n            var lookup = FS.lookupPath(path, { follow: !(flags & 131072) })\n            node = lookup.node\n          } catch (e) {}\n        }\n        var created = false\n        if (flags & 64) {\n          if (node) {\n            if (flags & 128) {\n              throw new FS.ErrnoError(20)\n            }\n          } else {\n            node = FS.mknod(path, mode, 0)\n            created = true\n          }\n        }\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (FS.isChrdev(node.mode)) {\n          flags &= ~512\n        }\n        if (flags & 65536 && !FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        if (!created) {\n          var errCode = FS.mayOpen(node, flags)\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        if (flags & 512 && !created) {\n          FS.truncate(node, 0)\n        }\n        flags &= ~(128 | 512 | 131072)\n        var stream = FS.createStream({\n          node: node,\n          path: FS.getPath(node),\n          flags: flags,\n          seekable: true,\n          position: 0,\n          stream_ops: node.stream_ops,\n          ungotten: [],\n          error: false,\n        })\n        if (stream.stream_ops.open) {\n          stream.stream_ops.open(stream)\n        }\n        if (Module['logReadFiles'] && !(flags & 1)) {\n          if (!FS.readFiles) FS.readFiles = {}\n          if (!(path in FS.readFiles)) {\n            FS.readFiles[path] = 1\n          }\n        }\n        return stream\n      },\n      close: stream => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (stream.getdents) stream.getdents = null\n        try {\n          if (stream.stream_ops.close) {\n            stream.stream_ops.close(stream)\n          }\n        } catch (e) {\n          throw e\n        } finally {\n          FS.closeStream(stream.fd)\n        }\n        stream.fd = null\n      },\n      isClosed: stream => {\n        return stream.fd === null\n      },\n      llseek: (stream, offset, whence) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!stream.seekable || !stream.stream_ops.llseek) {\n          throw new FS.ErrnoError(70)\n        }\n        if (whence != 0 && whence != 1 && whence != 2) {\n          throw new FS.ErrnoError(28)\n        }\n        stream.position = stream.stream_ops.llseek(stream, offset, whence)\n        stream.ungotten = []\n        return stream.position\n      },\n      read: (stream, buffer, offset, length, position) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.read) {\n          throw new FS.ErrnoError(28)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesRead = stream.stream_ops.read(\n          stream,\n          buffer,\n          offset,\n          length,\n          position\n        )\n        if (!seeking) stream.position += bytesRead\n        return bytesRead\n      },\n      write: (stream, buffer, offset, length, position, canOwn) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.write) {\n          throw new FS.ErrnoError(28)\n        }\n        if (stream.seekable && stream.flags & 1024) {\n          FS.llseek(stream, 0, 2)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesWritten = stream.stream_ops.write(\n          stream,\n          buffer,\n          offset,\n          length,\n          position,\n          canOwn\n        )\n        if (!seeking) stream.position += bytesWritten\n        return bytesWritten\n      },\n      allocate: (stream, offset, length) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (offset < 0 || length <= 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (!stream.stream_ops.allocate) {\n          throw new FS.ErrnoError(138)\n        }\n        stream.stream_ops.allocate(stream, offset, length)\n      },\n      mmap: (stream, length, position, prot, flags) => {\n        if (\n          (prot & 2) !== 0 &&\n          (flags & 2) === 0 &&\n          (stream.flags & 2097155) !== 2\n        ) {\n          throw new FS.ErrnoError(2)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(2)\n        }\n        if (!stream.stream_ops.mmap) {\n          throw new FS.ErrnoError(43)\n        }\n        return stream.stream_ops.mmap(stream, length, position, prot, flags)\n      },\n      msync: (stream, buffer, offset, length, mmapFlags) => {\n        if (!stream.stream_ops.msync) {\n          return 0\n        }\n        return stream.stream_ops.msync(\n          stream,\n          buffer,\n          offset,\n          length,\n          mmapFlags\n        )\n      },\n      munmap: stream => 0,\n      ioctl: (stream, cmd, arg) => {\n        if (!stream.stream_ops.ioctl) {\n          throw new FS.ErrnoError(59)\n        }\n        return stream.stream_ops.ioctl(stream, cmd, arg)\n      },\n      readFile: (path, opts = {}) => {\n        opts.flags = opts.flags || 0\n        opts.encoding = opts.encoding || 'binary'\n        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {\n          throw new Error('Invalid encoding type \"' + opts.encoding + '\"')\n        }\n        var ret\n        var stream = FS.open(path, opts.flags)\n        var stat = FS.stat(path)\n        var length = stat.size\n        var buf = new Uint8Array(length)\n        FS.read(stream, buf, 0, length, 0)\n        if (opts.encoding === 'utf8') {\n          ret = UTF8ArrayToString(buf, 0)\n        } else if (opts.encoding === 'binary') {\n          ret = buf\n        }\n        FS.close(stream)\n        return ret\n      },\n      writeFile: (path, data, opts = {}) => {\n        opts.flags = opts.flags || 577\n        var stream = FS.open(path, opts.flags, opts.mode)\n        if (typeof data == 'string') {\n          var buf = new Uint8Array(lengthBytesUTF8(data) + 1)\n          var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length)\n          FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn)\n        } else if (ArrayBuffer.isView(data)) {\n          FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn)\n        } else {\n          throw new Error('Unsupported data type')\n        }\n        FS.close(stream)\n      },\n      cwd: () => FS.currentPath,\n      chdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        if (lookup.node === null) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!FS.isDir(lookup.node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        var errCode = FS.nodePermissions(lookup.node, 'x')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        FS.currentPath = lookup.path\n      },\n      createDefaultDirectories: () => {\n        FS.mkdir('/tmp')\n        FS.mkdir('/home')\n        FS.mkdir('/home/web_user')\n      },\n      createDefaultDevices: () => {\n        FS.mkdir('/dev')\n        FS.registerDevice(FS.makedev(1, 3), {\n          read: () => 0,\n          write: (stream, buffer, offset, length, pos) => length,\n        })\n        FS.mkdev('/dev/null', FS.makedev(1, 3))\n        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops)\n        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops)\n        FS.mkdev('/dev/tty', FS.makedev(5, 0))\n        FS.mkdev('/dev/tty1', FS.makedev(6, 0))\n        var random_device = getRandomDevice()\n        FS.createDevice('/dev', 'random', random_device)\n        FS.createDevice('/dev', 'urandom', random_device)\n        FS.mkdir('/dev/shm')\n        FS.mkdir('/dev/shm/tmp')\n      },\n      createSpecialDirectories: () => {\n        FS.mkdir('/proc')\n        var proc_self = FS.mkdir('/proc/self')\n        FS.mkdir('/proc/self/fd')\n        FS.mount(\n          {\n            mount: () => {\n              var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73)\n              node.node_ops = {\n                lookup: (parent, name) => {\n                  var fd = +name\n                  var stream = FS.getStream(fd)\n                  if (!stream) throw new FS.ErrnoError(8)\n                  var ret = {\n                    parent: null,\n                    mount: { mountpoint: 'fake' },\n                    node_ops: { readlink: () => stream.path },\n                  }\n                  ret.parent = ret\n                  return ret\n                },\n              }\n              return node\n            },\n          },\n          {},\n          '/proc/self/fd'\n        )\n      },\n      createStandardStreams: () => {\n        if (Module['stdin']) {\n          FS.createDevice('/dev', 'stdin', Module['stdin'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdin')\n        }\n        if (Module['stdout']) {\n          FS.createDevice('/dev', 'stdout', null, Module['stdout'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdout')\n        }\n        if (Module['stderr']) {\n          FS.createDevice('/dev', 'stderr', null, Module['stderr'])\n        } else {\n          FS.symlink('/dev/tty1', '/dev/stderr')\n        }\n        var stdin = FS.open('/dev/stdin', 0)\n        var stdout = FS.open('/dev/stdout', 1)\n        var stderr = FS.open('/dev/stderr', 1)\n      },\n      ensureErrnoError: () => {\n        if (FS.ErrnoError) return\n        FS.ErrnoError = function ErrnoError(errno, node) {\n          this.node = node\n          this.setErrno = function(errno) {\n            this.errno = errno\n          }\n          this.setErrno(errno)\n          this.message = 'FS error'\n        }\n        FS.ErrnoError.prototype = new Error()\n        FS.ErrnoError.prototype.constructor = FS.ErrnoError\n        ;[44].forEach(code => {\n          FS.genericErrors[code] = new FS.ErrnoError(code)\n          FS.genericErrors[code].stack = '<generic error, no stack>'\n        })\n      },\n      staticInit: () => {\n        FS.ensureErrnoError()\n        FS.nameTable = new Array(4096)\n        FS.mount(MEMFS, {}, '/')\n        FS.createDefaultDirectories()\n        FS.createDefaultDevices()\n        FS.createSpecialDirectories()\n        FS.filesystems = { MEMFS: MEMFS, NODEFS: NODEFS }\n      },\n      init: (input, output, error) => {\n        FS.init.initialized = true\n        FS.ensureErrnoError()\n        Module['stdin'] = input || Module['stdin']\n        Module['stdout'] = output || Module['stdout']\n        Module['stderr'] = error || Module['stderr']\n        FS.createStandardStreams()\n      },\n      quit: () => {\n        FS.init.initialized = false\n        for (var i = 0; i < FS.streams.length; i++) {\n          var stream = FS.streams[i]\n          if (!stream) {\n            continue\n          }\n          FS.close(stream)\n        }\n      },\n      getMode: (canRead, canWrite) => {\n        var mode = 0\n        if (canRead) mode |= 292 | 73\n        if (canWrite) mode |= 146\n        return mode\n      },\n      findObject: (path, dontResolveLastLink) => {\n        var ret = FS.analyzePath(path, dontResolveLastLink)\n        if (!ret.exists) {\n          return null\n        }\n        return ret.object\n      },\n      analyzePath: (path, dontResolveLastLink) => {\n        try {\n          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          path = lookup.path\n        } catch (e) {}\n        var ret = {\n          isRoot: false,\n          exists: false,\n          error: 0,\n          name: null,\n          path: null,\n          object: null,\n          parentExists: false,\n          parentPath: null,\n          parentObject: null,\n        }\n        try {\n          var lookup = FS.lookupPath(path, { parent: true })\n          ret.parentExists = true\n          ret.parentPath = lookup.path\n          ret.parentObject = lookup.node\n          ret.name = PATH.basename(path)\n          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          ret.exists = true\n          ret.path = lookup.path\n          ret.object = lookup.node\n          ret.name = lookup.node.name\n          ret.isRoot = lookup.path === '/'\n        } catch (e) {\n          ret.error = e.errno\n        }\n        return ret\n      },\n      createPath: (parent, path, canRead, canWrite) => {\n        parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n        var parts = path.split('/').reverse()\n        while (parts.length) {\n          var part = parts.pop()\n          if (!part) continue\n          var current = PATH.join2(parent, part)\n          try {\n            FS.mkdir(current)\n          } catch (e) {}\n          parent = current\n        }\n        return current\n      },\n      createFile: (parent, name, properties, canRead, canWrite) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(canRead, canWrite)\n        return FS.create(path, mode)\n      },\n      createDataFile: (parent, name, data, canRead, canWrite, canOwn) => {\n        var path = name\n        if (parent) {\n          parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n          path = name ? PATH.join2(parent, name) : parent\n        }\n        var mode = FS.getMode(canRead, canWrite)\n        var node = FS.create(path, mode)\n        if (data) {\n          if (typeof data == 'string') {\n            var arr = new Array(data.length)\n            for (var i = 0, len = data.length; i < len; ++i)\n              arr[i] = data.charCodeAt(i)\n            data = arr\n          }\n          FS.chmod(node, mode | 146)\n          var stream = FS.open(node, 577)\n          FS.write(stream, data, 0, data.length, 0, canOwn)\n          FS.close(stream)\n          FS.chmod(node, mode)\n        }\n        return node\n      },\n      createDevice: (parent, name, input, output) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(!!input, !!output)\n        if (!FS.createDevice.major) FS.createDevice.major = 64\n        var dev = FS.makedev(FS.createDevice.major++, 0)\n        FS.registerDevice(dev, {\n          open: stream => {\n            stream.seekable = false\n          },\n          close: stream => {\n            if (output && output.buffer && output.buffer.length) {\n              output(10)\n            }\n          },\n          read: (stream, buffer, offset, length, pos) => {\n            var bytesRead = 0\n            for (var i = 0; i < length; i++) {\n              var result\n              try {\n                result = input()\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n              if (result === undefined && bytesRead === 0) {\n                throw new FS.ErrnoError(6)\n              }\n              if (result === null || result === undefined) break\n              bytesRead++\n              buffer[offset + i] = result\n            }\n            if (bytesRead) {\n              stream.node.timestamp = Date.now()\n            }\n            return bytesRead\n          },\n          write: (stream, buffer, offset, length, pos) => {\n            for (var i = 0; i < length; i++) {\n              try {\n                output(buffer[offset + i])\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n            }\n            if (length) {\n              stream.node.timestamp = Date.now()\n            }\n            return i\n          },\n        })\n        return FS.mkdev(path, mode, dev)\n      },\n      forceLoadFile: obj => {\n        if (obj.isDevice || obj.isFolder || obj.link || obj.contents)\n          return true\n        if (typeof XMLHttpRequest != 'undefined') {\n          throw new Error(\n            'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.'\n          )\n        } else if (read_) {\n          try {\n            obj.contents = intArrayFromString(read_(obj.url), true)\n            obj.usedBytes = obj.contents.length\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n        } else {\n          throw new Error('Cannot load without read() or XMLHttpRequest.')\n        }\n      },\n      createLazyFile: (parent, name, url, canRead, canWrite) => {\n        function LazyUint8Array() {\n          this.lengthKnown = false\n          this.chunks = []\n        }\n        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n          if (idx > this.length - 1 || idx < 0) {\n            return undefined\n          }\n          var chunkOffset = idx % this.chunkSize\n          var chunkNum = (idx / this.chunkSize) | 0\n          return this.getter(chunkNum)[chunkOffset]\n        }\n        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(\n          getter\n        ) {\n          this.getter = getter\n        }\n        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n          var xhr = new XMLHttpRequest()\n          xhr.open('HEAD', url, false)\n          xhr.send(null)\n          if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n            throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n          var datalength = Number(xhr.getResponseHeader('Content-length'))\n          var header\n          var hasByteServing =\n            (header = xhr.getResponseHeader('Accept-Ranges')) &&\n            header === 'bytes'\n          var usesGzip =\n            (header = xhr.getResponseHeader('Content-Encoding')) &&\n            header === 'gzip'\n          var chunkSize = 1024 * 1024\n          if (!hasByteServing) chunkSize = datalength\n          var doXHR = (from, to) => {\n            if (from > to)\n              throw new Error(\n                'invalid range (' +\n                  from +\n                  ', ' +\n                  to +\n                  ') or no bytes requested!'\n              )\n            if (to > datalength - 1)\n              throw new Error(\n                'only ' + datalength + ' bytes available! programmer error!'\n              )\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            if (datalength !== chunkSize)\n              xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to)\n            xhr.responseType = 'arraybuffer'\n            if (xhr.overrideMimeType) {\n              xhr.overrideMimeType('text/plain; charset=x-user-defined')\n            }\n            xhr.send(null)\n            if (\n              !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)\n            )\n              throw new Error(\n                \"Couldn't load \" + url + '. Status: ' + xhr.status\n              )\n            if (xhr.response !== undefined) {\n              return new Uint8Array(xhr.response || [])\n            }\n            return intArrayFromString(xhr.responseText || '', true)\n          }\n          var lazyArray = this\n          lazyArray.setDataGetter(chunkNum => {\n            var start = chunkNum * chunkSize\n            var end = (chunkNum + 1) * chunkSize - 1\n            end = Math.min(end, datalength - 1)\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined') {\n              lazyArray.chunks[chunkNum] = doXHR(start, end)\n            }\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined')\n              throw new Error('doXHR failed!')\n            return lazyArray.chunks[chunkNum]\n          })\n          if (usesGzip || !datalength) {\n            chunkSize = datalength = 1\n            datalength = this.getter(0).length\n            chunkSize = datalength\n            out(\n              'LazyFiles on gzip forces download of the whole file when length is accessed'\n            )\n          }\n          this._length = datalength\n          this._chunkSize = chunkSize\n          this.lengthKnown = true\n        }\n        if (typeof XMLHttpRequest != 'undefined') {\n          if (!ENVIRONMENT_IS_WORKER)\n            throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'\n          var lazyArray = new LazyUint8Array()\n          Object.defineProperties(lazyArray, {\n            length: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._length\n              },\n            },\n            chunkSize: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._chunkSize\n              },\n            },\n          })\n          var properties = { isDevice: false, contents: lazyArray }\n        } else {\n          var properties = { isDevice: false, url: url }\n        }\n        var node = FS.createFile(parent, name, properties, canRead, canWrite)\n        if (properties.contents) {\n          node.contents = properties.contents\n        } else if (properties.url) {\n          node.contents = null\n          node.url = properties.url\n        }\n        Object.defineProperties(node, {\n          usedBytes: {\n            get: function() {\n              return this.contents.length\n            },\n          },\n        })\n        var stream_ops = {}\n        var keys = Object.keys(node.stream_ops)\n        keys.forEach(key => {\n          var fn = node.stream_ops[key]\n          stream_ops[key] = function forceLoadLazyFile() {\n            FS.forceLoadFile(node)\n            return fn.apply(null, arguments)\n          }\n        })\n        function writeChunks(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= contents.length) return 0\n          var size = Math.min(contents.length - position, length)\n          if (contents.slice) {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents[position + i]\n            }\n          } else {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents.get(position + i)\n            }\n          }\n          return size\n        }\n        stream_ops.read = (stream, buffer, offset, length, position) => {\n          FS.forceLoadFile(node)\n          return writeChunks(stream, buffer, offset, length, position)\n        }\n        stream_ops.mmap = (stream, length, position, prot, flags) => {\n          FS.forceLoadFile(node)\n          var ptr = mmapAlloc(length)\n          if (!ptr) {\n            throw new FS.ErrnoError(48)\n          }\n          writeChunks(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        }\n        node.stream_ops = stream_ops\n        return node\n      },\n      createPreloadedFile: (\n        parent,\n        name,\n        url,\n        canRead,\n        canWrite,\n        onload,\n        onerror,\n        dontCreateFile,\n        canOwn,\n        preFinish\n      ) => {\n        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent\n        var dep = getUniqueRunDependency('cp ' + fullname)\n        function processData(byteArray) {\n          function finish(byteArray) {\n            if (preFinish) preFinish()\n            if (!dontCreateFile) {\n              FS.createDataFile(\n                parent,\n                name,\n                byteArray,\n                canRead,\n                canWrite,\n                canOwn\n              )\n            }\n            if (onload) onload()\n            removeRunDependency(dep)\n          }\n          if (\n            Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => {\n              if (onerror) onerror()\n              removeRunDependency(dep)\n            })\n          ) {\n            return\n          }\n          finish(byteArray)\n        }\n        addRunDependency(dep)\n        if (typeof url == 'string') {\n          asyncLoad(url, byteArray => processData(byteArray), onerror)\n        } else {\n          processData(url)\n        }\n      },\n      indexedDB: () => {\n        return (\n          window.indexedDB ||\n          window.mozIndexedDB ||\n          window.webkitIndexedDB ||\n          window.msIndexedDB\n        )\n      },\n      DB_NAME: () => {\n        return 'EM_FS_' + window.location.pathname\n      },\n      DB_VERSION: 20,\n      DB_STORE_NAME: 'FILE_DATA',\n      saveFilesToDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = () => {\n          out('creating db')\n          var db = openRequest.result\n          db.createObjectStore(FS.DB_STORE_NAME)\n        }\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite')\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var putRequest = files.put(\n              FS.analyzePath(path).object.contents,\n              path\n            )\n            putRequest.onsuccess = () => {\n              ok++\n              if (ok + fail == total) finish()\n            }\n            putRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n      loadFilesFromDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = onerror\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          try {\n            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly')\n          } catch (e) {\n            onerror(e)\n            return\n          }\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var getRequest = files.get(path)\n            getRequest.onsuccess = () => {\n              if (FS.analyzePath(path).exists) {\n                FS.unlink(path)\n              }\n              FS.createDataFile(\n                PATH.dirname(path),\n                PATH.basename(path),\n                getRequest.result,\n                true,\n                true,\n                true\n              )\n              ok++\n              if (ok + fail == total) finish()\n            }\n            getRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n    }\n    var SYSCALLS = {\n      DEFAULT_POLLMASK: 5,\n      calculateAt: function(dirfd, path, allowEmpty) {\n        if (PATH.isAbs(path)) {\n          return path\n        }\n        var dir\n        if (dirfd === -100) {\n          dir = FS.cwd()\n        } else {\n          var dirstream = SYSCALLS.getStreamFromFD(dirfd)\n          dir = dirstream.path\n        }\n        if (path.length == 0) {\n          if (!allowEmpty) {\n            throw new FS.ErrnoError(44)\n          }\n          return dir\n        }\n        return PATH.join2(dir, path)\n      },\n      doStat: function(func, path, buf) {\n        try {\n          var stat = func(path)\n        } catch (e) {\n          if (\n            e &&\n            e.node &&\n            PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))\n          ) {\n            return -54\n          }\n          throw e\n        }\n        HEAP32[buf >> 2] = stat.dev\n        HEAP32[(buf + 8) >> 2] = stat.ino\n        HEAP32[(buf + 12) >> 2] = stat.mode\n        HEAPU32[(buf + 16) >> 2] = stat.nlink\n        HEAP32[(buf + 20) >> 2] = stat.uid\n        HEAP32[(buf + 24) >> 2] = stat.gid\n        HEAP32[(buf + 28) >> 2] = stat.rdev\n        ;(tempI64 = [\n          stat.size >>> 0,\n          ((tempDouble = stat.size),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 40) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 44) >> 2] = tempI64[1])\n        HEAP32[(buf + 48) >> 2] = 4096\n        HEAP32[(buf + 52) >> 2] = stat.blocks\n        var atime = stat.atime.getTime()\n        var mtime = stat.mtime.getTime()\n        var ctime = stat.ctime.getTime()\n        ;(tempI64 = [\n          Math.floor(atime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(atime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 56) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 60) >> 2] = tempI64[1])\n        HEAPU32[(buf + 64) >> 2] = (atime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(mtime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(mtime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 72) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 76) >> 2] = tempI64[1])\n        HEAPU32[(buf + 80) >> 2] = (mtime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(ctime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(ctime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 88) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 92) >> 2] = tempI64[1])\n        HEAPU32[(buf + 96) >> 2] = (ctime % 1e3) * 1e3\n        ;(tempI64 = [\n          stat.ino >>> 0,\n          ((tempDouble = stat.ino),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 104) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 108) >> 2] = tempI64[1])\n        return 0\n      },\n      doMsync: function(addr, stream, len, flags, offset) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (flags & 2) {\n          return 0\n        }\n        var buffer = HEAPU8.slice(addr, addr + len)\n        FS.msync(stream, buffer, offset, len, flags)\n      },\n      varargs: undefined,\n      get: function() {\n        SYSCALLS.varargs += 4\n        var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]\n        return ret\n      },\n      getStr: function(ptr) {\n        var ret = UTF8ToString(ptr)\n        return ret\n      },\n      getStreamFromFD: function(fd) {\n        var stream = FS.getStream(fd)\n        if (!stream) throw new FS.ErrnoError(8)\n        return stream\n      },\n    }\n    function ___syscall_fcntl64(fd, cmd, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (cmd) {\n          case 0: {\n            var arg = SYSCALLS.get()\n            if (arg < 0) {\n              return -28\n            }\n            var newStream\n            newStream = FS.createStream(stream, arg)\n            return newStream.fd\n          }\n          case 1:\n          case 2:\n            return 0\n          case 3:\n            return stream.flags\n          case 4: {\n            var arg = SYSCALLS.get()\n            stream.flags |= arg\n            return 0\n          }\n          case 5: {\n            var arg = SYSCALLS.get()\n            var offset = 0\n            HEAP16[(arg + offset) >> 1] = 2\n            return 0\n          }\n          case 6:\n          case 7:\n            return 0\n          case 16:\n          case 8:\n            return -28\n          case 9:\n            setErrNo(28)\n            return -1\n          default: {\n            return -28\n          }\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_getcwd(buf, size) {\n      try {\n        if (size === 0) return -28\n        var cwd = FS.cwd()\n        var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1\n        if (size < cwdLengthInBytes) return -68\n        stringToUTF8(cwd, buf, size)\n        return cwdLengthInBytes\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_ioctl(fd, op, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (op) {\n          case 21509:\n          case 21505: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21510:\n          case 21511:\n          case 21512:\n          case 21506:\n          case 21507:\n          case 21508: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21519: {\n            if (!stream.tty) return -59\n            var argp = SYSCALLS.get()\n            HEAP32[argp >> 2] = 0\n            return 0\n          }\n          case 21520: {\n            if (!stream.tty) return -59\n            return -28\n          }\n          case 21531: {\n            var argp = SYSCALLS.get()\n            return FS.ioctl(stream, op, argp)\n          }\n          case 21523: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21524: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          default:\n            return -28\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_openat(dirfd, path, flags, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        var mode = varargs ? SYSCALLS.get() : 0\n        return FS.open(path, flags, mode).fd\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_readlinkat(dirfd, path, buf, bufsize) {\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        if (bufsize <= 0) return -28\n        var ret = FS.readlink(path)\n        var len = Math.min(bufsize, lengthBytesUTF8(ret))\n        var endChar = HEAP8[buf + len]\n        stringToUTF8(ret, buf, bufsize + 1)\n        HEAP8[buf + len] = endChar\n        return len\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_stat64(path, buf) {\n      try {\n        path = SYSCALLS.getStr(path)\n        return SYSCALLS.doStat(FS.stat, path, buf)\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function _abort() {\n      abort('')\n    }\n    function _emscripten_memcpy_big(dest, src, num) {\n      HEAPU8.copyWithin(dest, src, src + num)\n    }\n    function getHeapMax() {\n      return 2147483648\n    }\n    function emscripten_realloc_buffer(size) {\n      try {\n        wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16)\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        return 1\n      } catch (e) {}\n    }\n    function _emscripten_resize_heap(requestedSize) {\n      var oldSize = HEAPU8.length\n      requestedSize = requestedSize >>> 0\n      var maxHeapSize = getHeapMax()\n      if (requestedSize > maxHeapSize) {\n        return false\n      }\n      let alignUp = (x, multiple) =>\n        x + ((multiple - (x % multiple)) % multiple)\n      for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {\n        var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown)\n        overGrownHeapSize = Math.min(\n          overGrownHeapSize,\n          requestedSize + 100663296\n        )\n        var newSize = Math.min(\n          maxHeapSize,\n          alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)\n        )\n        var replacement = emscripten_realloc_buffer(newSize)\n        if (replacement) {\n          return true\n        }\n      }\n      return false\n    }\n    var ENV = {}\n    function getExecutableName() {\n      return thisProgram || './this.program'\n    }\n    function getEnvStrings() {\n      if (!getEnvStrings.strings) {\n        var lang =\n          (\n            (typeof navigator == 'object' &&\n              navigator.languages &&\n              navigator.languages[0]) ||\n            'C'\n          ).replace('-', '_') + '.UTF-8'\n        var env = {\n          USER: 'web_user',\n          LOGNAME: 'web_user',\n          PATH: '/',\n          PWD: '/',\n          HOME: '/home/web_user',\n          LANG: lang,\n          _: getExecutableName(),\n        }\n        for (var x in ENV) {\n          if (ENV[x] === undefined) delete env[x]\n          else env[x] = ENV[x]\n        }\n        var strings = []\n        for (var x in env) {\n          strings.push(x + '=' + env[x])\n        }\n        getEnvStrings.strings = strings\n      }\n      return getEnvStrings.strings\n    }\n    function writeAsciiToMemory(str, buffer, dontAddNull) {\n      for (var i = 0; i < str.length; ++i) {\n        HEAP8[buffer++ >> 0] = str.charCodeAt(i)\n      }\n      if (!dontAddNull) HEAP8[buffer >> 0] = 0\n    }\n    function _environ_get(__environ, environ_buf) {\n      var bufSize = 0\n      getEnvStrings().forEach(function(string, i) {\n        var ptr = environ_buf + bufSize\n        HEAPU32[(__environ + i * 4) >> 2] = ptr\n        writeAsciiToMemory(string, ptr)\n        bufSize += string.length + 1\n      })\n      return 0\n    }\n    function _environ_sizes_get(penviron_count, penviron_buf_size) {\n      var strings = getEnvStrings()\n      HEAPU32[penviron_count >> 2] = strings.length\n      var bufSize = 0\n      strings.forEach(function(string) {\n        bufSize += string.length + 1\n      })\n      HEAPU32[penviron_buf_size >> 2] = bufSize\n      return 0\n    }\n    function _proc_exit(code) {\n      EXITSTATUS = code\n      if (!keepRuntimeAlive()) {\n        if (Module['onExit']) Module['onExit'](code)\n        ABORT = true\n      }\n      quit_(code, new ExitStatus(code))\n    }\n    function exitJS(status, implicit) {\n      EXITSTATUS = status\n      _proc_exit(status)\n    }\n    var _exit = exitJS\n    function _fd_close(fd) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.close(stream)\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doReadv(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.read(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n        if (curr < len) break\n      }\n      return ret\n    }\n    function _fd_read(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doReadv(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function convertI32PairToI53Checked(lo, hi) {\n      return (hi + 2097152) >>> 0 < 4194305 - !!lo\n        ? (lo >>> 0) + hi * 4294967296\n        : NaN\n    }\n    function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {\n      try {\n        var offset = convertI32PairToI53Checked(offset_low, offset_high)\n        if (isNaN(offset)) return 61\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.llseek(stream, offset, whence)\n        ;(tempI64 = [\n          stream.position >>> 0,\n          ((tempDouble = stream.position),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[newOffset >> 2] = tempI64[0]),\n          (HEAP32[(newOffset + 4) >> 2] = tempI64[1])\n        if (stream.getdents && offset === 0 && whence === 0)\n          stream.getdents = null\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doWritev(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.write(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n      }\n      return ret\n    }\n    function _fd_write(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doWritev(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function __isLeapYear(year) {\n      return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n    }\n    function __arraySum(array, index) {\n      var sum = 0\n      for (var i = 0; i <= index; sum += array[i++]) {}\n      return sum\n    }\n    var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    function __addDays(date, days) {\n      var newDate = new Date(date.getTime())\n      while (days > 0) {\n        var leap = __isLeapYear(newDate.getFullYear())\n        var currentMonth = newDate.getMonth()\n        var daysInCurrentMonth = (leap\n          ? __MONTH_DAYS_LEAP\n          : __MONTH_DAYS_REGULAR)[currentMonth]\n        if (days > daysInCurrentMonth - newDate.getDate()) {\n          days -= daysInCurrentMonth - newDate.getDate() + 1\n          newDate.setDate(1)\n          if (currentMonth < 11) {\n            newDate.setMonth(currentMonth + 1)\n          } else {\n            newDate.setMonth(0)\n            newDate.setFullYear(newDate.getFullYear() + 1)\n          }\n        } else {\n          newDate.setDate(newDate.getDate() + days)\n          return newDate\n        }\n      }\n      return newDate\n    }\n    function writeArrayToMemory(array, buffer) {\n      HEAP8.set(array, buffer)\n    }\n    function _strftime(s, maxsize, format, tm) {\n      var tm_zone = HEAP32[(tm + 40) >> 2]\n      var date = {\n        tm_sec: HEAP32[tm >> 2],\n        tm_min: HEAP32[(tm + 4) >> 2],\n        tm_hour: HEAP32[(tm + 8) >> 2],\n        tm_mday: HEAP32[(tm + 12) >> 2],\n        tm_mon: HEAP32[(tm + 16) >> 2],\n        tm_year: HEAP32[(tm + 20) >> 2],\n        tm_wday: HEAP32[(tm + 24) >> 2],\n        tm_yday: HEAP32[(tm + 28) >> 2],\n        tm_isdst: HEAP32[(tm + 32) >> 2],\n        tm_gmtoff: HEAP32[(tm + 36) >> 2],\n        tm_zone: tm_zone ? UTF8ToString(tm_zone) : '',\n      }\n      var pattern = UTF8ToString(format)\n      var EXPANSION_RULES_1 = {\n        '%c': '%a %b %d %H:%M:%S %Y',\n        '%D': '%m/%d/%y',\n        '%F': '%Y-%m-%d',\n        '%h': '%b',\n        '%r': '%I:%M:%S %p',\n        '%R': '%H:%M',\n        '%T': '%H:%M:%S',\n        '%x': '%m/%d/%y',\n        '%X': '%H:%M:%S',\n        '%Ec': '%c',\n        '%EC': '%C',\n        '%Ex': '%m/%d/%y',\n        '%EX': '%H:%M:%S',\n        '%Ey': '%y',\n        '%EY': '%Y',\n        '%Od': '%d',\n        '%Oe': '%e',\n        '%OH': '%H',\n        '%OI': '%I',\n        '%Om': '%m',\n        '%OM': '%M',\n        '%OS': '%S',\n        '%Ou': '%u',\n        '%OU': '%U',\n        '%OV': '%V',\n        '%Ow': '%w',\n        '%OW': '%W',\n        '%Oy': '%y',\n      }\n      for (var rule in EXPANSION_RULES_1) {\n        pattern = pattern.replace(\n          new RegExp(rule, 'g'),\n          EXPANSION_RULES_1[rule]\n        )\n      }\n      var WEEKDAYS = [\n        'Sunday',\n        'Monday',\n        'Tuesday',\n        'Wednesday',\n        'Thursday',\n        'Friday',\n        'Saturday',\n      ]\n      var MONTHS = [\n        'January',\n        'February',\n        'March',\n        'April',\n        'May',\n        'June',\n        'July',\n        'August',\n        'September',\n        'October',\n        'November',\n        'December',\n      ]\n      function leadingSomething(value, digits, character) {\n        var str = typeof value == 'number' ? value.toString() : value || ''\n        while (str.length < digits) {\n          str = character[0] + str\n        }\n        return str\n      }\n      function leadingNulls(value, digits) {\n        return leadingSomething(value, digits, '0')\n      }\n      function compareByDay(date1, date2) {\n        function sgn(value) {\n          return value < 0 ? -1 : value > 0 ? 1 : 0\n        }\n        var compare\n        if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) {\n          if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) {\n            compare = sgn(date1.getDate() - date2.getDate())\n          }\n        }\n        return compare\n      }\n      function getFirstWeekStartDate(janFourth) {\n        switch (janFourth.getDay()) {\n          case 0:\n            return new Date(janFourth.getFullYear() - 1, 11, 29)\n          case 1:\n            return janFourth\n          case 2:\n            return new Date(janFourth.getFullYear(), 0, 3)\n          case 3:\n            return new Date(janFourth.getFullYear(), 0, 2)\n          case 4:\n            return new Date(janFourth.getFullYear(), 0, 1)\n          case 5:\n            return new Date(janFourth.getFullYear() - 1, 11, 31)\n          case 6:\n            return new Date(janFourth.getFullYear() - 1, 11, 30)\n        }\n      }\n      function getWeekBasedYear(date) {\n        var thisDate = __addDays(\n          new Date(date.tm_year + 1900, 0, 1),\n          date.tm_yday\n        )\n        var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4)\n        var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4)\n        var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear)\n        var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear)\n        if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {\n          if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {\n            return thisDate.getFullYear() + 1\n          }\n          return thisDate.getFullYear()\n        }\n        return thisDate.getFullYear() - 1\n      }\n      var EXPANSION_RULES_2 = {\n        '%a': function(date) {\n          return WEEKDAYS[date.tm_wday].substring(0, 3)\n        },\n        '%A': function(date) {\n          return WEEKDAYS[date.tm_wday]\n        },\n        '%b': function(date) {\n          return MONTHS[date.tm_mon].substring(0, 3)\n        },\n        '%B': function(date) {\n          return MONTHS[date.tm_mon]\n        },\n        '%C': function(date) {\n          var year = date.tm_year + 1900\n          return leadingNulls((year / 100) | 0, 2)\n        },\n        '%d': function(date) {\n          return leadingNulls(date.tm_mday, 2)\n        },\n        '%e': function(date) {\n          return leadingSomething(date.tm_mday, 2, ' ')\n        },\n        '%g': function(date) {\n          return getWeekBasedYear(date)\n            .toString()\n            .substring(2)\n        },\n        '%G': function(date) {\n          return getWeekBasedYear(date)\n        },\n        '%H': function(date) {\n          return leadingNulls(date.tm_hour, 2)\n        },\n        '%I': function(date) {\n          var twelveHour = date.tm_hour\n          if (twelveHour == 0) twelveHour = 12\n          else if (twelveHour > 12) twelveHour -= 12\n          return leadingNulls(twelveHour, 2)\n        },\n        '%j': function(date) {\n          return leadingNulls(\n            date.tm_mday +\n              __arraySum(\n                __isLeapYear(date.tm_year + 1900)\n                  ? __MONTH_DAYS_LEAP\n                  : __MONTH_DAYS_REGULAR,\n                date.tm_mon - 1\n              ),\n            3\n          )\n        },\n        '%m': function(date) {\n          return leadingNulls(date.tm_mon + 1, 2)\n        },\n        '%M': function(date) {\n          return leadingNulls(date.tm_min, 2)\n        },\n        '%n': function() {\n          return '\\n'\n        },\n        '%p': function(date) {\n          if (date.tm_hour >= 0 && date.tm_hour < 12) {\n            return 'AM'\n          }\n          return 'PM'\n        },\n        '%S': function(date) {\n          return leadingNulls(date.tm_sec, 2)\n        },\n        '%t': function() {\n          return '\\t'\n        },\n        '%u': function(date) {\n          return date.tm_wday || 7\n        },\n        '%U': function(date) {\n          var days = date.tm_yday + 7 - date.tm_wday\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%V': function(date) {\n          var val = Math.floor(\n            (date.tm_yday + 7 - ((date.tm_wday + 6) % 7)) / 7\n          )\n          if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) {\n            val++\n          }\n          if (!val) {\n            val = 52\n            var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7\n            if (\n              dec31 == 4 ||\n              (dec31 == 5 && __isLeapYear((date.tm_year % 400) - 1))\n            ) {\n              val++\n            }\n          } else if (val == 53) {\n            var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7\n            if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) val = 1\n          }\n          return leadingNulls(val, 2)\n        },\n        '%w': function(date) {\n          return date.tm_wday\n        },\n        '%W': function(date) {\n          var days = date.tm_yday + 7 - ((date.tm_wday + 6) % 7)\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%y': function(date) {\n          return (date.tm_year + 1900).toString().substring(2)\n        },\n        '%Y': function(date) {\n          return date.tm_year + 1900\n        },\n        '%z': function(date) {\n          var off = date.tm_gmtoff\n          var ahead = off >= 0\n          off = Math.abs(off) / 60\n          off = (off / 60) * 100 + (off % 60)\n          return (ahead ? '+' : '-') + String('0000' + off).slice(-4)\n        },\n        '%Z': function(date) {\n          return date.tm_zone\n        },\n        '%%': function() {\n          return '%'\n        },\n      }\n      pattern = pattern.replace(/%%/g, '\\0\\0')\n      for (var rule in EXPANSION_RULES_2) {\n        if (pattern.includes(rule)) {\n          pattern = pattern.replace(\n            new RegExp(rule, 'g'),\n            EXPANSION_RULES_2[rule](date)\n          )\n        }\n      }\n      pattern = pattern.replace(/\\0\\0/g, '%')\n      var bytes = intArrayFromString(pattern, false)\n      if (bytes.length > maxsize) {\n        return 0\n      }\n      writeArrayToMemory(bytes, s)\n      return bytes.length - 1\n    }\n    function _strftime_l(s, maxsize, format, tm, loc) {\n      return _strftime(s, maxsize, format, tm)\n    }\n    function handleException(e) {\n      if (e instanceof ExitStatus || e == 'unwind') {\n        return EXITSTATUS\n      }\n      quit_(1, e)\n    }\n    function allocateUTF8OnStack(str) {\n      var size = lengthBytesUTF8(str) + 1\n      var ret = stackAlloc(size)\n      stringToUTF8Array(str, HEAP8, ret, size)\n      return ret\n    }\n    function getCFunc(ident) {\n      var func = Module['_' + ident]\n      return func\n    }\n    function ccall(ident, returnType, argTypes, args, opts) {\n      var toC = {\n        string: str => {\n          var ret = 0\n          if (str !== null && str !== undefined && str !== 0) {\n            var len = (str.length << 2) + 1\n            ret = stackAlloc(len)\n            stringToUTF8(str, ret, len)\n          }\n          return ret\n        },\n        array: arr => {\n          var ret = stackAlloc(arr.length)\n          writeArrayToMemory(arr, ret)\n          return ret\n        },\n      }\n      function convertReturnValue(ret) {\n        if (returnType === 'string') {\n          return UTF8ToString(ret)\n        }\n        if (returnType === 'boolean') return Boolean(ret)\n        return ret\n      }\n      var func = getCFunc(ident)\n      var cArgs = []\n      var stack = 0\n      if (args) {\n        for (var i = 0; i < args.length; i++) {\n          var converter = toC[argTypes[i]]\n          if (converter) {\n            if (stack === 0) stack = stackSave()\n            cArgs[i] = converter(args[i])\n          } else {\n            cArgs[i] = args[i]\n          }\n        }\n      }\n      var ret = func.apply(null, cArgs)\n      function onDone(ret) {\n        if (stack !== 0) stackRestore(stack)\n        return convertReturnValue(ret)\n      }\n      ret = onDone(ret)\n      return ret\n    }\n    function cwrap(ident, returnType, argTypes, opts) {\n      argTypes = argTypes || []\n      var numericArgs = argTypes.every(\n        type => type === 'number' || type === 'boolean'\n      )\n      var numericRet = returnType !== 'string'\n      if (numericRet && numericArgs && !opts) {\n        return getCFunc(ident)\n      }\n      return function() {\n        return ccall(ident, returnType, argTypes, arguments, opts)\n      }\n    }\n    function AsciiToString(ptr) {\n      var str = ''\n      while (1) {\n        var ch = HEAPU8[ptr++ >> 0]\n        if (!ch) return str\n        str += String.fromCharCode(ch)\n      }\n    }\n    var FSNode = function(parent, name, mode, rdev) {\n      if (!parent) {\n        parent = this\n      }\n      this.parent = parent\n      this.mount = parent.mount\n      this.mounted = null\n      this.id = FS.nextInode++\n      this.name = name\n      this.mode = mode\n      this.node_ops = {}\n      this.stream_ops = {}\n      this.rdev = rdev\n    }\n    var readMode = 292 | 73\n    var writeMode = 146\n    Object.defineProperties(FSNode.prototype, {\n      read: {\n        get: function() {\n          return (this.mode & readMode) === readMode\n        },\n        set: function(val) {\n          val ? (this.mode |= readMode) : (this.mode &= ~readMode)\n        },\n      },\n      write: {\n        get: function() {\n          return (this.mode & writeMode) === writeMode\n        },\n        set: function(val) {\n          val ? (this.mode |= writeMode) : (this.mode &= ~writeMode)\n        },\n      },\n      isFolder: {\n        get: function() {\n          return FS.isDir(this.mode)\n        },\n      },\n      isDevice: {\n        get: function() {\n          return FS.isChrdev(this.mode)\n        },\n      },\n    })\n    FS.FSNode = FSNode\n    FS.staticInit()\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_unlink'] = FS.unlink\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    if (ENVIRONMENT_IS_NODE) {\n      NODEFS.staticInit()\n    }\n    ERRNO_CODES = {\n      EPERM: 63,\n      ENOENT: 44,\n      ESRCH: 71,\n      EINTR: 27,\n      EIO: 29,\n      ENXIO: 60,\n      E2BIG: 1,\n      ENOEXEC: 45,\n      EBADF: 8,\n      ECHILD: 12,\n      EAGAIN: 6,\n      EWOULDBLOCK: 6,\n      ENOMEM: 48,\n      EACCES: 2,\n      EFAULT: 21,\n      ENOTBLK: 105,\n      EBUSY: 10,\n      EEXIST: 20,\n      EXDEV: 75,\n      ENODEV: 43,\n      ENOTDIR: 54,\n      EISDIR: 31,\n      EINVAL: 28,\n      ENFILE: 41,\n      EMFILE: 33,\n      ENOTTY: 59,\n      ETXTBSY: 74,\n      EFBIG: 22,\n      ENOSPC: 51,\n      ESPIPE: 70,\n      EROFS: 69,\n      EMLINK: 34,\n      EPIPE: 64,\n      EDOM: 18,\n      ERANGE: 68,\n      ENOMSG: 49,\n      EIDRM: 24,\n      ECHRNG: 106,\n      EL2NSYNC: 156,\n      EL3HLT: 107,\n      EL3RST: 108,\n      ELNRNG: 109,\n      EUNATCH: 110,\n      ENOCSI: 111,\n      EL2HLT: 112,\n      EDEADLK: 16,\n      ENOLCK: 46,\n      EBADE: 113,\n      EBADR: 114,\n      EXFULL: 115,\n      ENOANO: 104,\n      EBADRQC: 103,\n      EBADSLT: 102,\n      EDEADLOCK: 16,\n      EBFONT: 101,\n      ENOSTR: 100,\n      ENODATA: 116,\n      ETIME: 117,\n      ENOSR: 118,\n      ENONET: 119,\n      ENOPKG: 120,\n      EREMOTE: 121,\n      ENOLINK: 47,\n      EADV: 122,\n      ESRMNT: 123,\n      ECOMM: 124,\n      EPROTO: 65,\n      EMULTIHOP: 36,\n      EDOTDOT: 125,\n      EBADMSG: 9,\n      ENOTUNIQ: 126,\n      EBADFD: 127,\n      EREMCHG: 128,\n      ELIBACC: 129,\n      ELIBBAD: 130,\n      ELIBSCN: 131,\n      ELIBMAX: 132,\n      ELIBEXEC: 133,\n      ENOSYS: 52,\n      ENOTEMPTY: 55,\n      ENAMETOOLONG: 37,\n      ELOOP: 32,\n      EOPNOTSUPP: 138,\n      EPFNOSUPPORT: 139,\n      ECONNRESET: 15,\n      ENOBUFS: 42,\n      EAFNOSUPPORT: 5,\n      EPROTOTYPE: 67,\n      ENOTSOCK: 57,\n      ENOPROTOOPT: 50,\n      ESHUTDOWN: 140,\n      ECONNREFUSED: 14,\n      EADDRINUSE: 3,\n      ECONNABORTED: 13,\n      ENETUNREACH: 40,\n      ENETDOWN: 38,\n      ETIMEDOUT: 73,\n      EHOSTDOWN: 142,\n      EHOSTUNREACH: 23,\n      EINPROGRESS: 26,\n      EALREADY: 7,\n      EDESTADDRREQ: 17,\n      EMSGSIZE: 35,\n      EPROTONOSUPPORT: 66,\n      ESOCKTNOSUPPORT: 137,\n      EADDRNOTAVAIL: 4,\n      ENETRESET: 39,\n      EISCONN: 30,\n      ENOTCONN: 53,\n      ETOOMANYREFS: 141,\n      EUSERS: 136,\n      EDQUOT: 19,\n      ESTALE: 72,\n      ENOTSUP: 138,\n      ENOMEDIUM: 148,\n      EILSEQ: 25,\n      EOVERFLOW: 61,\n      ECANCELED: 11,\n      ENOTRECOVERABLE: 56,\n      EOWNERDEAD: 62,\n      ESTRPIPE: 135,\n    }\n    var asmLibraryArg = {\n      a: ___cxa_throw,\n      d: ___syscall_fcntl64,\n      r: ___syscall_getcwd,\n      i: ___syscall_ioctl,\n      j: ___syscall_openat,\n      n: ___syscall_readlinkat,\n      o: ___syscall_stat64,\n      b: _abort,\n      f: _emscripten_memcpy_big,\n      m: _emscripten_resize_heap,\n      p: _environ_get,\n      q: _environ_sizes_get,\n      c: _exit,\n      e: _fd_close,\n      h: _fd_read,\n      k: _fd_seek,\n      g: _fd_write,\n      l: _strftime_l,\n    }\n    var asm = createWasm()\n    var ___wasm_call_ctors = (Module['___wasm_call_ctors'] = function() {\n      return (___wasm_call_ctors = Module['___wasm_call_ctors'] =\n        Module['asm']['t']).apply(null, arguments)\n    })\n    var _main = (Module['_main'] = function() {\n      return (_main = Module['_main'] = Module['asm']['u']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___errno_location = (Module['___errno_location'] = function() {\n      return (___errno_location = Module['___errno_location'] =\n        Module['asm']['v']).apply(null, arguments)\n    })\n    var _itk_wasm_input_array_alloc = (Module[\n      '_itk_wasm_input_array_alloc'\n    ] = function() {\n      return (_itk_wasm_input_array_alloc = Module[\n        '_itk_wasm_input_array_alloc'\n      ] = Module['asm']['w']).apply(null, arguments)\n    })\n    var _itk_wasm_input_json_alloc = (Module[\n      '_itk_wasm_input_json_alloc'\n    ] = function() {\n      return (_itk_wasm_input_json_alloc = Module[\n        '_itk_wasm_input_json_alloc'\n      ] = Module['asm']['x']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_address = (Module[\n      '_itk_wasm_output_json_address'\n    ] = function() {\n      return (_itk_wasm_output_json_address = Module[\n        '_itk_wasm_output_json_address'\n      ] = Module['asm']['y']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_size = (Module[\n      '_itk_wasm_output_json_size'\n    ] = function() {\n      return (_itk_wasm_output_json_size = Module[\n        '_itk_wasm_output_json_size'\n      ] = Module['asm']['z']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_address = (Module[\n      '_itk_wasm_output_array_address'\n    ] = function() {\n      return (_itk_wasm_output_array_address = Module[\n        '_itk_wasm_output_array_address'\n      ] = Module['asm']['A']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_size = (Module[\n      '_itk_wasm_output_array_size'\n    ] = function() {\n      return (_itk_wasm_output_array_size = Module[\n        '_itk_wasm_output_array_size'\n      ] = Module['asm']['B']).apply(null, arguments)\n    })\n    var _itk_wasm_free_all = (Module['_itk_wasm_free_all'] = function() {\n      return (_itk_wasm_free_all = Module['_itk_wasm_free_all'] =\n        Module['asm']['C']).apply(null, arguments)\n    })\n    var stackSave = (Module['stackSave'] = function() {\n      return (stackSave = Module['stackSave'] = Module['asm']['E']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackRestore = (Module['stackRestore'] = function() {\n      return (stackRestore = Module['stackRestore'] = Module['asm']['F']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackAlloc = (Module['stackAlloc'] = function() {\n      return (stackAlloc = Module['stackAlloc'] = Module['asm']['G']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___cxa_is_pointer_type = (Module[\n      '___cxa_is_pointer_type'\n    ] = function() {\n      return (___cxa_is_pointer_type = Module['___cxa_is_pointer_type'] =\n        Module['asm']['H']).apply(null, arguments)\n    })\n    Module['addRunDependency'] = addRunDependency\n    Module['removeRunDependency'] = removeRunDependency\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    Module['FS_unlink'] = FS.unlink\n    Module['callMain'] = callMain\n    Module['ccall'] = ccall\n    Module['cwrap'] = cwrap\n    Module['AsciiToString'] = AsciiToString\n    Module['writeArrayToMemory'] = writeArrayToMemory\n    Module['writeAsciiToMemory'] = writeAsciiToMemory\n    var calledRun\n    dependenciesFulfilled = function runCaller() {\n      if (!calledRun) run()\n      if (!calledRun) dependenciesFulfilled = runCaller\n    }\n    function callMain(args) {\n      var entryFunction = Module['_main']\n      args = args || []\n      args.unshift(thisProgram)\n      var argc = args.length\n      var argv = stackAlloc((argc + 1) * 4)\n      var argv_ptr = argv >> 2\n      args.forEach(arg => {\n        HEAP32[argv_ptr++] = allocateUTF8OnStack(arg)\n      })\n      HEAP32[argv_ptr] = 0\n      try {\n        var ret = entryFunction(argc, argv)\n        exitJS(ret, true)\n        return ret\n      } catch (e) {\n        return handleException(e)\n      }\n    }\n    function run(args) {\n      args = args || arguments_\n      if (runDependencies > 0) {\n        return\n      }\n      preRun()\n      if (runDependencies > 0) {\n        return\n      }\n      function doRun() {\n        if (calledRun) return\n        calledRun = true\n        Module['calledRun'] = true\n        if (ABORT) return\n        initRuntime()\n        preMain()\n        readyPromiseResolve(Module)\n        if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']()\n        if (shouldRunNow) callMain(args)\n        postRun()\n      }\n      if (Module['setStatus']) {\n        Module['setStatus']('Running...')\n        setTimeout(function() {\n          setTimeout(function() {\n            Module['setStatus']('')\n          }, 1)\n          doRun()\n        }, 1)\n      } else {\n        doRun()\n      }\n    }\n    if (Module['preInit']) {\n      if (typeof Module['preInit'] == 'function')\n        Module['preInit'] = [Module['preInit']]\n      while (Module['preInit'].length > 0) {\n        Module['preInit'].pop()()\n      }\n    }\n    var shouldRunNow = false\n    if (Module['noInitialRun']) shouldRunNow = false\n    run()\n    Module.mountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      if (FS.isDir(containingDir) || containingDir === '/') {\n        return\n      }\n      var currentDir = '/'\n      var splitContainingDir = containingDir.split(path.sep)\n      for (var ii = 1; ii < splitContainingDir.length; ii++) {\n        currentDir += splitContainingDir[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n      FS.mount(NODEFS, { root: containingDir }, currentDir)\n      return currentDir + path.basename(filePath)\n    }\n    Module.unmountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      FS.unmount(containingDir)\n    }\n    Module.fs_mkdirs = function(dirs) {\n      var currentDir = '/'\n      var splitDirs = dirs.split('/')\n      for (var ii = 1; ii < splitDirs.length; ++ii) {\n        currentDir += splitDirs[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n    }\n    Module.fs_readFile = function(path, opts) {\n      return FS.readFile(path, opts)\n    }\n    Module.fs_writeFile = function(path, data, opts) {\n      return FS.writeFile(path, data, opts)\n    }\n    Module.fs_unlink = function(path) {\n      return FS.unlink(path)\n    }\n    Module.fs_open = function(path, flags, mode) {\n      return FS.open(path, flags, mode)\n    }\n    Module.fs_stat = function(path) {\n      return FS.stat(path)\n    }\n    Module.fs_read = function(stream, buffer, offset, length, position) {\n      return FS.read(stream, buffer, offset, length, position)\n    }\n    Module.fs_close = function(stream) {\n      return FS.close(stream)\n    }\n\n    return DownsampleLabelImage.ready\n  }\n})()\nexport default DownsampleLabelImage\n"
  },
  {
    "path": "src/IO/Downsample/emscripten-build/DownsampleLabelImage.umd.js",
    "content": "var DownsampleLabelImage = (() => {\n  var _scriptDir =\n    typeof document !== 'undefined' && document.currentScript\n      ? document.currentScript.src\n      : undefined\n  if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename\n  return function(DownsampleLabelImage) {\n    DownsampleLabelImage = DownsampleLabelImage || {}\n\n    var Module =\n      typeof DownsampleLabelImage != 'undefined' ? DownsampleLabelImage : {}\n    var readyPromiseResolve, readyPromiseReject\n    Module['ready'] = new Promise(function(resolve, reject) {\n      readyPromiseResolve = resolve\n      readyPromiseReject = reject\n    })\n    var mStdout = null\n    var mStderr = null\n    Module['resetModuleStdout'] = function() {\n      mStdout = ''\n    }\n    Module['resetModuleStderr'] = function() {\n      mStderr = ''\n    }\n    Module['print'] = function(text) {\n      console.log(text)\n      mStdout += text + '\\n'\n    }\n    Module['printErr'] = function(text) {\n      console.error(text)\n      mStderr += text + '\\n'\n    }\n    Module['getModuleStdout'] = function() {\n      return mStdout\n    }\n    Module['getModuleStderr'] = function() {\n      return mStderr\n    }\n    var moduleOverrides = Object.assign({}, Module)\n    var arguments_ = []\n    var thisProgram = './this.program'\n    var quit_ = (status, toThrow) => {\n      throw toThrow\n    }\n    var ENVIRONMENT_IS_WEB = typeof window == 'object'\n    var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'\n    var ENVIRONMENT_IS_NODE =\n      typeof process == 'object' &&\n      typeof process.versions == 'object' &&\n      typeof process.versions.node == 'string'\n    var scriptDirectory = ''\n    function locateFile(path) {\n      if (Module['locateFile']) {\n        return Module['locateFile'](path, scriptDirectory)\n      }\n      return scriptDirectory + path\n    }\n    var read_, readAsync, readBinary, setWindowTitle\n    function logExceptionOnExit(e) {\n      if (e instanceof ExitStatus) return\n      let toLog = e\n      err('exiting due to exception: ' + toLog)\n    }\n    if (ENVIRONMENT_IS_NODE) {\n      var fs = require('fs')\n      var nodePath = require('path')\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = nodePath.dirname(scriptDirectory) + '/'\n      } else {\n        scriptDirectory = __dirname + '/'\n      }\n      read_ = (filename, binary) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        return fs.readFileSync(filename, binary ? undefined : 'utf8')\n      }\n      readBinary = filename => {\n        var ret = read_(filename, true)\n        if (!ret.buffer) {\n          ret = new Uint8Array(ret)\n        }\n        return ret\n      }\n      readAsync = (filename, onload, onerror) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        fs.readFile(filename, function(err, data) {\n          if (err) onerror(err)\n          else onload(data.buffer)\n        })\n      }\n      if (process['argv'].length > 1) {\n        thisProgram = process['argv'][1].replace(/\\\\/g, '/')\n      }\n      arguments_ = process['argv'].slice(2)\n      process['on']('uncaughtException', function(ex) {\n        if (!(ex instanceof ExitStatus)) {\n          throw ex\n        }\n      })\n      process['on']('unhandledRejection', function(reason) {\n        throw reason\n      })\n      quit_ = (status, toThrow) => {\n        if (keepRuntimeAlive()) {\n          process['exitCode'] = status\n          throw toThrow\n        }\n        logExceptionOnExit(toThrow)\n        process['exit'](status)\n      }\n      Module['inspect'] = function() {\n        return '[Emscripten Module object]'\n      }\n    } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = self.location.href\n      } else if (typeof document != 'undefined' && document.currentScript) {\n        scriptDirectory = document.currentScript.src\n      }\n      if (_scriptDir) {\n        scriptDirectory = _scriptDir\n      }\n      if (scriptDirectory.indexOf('blob:') !== 0) {\n        scriptDirectory = scriptDirectory.substr(\n          0,\n          scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1\n        )\n      } else {\n        scriptDirectory = ''\n      }\n      {\n        read_ = url => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, false)\n          xhr.send(null)\n          return xhr.responseText\n        }\n        if (ENVIRONMENT_IS_WORKER) {\n          readBinary = url => {\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            xhr.responseType = 'arraybuffer'\n            xhr.send(null)\n            return new Uint8Array(xhr.response)\n          }\n        }\n        readAsync = (url, onload, onerror) => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, true)\n          xhr.responseType = 'arraybuffer'\n          xhr.onload = () => {\n            if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n              onload(xhr.response)\n              return\n            }\n            onerror()\n          }\n          xhr.onerror = onerror\n          xhr.send(null)\n        }\n      }\n      setWindowTitle = title => (document.title = title)\n    } else {\n    }\n    var out = Module['print'] || console.log.bind(console)\n    var err = Module['printErr'] || console.warn.bind(console)\n    Object.assign(Module, moduleOverrides)\n    moduleOverrides = null\n    if (Module['arguments']) arguments_ = Module['arguments']\n    if (Module['thisProgram']) thisProgram = Module['thisProgram']\n    if (Module['quit']) quit_ = Module['quit']\n    var wasmBinary\n    if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']\n    var noExitRuntime = Module['noExitRuntime'] || true\n    if (typeof WebAssembly != 'object') {\n      abort('no native wasm support detected')\n    }\n    var wasmMemory\n    var ABORT = false\n    var EXITSTATUS\n    function assert(condition, text) {\n      if (!condition) {\n        abort(text)\n      }\n    }\n    var UTF8Decoder =\n      typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined\n    function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {\n      var endIdx = idx + maxBytesToRead\n      var endPtr = idx\n      while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr\n      if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {\n        return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr))\n      }\n      var str = ''\n      while (idx < endPtr) {\n        var u0 = heapOrArray[idx++]\n        if (!(u0 & 128)) {\n          str += String.fromCharCode(u0)\n          continue\n        }\n        var u1 = heapOrArray[idx++] & 63\n        if ((u0 & 224) == 192) {\n          str += String.fromCharCode(((u0 & 31) << 6) | u1)\n          continue\n        }\n        var u2 = heapOrArray[idx++] & 63\n        if ((u0 & 240) == 224) {\n          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2\n        } else {\n          u0 =\n            ((u0 & 7) << 18) |\n            (u1 << 12) |\n            (u2 << 6) |\n            (heapOrArray[idx++] & 63)\n        }\n        if (u0 < 65536) {\n          str += String.fromCharCode(u0)\n        } else {\n          var ch = u0 - 65536\n          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023))\n        }\n      }\n      return str\n    }\n    function UTF8ToString(ptr, maxBytesToRead) {\n      return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''\n    }\n    function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {\n      if (!(maxBytesToWrite > 0)) return 0\n      var startIdx = outIdx\n      var endIdx = outIdx + maxBytesToWrite - 1\n      for (var i = 0; i < str.length; ++i) {\n        var u = str.charCodeAt(i)\n        if (u >= 55296 && u <= 57343) {\n          var u1 = str.charCodeAt(++i)\n          u = (65536 + ((u & 1023) << 10)) | (u1 & 1023)\n        }\n        if (u <= 127) {\n          if (outIdx >= endIdx) break\n          heap[outIdx++] = u\n        } else if (u <= 2047) {\n          if (outIdx + 1 >= endIdx) break\n          heap[outIdx++] = 192 | (u >> 6)\n          heap[outIdx++] = 128 | (u & 63)\n        } else if (u <= 65535) {\n          if (outIdx + 2 >= endIdx) break\n          heap[outIdx++] = 224 | (u >> 12)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        } else {\n          if (outIdx + 3 >= endIdx) break\n          heap[outIdx++] = 240 | (u >> 18)\n          heap[outIdx++] = 128 | ((u >> 12) & 63)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        }\n      }\n      heap[outIdx] = 0\n      return outIdx - startIdx\n    }\n    function stringToUTF8(str, outPtr, maxBytesToWrite) {\n      return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite)\n    }\n    function lengthBytesUTF8(str) {\n      var len = 0\n      for (var i = 0; i < str.length; ++i) {\n        var c = str.charCodeAt(i)\n        if (c <= 127) {\n          len++\n        } else if (c <= 2047) {\n          len += 2\n        } else if (c >= 55296 && c <= 57343) {\n          len += 4\n          ++i\n        } else {\n          len += 3\n        }\n      }\n      return len\n    }\n    var buffer,\n      HEAP8,\n      HEAPU8,\n      HEAP16,\n      HEAPU16,\n      HEAP32,\n      HEAPU32,\n      HEAPF32,\n      HEAPF64\n    function updateGlobalBufferAndViews(buf) {\n      buffer = buf\n      Module['HEAP8'] = HEAP8 = new Int8Array(buf)\n      Module['HEAP16'] = HEAP16 = new Int16Array(buf)\n      Module['HEAP32'] = HEAP32 = new Int32Array(buf)\n      Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf)\n      Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf)\n      Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf)\n      Module['HEAPF32'] = HEAPF32 = new Float32Array(buf)\n      Module['HEAPF64'] = HEAPF64 = new Float64Array(buf)\n    }\n    var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216\n    var wasmTable\n    var __ATPRERUN__ = []\n    var __ATINIT__ = []\n    var __ATMAIN__ = []\n    var __ATPOSTRUN__ = []\n    var runtimeInitialized = false\n    function keepRuntimeAlive() {\n      return noExitRuntime\n    }\n    function preRun() {\n      if (Module['preRun']) {\n        if (typeof Module['preRun'] == 'function')\n          Module['preRun'] = [Module['preRun']]\n        while (Module['preRun'].length) {\n          addOnPreRun(Module['preRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPRERUN__)\n    }\n    function initRuntime() {\n      runtimeInitialized = true\n      if (!Module['noFSInit'] && !FS.init.initialized) FS.init()\n      FS.ignorePermissions = false\n      TTY.init()\n      callRuntimeCallbacks(__ATINIT__)\n    }\n    function preMain() {\n      callRuntimeCallbacks(__ATMAIN__)\n    }\n    function postRun() {\n      if (Module['postRun']) {\n        if (typeof Module['postRun'] == 'function')\n          Module['postRun'] = [Module['postRun']]\n        while (Module['postRun'].length) {\n          addOnPostRun(Module['postRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPOSTRUN__)\n    }\n    function addOnPreRun(cb) {\n      __ATPRERUN__.unshift(cb)\n    }\n    function addOnInit(cb) {\n      __ATINIT__.unshift(cb)\n    }\n    function addOnPostRun(cb) {\n      __ATPOSTRUN__.unshift(cb)\n    }\n    var runDependencies = 0\n    var runDependencyWatcher = null\n    var dependenciesFulfilled = null\n    function getUniqueRunDependency(id) {\n      return id\n    }\n    function addRunDependency(id) {\n      runDependencies++\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n    }\n    function removeRunDependency(id) {\n      runDependencies--\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n      if (runDependencies == 0) {\n        if (runDependencyWatcher !== null) {\n          clearInterval(runDependencyWatcher)\n          runDependencyWatcher = null\n        }\n        if (dependenciesFulfilled) {\n          var callback = dependenciesFulfilled\n          dependenciesFulfilled = null\n          callback()\n        }\n      }\n    }\n    function abort(what) {\n      if (Module['onAbort']) {\n        Module['onAbort'](what)\n      }\n      what = 'Aborted(' + what + ')'\n      err(what)\n      ABORT = true\n      EXITSTATUS = 1\n      what += '. Build with -sASSERTIONS for more info.'\n      var e = new WebAssembly.RuntimeError(what)\n      readyPromiseReject(e)\n      throw e\n    }\n    var dataURIPrefix = 'data:application/octet-stream;base64,'\n    function isDataURI(filename) {\n      return filename.startsWith(dataURIPrefix)\n    }\n    function isFileURI(filename) {\n      return filename.startsWith('file://')\n    }\n    var wasmBinaryFile\n    wasmBinaryFile = 'DownsampleLabelImage.umd.wasm'\n    if (!isDataURI(wasmBinaryFile)) {\n      wasmBinaryFile = locateFile(wasmBinaryFile)\n    }\n    function getBinary(file) {\n      try {\n        if (file == wasmBinaryFile && wasmBinary) {\n          return new Uint8Array(wasmBinary)\n        }\n        if (readBinary) {\n          return readBinary(file)\n        }\n        throw 'both async and sync fetching of the wasm failed'\n      } catch (err) {\n        abort(err)\n      }\n    }\n    function getBinaryPromise() {\n      if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {\n        if (typeof fetch == 'function' && !isFileURI(wasmBinaryFile)) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' })\n            .then(function(response) {\n              if (!response['ok']) {\n                throw \"failed to load wasm binary file at '\" +\n                  wasmBinaryFile +\n                  \"'\"\n              }\n              return response['arrayBuffer']()\n            })\n            .catch(function() {\n              return getBinary(wasmBinaryFile)\n            })\n        } else {\n          if (readAsync) {\n            return new Promise(function(resolve, reject) {\n              readAsync(\n                wasmBinaryFile,\n                function(response) {\n                  resolve(new Uint8Array(response))\n                },\n                reject\n              )\n            })\n          }\n        }\n      }\n      return Promise.resolve().then(function() {\n        return getBinary(wasmBinaryFile)\n      })\n    }\n    function createWasm() {\n      var info = { a: asmLibraryArg }\n      function receiveInstance(instance, module) {\n        var exports = instance.exports\n        Module['asm'] = exports\n        wasmMemory = Module['asm']['s']\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        wasmTable = Module['asm']['D']\n        addOnInit(Module['asm']['t'])\n        removeRunDependency('wasm-instantiate')\n      }\n      addRunDependency('wasm-instantiate')\n      function receiveInstantiationResult(result) {\n        receiveInstance(result['instance'])\n      }\n      function instantiateArrayBuffer(receiver) {\n        return getBinaryPromise()\n          .then(function(binary) {\n            return WebAssembly.instantiate(binary, info)\n          })\n          .then(function(instance) {\n            return instance\n          })\n          .then(receiver, function(reason) {\n            err('failed to asynchronously prepare wasm: ' + reason)\n            abort(reason)\n          })\n      }\n      function instantiateAsync() {\n        if (\n          !wasmBinary &&\n          typeof WebAssembly.instantiateStreaming == 'function' &&\n          !isDataURI(wasmBinaryFile) &&\n          !isFileURI(wasmBinaryFile) &&\n          !ENVIRONMENT_IS_NODE &&\n          typeof fetch == 'function'\n        ) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(\n            function(response) {\n              var result = WebAssembly.instantiateStreaming(response, info)\n              return result.then(receiveInstantiationResult, function(reason) {\n                err('wasm streaming compile failed: ' + reason)\n                err('falling back to ArrayBuffer instantiation')\n                return instantiateArrayBuffer(receiveInstantiationResult)\n              })\n            }\n          )\n        } else {\n          return instantiateArrayBuffer(receiveInstantiationResult)\n        }\n      }\n      if (Module['instantiateWasm']) {\n        try {\n          var exports = Module['instantiateWasm'](info, receiveInstance)\n          return exports\n        } catch (e) {\n          err('Module.instantiateWasm callback failed with error: ' + e)\n          readyPromiseReject(e)\n        }\n      }\n      instantiateAsync().catch(readyPromiseReject)\n      return {}\n    }\n    var tempDouble\n    var tempI64\n    function ExitStatus(status) {\n      this.name = 'ExitStatus'\n      this.message = 'Program terminated with exit(' + status + ')'\n      this.status = status\n    }\n    function callRuntimeCallbacks(callbacks) {\n      while (callbacks.length > 0) {\n        callbacks.shift()(Module)\n      }\n    }\n    function ExceptionInfo(excPtr) {\n      this.excPtr = excPtr\n      this.ptr = excPtr - 24\n      this.set_type = function(type) {\n        HEAPU32[(this.ptr + 4) >> 2] = type\n      }\n      this.get_type = function() {\n        return HEAPU32[(this.ptr + 4) >> 2]\n      }\n      this.set_destructor = function(destructor) {\n        HEAPU32[(this.ptr + 8) >> 2] = destructor\n      }\n      this.get_destructor = function() {\n        return HEAPU32[(this.ptr + 8) >> 2]\n      }\n      this.set_refcount = function(refcount) {\n        HEAP32[this.ptr >> 2] = refcount\n      }\n      this.set_caught = function(caught) {\n        caught = caught ? 1 : 0\n        HEAP8[(this.ptr + 12) >> 0] = caught\n      }\n      this.get_caught = function() {\n        return HEAP8[(this.ptr + 12) >> 0] != 0\n      }\n      this.set_rethrown = function(rethrown) {\n        rethrown = rethrown ? 1 : 0\n        HEAP8[(this.ptr + 13) >> 0] = rethrown\n      }\n      this.get_rethrown = function() {\n        return HEAP8[(this.ptr + 13) >> 0] != 0\n      }\n      this.init = function(type, destructor) {\n        this.set_adjusted_ptr(0)\n        this.set_type(type)\n        this.set_destructor(destructor)\n        this.set_refcount(0)\n        this.set_caught(false)\n        this.set_rethrown(false)\n      }\n      this.add_ref = function() {\n        var value = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = value + 1\n      }\n      this.release_ref = function() {\n        var prev = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = prev - 1\n        return prev === 1\n      }\n      this.set_adjusted_ptr = function(adjustedPtr) {\n        HEAPU32[(this.ptr + 16) >> 2] = adjustedPtr\n      }\n      this.get_adjusted_ptr = function() {\n        return HEAPU32[(this.ptr + 16) >> 2]\n      }\n      this.get_exception_ptr = function() {\n        var isPointer = ___cxa_is_pointer_type(this.get_type())\n        if (isPointer) {\n          return HEAPU32[this.excPtr >> 2]\n        }\n        var adjusted = this.get_adjusted_ptr()\n        if (adjusted !== 0) return adjusted\n        return this.excPtr\n      }\n    }\n    var exceptionLast = 0\n    var uncaughtExceptionCount = 0\n    function ___cxa_throw(ptr, type, destructor) {\n      var info = new ExceptionInfo(ptr)\n      info.init(type, destructor)\n      exceptionLast = ptr\n      uncaughtExceptionCount++\n      throw ptr\n    }\n    function setErrNo(value) {\n      HEAP32[___errno_location() >> 2] = value\n      return value\n    }\n    var PATH = {\n      isAbs: path => path.charAt(0) === '/',\n      splitPath: filename => {\n        var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/\n        return splitPathRe.exec(filename).slice(1)\n      },\n      normalizeArray: (parts, allowAboveRoot) => {\n        var up = 0\n        for (var i = parts.length - 1; i >= 0; i--) {\n          var last = parts[i]\n          if (last === '.') {\n            parts.splice(i, 1)\n          } else if (last === '..') {\n            parts.splice(i, 1)\n            up++\n          } else if (up) {\n            parts.splice(i, 1)\n            up--\n          }\n        }\n        if (allowAboveRoot) {\n          for (; up; up--) {\n            parts.unshift('..')\n          }\n        }\n        return parts\n      },\n      normalize: path => {\n        var isAbsolute = PATH.isAbs(path),\n          trailingSlash = path.substr(-1) === '/'\n        path = PATH.normalizeArray(\n          path.split('/').filter(p => !!p),\n          !isAbsolute\n        ).join('/')\n        if (!path && !isAbsolute) {\n          path = '.'\n        }\n        if (path && trailingSlash) {\n          path += '/'\n        }\n        return (isAbsolute ? '/' : '') + path\n      },\n      dirname: path => {\n        var result = PATH.splitPath(path),\n          root = result[0],\n          dir = result[1]\n        if (!root && !dir) {\n          return '.'\n        }\n        if (dir) {\n          dir = dir.substr(0, dir.length - 1)\n        }\n        return root + dir\n      },\n      basename: path => {\n        if (path === '/') return '/'\n        path = PATH.normalize(path)\n        path = path.replace(/\\/$/, '')\n        var lastSlash = path.lastIndexOf('/')\n        if (lastSlash === -1) return path\n        return path.substr(lastSlash + 1)\n      },\n      join: function() {\n        var paths = Array.prototype.slice.call(arguments)\n        return PATH.normalize(paths.join('/'))\n      },\n      join2: (l, r) => {\n        return PATH.normalize(l + '/' + r)\n      },\n    }\n    function getRandomDevice() {\n      if (\n        typeof crypto == 'object' &&\n        typeof crypto['getRandomValues'] == 'function'\n      ) {\n        var randomBuffer = new Uint8Array(1)\n        return () => {\n          crypto.getRandomValues(randomBuffer)\n          return randomBuffer[0]\n        }\n      } else if (ENVIRONMENT_IS_NODE) {\n        try {\n          var crypto_module = require('crypto')\n          return () => crypto_module['randomBytes'](1)[0]\n        } catch (e) {}\n      }\n      return () => abort('randomDevice')\n    }\n    var PATH_FS = {\n      resolve: function() {\n        var resolvedPath = '',\n          resolvedAbsolute = false\n        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n          var path = i >= 0 ? arguments[i] : FS.cwd()\n          if (typeof path != 'string') {\n            throw new TypeError('Arguments to path.resolve must be strings')\n          } else if (!path) {\n            return ''\n          }\n          resolvedPath = path + '/' + resolvedPath\n          resolvedAbsolute = PATH.isAbs(path)\n        }\n        resolvedPath = PATH.normalizeArray(\n          resolvedPath.split('/').filter(p => !!p),\n          !resolvedAbsolute\n        ).join('/')\n        return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'\n      },\n      relative: (from, to) => {\n        from = PATH_FS.resolve(from).substr(1)\n        to = PATH_FS.resolve(to).substr(1)\n        function trim(arr) {\n          var start = 0\n          for (; start < arr.length; start++) {\n            if (arr[start] !== '') break\n          }\n          var end = arr.length - 1\n          for (; end >= 0; end--) {\n            if (arr[end] !== '') break\n          }\n          if (start > end) return []\n          return arr.slice(start, end - start + 1)\n        }\n        var fromParts = trim(from.split('/'))\n        var toParts = trim(to.split('/'))\n        var length = Math.min(fromParts.length, toParts.length)\n        var samePartsLength = length\n        for (var i = 0; i < length; i++) {\n          if (fromParts[i] !== toParts[i]) {\n            samePartsLength = i\n            break\n          }\n        }\n        var outputParts = []\n        for (var i = samePartsLength; i < fromParts.length; i++) {\n          outputParts.push('..')\n        }\n        outputParts = outputParts.concat(toParts.slice(samePartsLength))\n        return outputParts.join('/')\n      },\n    }\n    function intArrayFromString(stringy, dontAddNull, length) {\n      var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1\n      var u8array = new Array(len)\n      var numBytesWritten = stringToUTF8Array(\n        stringy,\n        u8array,\n        0,\n        u8array.length\n      )\n      if (dontAddNull) u8array.length = numBytesWritten\n      return u8array\n    }\n    var TTY = {\n      ttys: [],\n      init: function() {},\n      shutdown: function() {},\n      register: function(dev, ops) {\n        TTY.ttys[dev] = { input: [], output: [], ops: ops }\n        FS.registerDevice(dev, TTY.stream_ops)\n      },\n      stream_ops: {\n        open: function(stream) {\n          var tty = TTY.ttys[stream.node.rdev]\n          if (!tty) {\n            throw new FS.ErrnoError(43)\n          }\n          stream.tty = tty\n          stream.seekable = false\n        },\n        close: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        fsync: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        read: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.get_char) {\n            throw new FS.ErrnoError(60)\n          }\n          var bytesRead = 0\n          for (var i = 0; i < length; i++) {\n            var result\n            try {\n              result = stream.tty.ops.get_char(stream.tty)\n            } catch (e) {\n              throw new FS.ErrnoError(29)\n            }\n            if (result === undefined && bytesRead === 0) {\n              throw new FS.ErrnoError(6)\n            }\n            if (result === null || result === undefined) break\n            bytesRead++\n            buffer[offset + i] = result\n          }\n          if (bytesRead) {\n            stream.node.timestamp = Date.now()\n          }\n          return bytesRead\n        },\n        write: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.put_char) {\n            throw new FS.ErrnoError(60)\n          }\n          try {\n            for (var i = 0; i < length; i++) {\n              stream.tty.ops.put_char(stream.tty, buffer[offset + i])\n            }\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n          if (length) {\n            stream.node.timestamp = Date.now()\n          }\n          return i\n        },\n      },\n      default_tty_ops: {\n        get_char: function(tty) {\n          if (!tty.input.length) {\n            var result = null\n            if (ENVIRONMENT_IS_NODE) {\n              var BUFSIZE = 256\n              var buf = Buffer.alloc(BUFSIZE)\n              var bytesRead = 0\n              try {\n                bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, -1)\n              } catch (e) {\n                if (e.toString().includes('EOF')) bytesRead = 0\n                else throw e\n              }\n              if (bytesRead > 0) {\n                result = buf.slice(0, bytesRead).toString('utf-8')\n              } else {\n                result = null\n              }\n            } else if (\n              typeof window != 'undefined' &&\n              typeof window.prompt == 'function'\n            ) {\n              result = window.prompt('Input: ')\n              if (result !== null) {\n                result += '\\n'\n              }\n            } else if (typeof readline == 'function') {\n              result = readline()\n              if (result !== null) {\n                result += '\\n'\n              }\n            }\n            if (!result) {\n              return null\n            }\n            tty.input = intArrayFromString(result, true)\n          }\n          return tty.input.shift()\n        },\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n      default_tty1_ops: {\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n    }\n    function mmapAlloc(size) {\n      abort()\n    }\n    var MEMFS = {\n      ops_table: null,\n      mount: function(mount) {\n        return MEMFS.createNode(null, '/', 16384 | 511, 0)\n      },\n      createNode: function(parent, name, mode, dev) {\n        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n          throw new FS.ErrnoError(63)\n        }\n        if (!MEMFS.ops_table) {\n          MEMFS.ops_table = {\n            dir: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                lookup: MEMFS.node_ops.lookup,\n                mknod: MEMFS.node_ops.mknod,\n                rename: MEMFS.node_ops.rename,\n                unlink: MEMFS.node_ops.unlink,\n                rmdir: MEMFS.node_ops.rmdir,\n                readdir: MEMFS.node_ops.readdir,\n                symlink: MEMFS.node_ops.symlink,\n              },\n              stream: { llseek: MEMFS.stream_ops.llseek },\n            },\n            file: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: {\n                llseek: MEMFS.stream_ops.llseek,\n                read: MEMFS.stream_ops.read,\n                write: MEMFS.stream_ops.write,\n                allocate: MEMFS.stream_ops.allocate,\n                mmap: MEMFS.stream_ops.mmap,\n                msync: MEMFS.stream_ops.msync,\n              },\n            },\n            link: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                readlink: MEMFS.node_ops.readlink,\n              },\n              stream: {},\n            },\n            chrdev: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: FS.chrdev_stream_ops,\n            },\n          }\n        }\n        var node = FS.createNode(parent, name, mode, dev)\n        if (FS.isDir(node.mode)) {\n          node.node_ops = MEMFS.ops_table.dir.node\n          node.stream_ops = MEMFS.ops_table.dir.stream\n          node.contents = {}\n        } else if (FS.isFile(node.mode)) {\n          node.node_ops = MEMFS.ops_table.file.node\n          node.stream_ops = MEMFS.ops_table.file.stream\n          node.usedBytes = 0\n          node.contents = null\n        } else if (FS.isLink(node.mode)) {\n          node.node_ops = MEMFS.ops_table.link.node\n          node.stream_ops = MEMFS.ops_table.link.stream\n        } else if (FS.isChrdev(node.mode)) {\n          node.node_ops = MEMFS.ops_table.chrdev.node\n          node.stream_ops = MEMFS.ops_table.chrdev.stream\n        }\n        node.timestamp = Date.now()\n        if (parent) {\n          parent.contents[name] = node\n          parent.timestamp = node.timestamp\n        }\n        return node\n      },\n      getFileDataAsTypedArray: function(node) {\n        if (!node.contents) return new Uint8Array(0)\n        if (node.contents.subarray)\n          return node.contents.subarray(0, node.usedBytes)\n        return new Uint8Array(node.contents)\n      },\n      expandFileStorage: function(node, newCapacity) {\n        var prevCapacity = node.contents ? node.contents.length : 0\n        if (prevCapacity >= newCapacity) return\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024\n        newCapacity = Math.max(\n          newCapacity,\n          (prevCapacity *\n            (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>>\n            0\n        )\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256)\n        var oldContents = node.contents\n        node.contents = new Uint8Array(newCapacity)\n        if (node.usedBytes > 0)\n          node.contents.set(oldContents.subarray(0, node.usedBytes), 0)\n      },\n      resizeFileStorage: function(node, newSize) {\n        if (node.usedBytes == newSize) return\n        if (newSize == 0) {\n          node.contents = null\n          node.usedBytes = 0\n        } else {\n          var oldContents = node.contents\n          node.contents = new Uint8Array(newSize)\n          if (oldContents) {\n            node.contents.set(\n              oldContents.subarray(0, Math.min(newSize, node.usedBytes))\n            )\n          }\n          node.usedBytes = newSize\n        }\n      },\n      node_ops: {\n        getattr: function(node) {\n          var attr = {}\n          attr.dev = FS.isChrdev(node.mode) ? node.id : 1\n          attr.ino = node.id\n          attr.mode = node.mode\n          attr.nlink = 1\n          attr.uid = 0\n          attr.gid = 0\n          attr.rdev = node.rdev\n          if (FS.isDir(node.mode)) {\n            attr.size = 4096\n          } else if (FS.isFile(node.mode)) {\n            attr.size = node.usedBytes\n          } else if (FS.isLink(node.mode)) {\n            attr.size = node.link.length\n          } else {\n            attr.size = 0\n          }\n          attr.atime = new Date(node.timestamp)\n          attr.mtime = new Date(node.timestamp)\n          attr.ctime = new Date(node.timestamp)\n          attr.blksize = 4096\n          attr.blocks = Math.ceil(attr.size / attr.blksize)\n          return attr\n        },\n        setattr: function(node, attr) {\n          if (attr.mode !== undefined) {\n            node.mode = attr.mode\n          }\n          if (attr.timestamp !== undefined) {\n            node.timestamp = attr.timestamp\n          }\n          if (attr.size !== undefined) {\n            MEMFS.resizeFileStorage(node, attr.size)\n          }\n        },\n        lookup: function(parent, name) {\n          throw FS.genericErrors[44]\n        },\n        mknod: function(parent, name, mode, dev) {\n          return MEMFS.createNode(parent, name, mode, dev)\n        },\n        rename: function(old_node, new_dir, new_name) {\n          if (FS.isDir(old_node.mode)) {\n            var new_node\n            try {\n              new_node = FS.lookupNode(new_dir, new_name)\n            } catch (e) {}\n            if (new_node) {\n              for (var i in new_node.contents) {\n                throw new FS.ErrnoError(55)\n              }\n            }\n          }\n          delete old_node.parent.contents[old_node.name]\n          old_node.parent.timestamp = Date.now()\n          old_node.name = new_name\n          new_dir.contents[new_name] = old_node\n          new_dir.timestamp = old_node.parent.timestamp\n          old_node.parent = new_dir\n        },\n        unlink: function(parent, name) {\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        rmdir: function(parent, name) {\n          var node = FS.lookupNode(parent, name)\n          for (var i in node.contents) {\n            throw new FS.ErrnoError(55)\n          }\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        readdir: function(node) {\n          var entries = ['.', '..']\n          for (var key in node.contents) {\n            if (!node.contents.hasOwnProperty(key)) {\n              continue\n            }\n            entries.push(key)\n          }\n          return entries\n        },\n        symlink: function(parent, newname, oldpath) {\n          var node = MEMFS.createNode(parent, newname, 511 | 40960, 0)\n          node.link = oldpath\n          return node\n        },\n        readlink: function(node) {\n          if (!FS.isLink(node.mode)) {\n            throw new FS.ErrnoError(28)\n          }\n          return node.link\n        },\n      },\n      stream_ops: {\n        read: function(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= stream.node.usedBytes) return 0\n          var size = Math.min(stream.node.usedBytes - position, length)\n          if (size > 8 && contents.subarray) {\n            buffer.set(contents.subarray(position, position + size), offset)\n          } else {\n            for (var i = 0; i < size; i++)\n              buffer[offset + i] = contents[position + i]\n          }\n          return size\n        },\n        write: function(stream, buffer, offset, length, position, canOwn) {\n          if (buffer.buffer === HEAP8.buffer) {\n            canOwn = false\n          }\n          if (!length) return 0\n          var node = stream.node\n          node.timestamp = Date.now()\n          if (buffer.subarray && (!node.contents || node.contents.subarray)) {\n            if (canOwn) {\n              node.contents = buffer.subarray(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (node.usedBytes === 0 && position === 0) {\n              node.contents = buffer.slice(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (position + length <= node.usedBytes) {\n              node.contents.set(\n                buffer.subarray(offset, offset + length),\n                position\n              )\n              return length\n            }\n          }\n          MEMFS.expandFileStorage(node, position + length)\n          if (node.contents.subarray && buffer.subarray) {\n            node.contents.set(\n              buffer.subarray(offset, offset + length),\n              position\n            )\n          } else {\n            for (var i = 0; i < length; i++) {\n              node.contents[position + i] = buffer[offset + i]\n            }\n          }\n          node.usedBytes = Math.max(node.usedBytes, position + length)\n          return length\n        },\n        llseek: function(stream, offset, whence) {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              position += stream.node.usedBytes\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        allocate: function(stream, offset, length) {\n          MEMFS.expandFileStorage(stream.node, offset + length)\n          stream.node.usedBytes = Math.max(\n            stream.node.usedBytes,\n            offset + length\n          )\n        },\n        mmap: function(stream, length, position, prot, flags) {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr\n          var allocated\n          var contents = stream.node.contents\n          if (!(flags & 2) && contents.buffer === buffer) {\n            allocated = false\n            ptr = contents.byteOffset\n          } else {\n            if (position > 0 || position + length < contents.length) {\n              if (contents.subarray) {\n                contents = contents.subarray(position, position + length)\n              } else {\n                contents = Array.prototype.slice.call(\n                  contents,\n                  position,\n                  position + length\n                )\n              }\n            }\n            allocated = true\n            ptr = mmapAlloc(length)\n            if (!ptr) {\n              throw new FS.ErrnoError(48)\n            }\n            HEAP8.set(contents, ptr)\n          }\n          return { ptr: ptr, allocated: allocated }\n        },\n        msync: function(stream, buffer, offset, length, mmapFlags) {\n          MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    function asyncLoad(url, onload, onerror, noRunDep) {\n      var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''\n      readAsync(\n        url,\n        arrayBuffer => {\n          assert(\n            arrayBuffer,\n            'Loading data file \"' + url + '\" failed (no arrayBuffer).'\n          )\n          onload(new Uint8Array(arrayBuffer))\n          if (dep) removeRunDependency(dep)\n        },\n        event => {\n          if (onerror) {\n            onerror()\n          } else {\n            throw 'Loading data file \"' + url + '\" failed.'\n          }\n        }\n      )\n      if (dep) addRunDependency(dep)\n    }\n    var ERRNO_CODES = {}\n    var NODEFS = {\n      isWindows: false,\n      staticInit: () => {\n        NODEFS.isWindows = !!process.platform.match(/^win/)\n        var flags = process['binding']('constants')\n        if (flags['fs']) {\n          flags = flags['fs']\n        }\n        NODEFS.flagsForNodeMap = {\n          1024: flags['O_APPEND'],\n          64: flags['O_CREAT'],\n          128: flags['O_EXCL'],\n          256: flags['O_NOCTTY'],\n          0: flags['O_RDONLY'],\n          2: flags['O_RDWR'],\n          4096: flags['O_SYNC'],\n          512: flags['O_TRUNC'],\n          1: flags['O_WRONLY'],\n          131072: flags['O_NOFOLLOW'],\n        }\n      },\n      convertNodeCode: e => {\n        var code = e.code\n        return ERRNO_CODES[code]\n      },\n      mount: mount => {\n        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0)\n      },\n      createNode: (parent, name, mode, dev) => {\n        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = FS.createNode(parent, name, mode)\n        node.node_ops = NODEFS.node_ops\n        node.stream_ops = NODEFS.stream_ops\n        return node\n      },\n      getMode: path => {\n        var stat\n        try {\n          stat = fs.lstatSync(path)\n          if (NODEFS.isWindows) {\n            stat.mode = stat.mode | ((stat.mode & 292) >> 2)\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n        }\n        return stat.mode\n      },\n      realPath: node => {\n        var parts = []\n        while (node.parent !== node) {\n          parts.push(node.name)\n          node = node.parent\n        }\n        parts.push(node.mount.opts.root)\n        parts.reverse()\n        return PATH.join.apply(null, parts)\n      },\n      flagsForNode: flags => {\n        flags &= ~2097152\n        flags &= ~2048\n        flags &= ~32768\n        flags &= ~524288\n        flags &= ~65536\n        var newFlags = 0\n        for (var k in NODEFS.flagsForNodeMap) {\n          if (flags & k) {\n            newFlags |= NODEFS.flagsForNodeMap[k]\n            flags ^= k\n          }\n        }\n        if (flags) {\n          throw new FS.ErrnoError(28)\n        }\n        return newFlags\n      },\n      node_ops: {\n        getattr: node => {\n          var path = NODEFS.realPath(node)\n          var stat\n          try {\n            stat = fs.lstatSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          if (NODEFS.isWindows && !stat.blksize) {\n            stat.blksize = 4096\n          }\n          if (NODEFS.isWindows && !stat.blocks) {\n            stat.blocks = ((stat.size + stat.blksize - 1) / stat.blksize) | 0\n          }\n          return {\n            dev: stat.dev,\n            ino: stat.ino,\n            mode: stat.mode,\n            nlink: stat.nlink,\n            uid: stat.uid,\n            gid: stat.gid,\n            rdev: stat.rdev,\n            size: stat.size,\n            atime: stat.atime,\n            mtime: stat.mtime,\n            ctime: stat.ctime,\n            blksize: stat.blksize,\n            blocks: stat.blocks,\n          }\n        },\n        setattr: (node, attr) => {\n          var path = NODEFS.realPath(node)\n          try {\n            if (attr.mode !== undefined) {\n              fs.chmodSync(path, attr.mode)\n              node.mode = attr.mode\n            }\n            if (attr.timestamp !== undefined) {\n              var date = new Date(attr.timestamp)\n              fs.utimesSync(path, date, date)\n            }\n            if (attr.size !== undefined) {\n              fs.truncateSync(path, attr.size)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        lookup: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          var mode = NODEFS.getMode(path)\n          return NODEFS.createNode(parent, name, mode)\n        },\n        mknod: (parent, name, mode, dev) => {\n          var node = NODEFS.createNode(parent, name, mode, dev)\n          var path = NODEFS.realPath(node)\n          try {\n            if (FS.isDir(node.mode)) {\n              fs.mkdirSync(path, node.mode)\n            } else {\n              fs.writeFileSync(path, '', { mode: node.mode })\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          return node\n        },\n        rename: (oldNode, newDir, newName) => {\n          var oldPath = NODEFS.realPath(oldNode)\n          var newPath = PATH.join2(NODEFS.realPath(newDir), newName)\n          try {\n            fs.renameSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          oldNode.name = newName\n        },\n        unlink: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.unlinkSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        rmdir: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.rmdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readdir: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            return fs.readdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        symlink: (parent, newName, oldPath) => {\n          var newPath = PATH.join2(NODEFS.realPath(parent), newName)\n          try {\n            fs.symlinkSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readlink: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            path = fs.readlinkSync(path)\n            path = nodePath.relative(\n              nodePath.resolve(node.mount.opts.root),\n              path\n            )\n            return path\n          } catch (e) {\n            if (!e.code) throw e\n            if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28)\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n      },\n      stream_ops: {\n        open: stream => {\n          var path = NODEFS.realPath(stream.node)\n          try {\n            if (FS.isFile(stream.node.mode)) {\n              stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags))\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        close: stream => {\n          try {\n            if (FS.isFile(stream.node.mode) && stream.nfd) {\n              fs.closeSync(stream.nfd)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        read: (stream, buffer, offset, length, position) => {\n          if (length === 0) return 0\n          try {\n            return fs.readSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        write: (stream, buffer, offset, length, position) => {\n          try {\n            return fs.writeSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        llseek: (stream, offset, whence) => {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              try {\n                var stat = fs.fstatSync(stream.nfd)\n                position += stat.size\n              } catch (e) {\n                throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n              }\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        mmap: (stream, length, position, prot, flags) => {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr = mmapAlloc(length)\n          NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        },\n        msync: (stream, buffer, offset, length, mmapFlags) => {\n          NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    var FS = {\n      root: null,\n      mounts: [],\n      devices: {},\n      streams: [],\n      nextInode: 1,\n      nameTable: null,\n      currentPath: '/',\n      initialized: false,\n      ignorePermissions: true,\n      ErrnoError: null,\n      genericErrors: {},\n      filesystems: null,\n      syncFSRequests: 0,\n      lookupPath: (path, opts = {}) => {\n        path = PATH_FS.resolve(path)\n        if (!path) return { path: '', node: null }\n        var defaults = { follow_mount: true, recurse_count: 0 }\n        opts = Object.assign(defaults, opts)\n        if (opts.recurse_count > 8) {\n          throw new FS.ErrnoError(32)\n        }\n        var parts = path.split('/').filter(p => !!p)\n        var current = FS.root\n        var current_path = '/'\n        for (var i = 0; i < parts.length; i++) {\n          var islast = i === parts.length - 1\n          if (islast && opts.parent) {\n            break\n          }\n          current = FS.lookupNode(current, parts[i])\n          current_path = PATH.join2(current_path, parts[i])\n          if (FS.isMountpoint(current)) {\n            if (!islast || (islast && opts.follow_mount)) {\n              current = current.mounted.root\n            }\n          }\n          if (!islast || opts.follow) {\n            var count = 0\n            while (FS.isLink(current.mode)) {\n              var link = FS.readlink(current_path)\n              current_path = PATH_FS.resolve(PATH.dirname(current_path), link)\n              var lookup = FS.lookupPath(current_path, {\n                recurse_count: opts.recurse_count + 1,\n              })\n              current = lookup.node\n              if (count++ > 40) {\n                throw new FS.ErrnoError(32)\n              }\n            }\n          }\n        }\n        return { path: current_path, node: current }\n      },\n      getPath: node => {\n        var path\n        while (true) {\n          if (FS.isRoot(node)) {\n            var mount = node.mount.mountpoint\n            if (!path) return mount\n            return mount[mount.length - 1] !== '/'\n              ? mount + '/' + path\n              : mount + path\n          }\n          path = path ? node.name + '/' + path : node.name\n          node = node.parent\n        }\n      },\n      hashName: (parentid, name) => {\n        var hash = 0\n        for (var i = 0; i < name.length; i++) {\n          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0\n        }\n        return ((parentid + hash) >>> 0) % FS.nameTable.length\n      },\n      hashAddNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        node.name_next = FS.nameTable[hash]\n        FS.nameTable[hash] = node\n      },\n      hashRemoveNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        if (FS.nameTable[hash] === node) {\n          FS.nameTable[hash] = node.name_next\n        } else {\n          var current = FS.nameTable[hash]\n          while (current) {\n            if (current.name_next === node) {\n              current.name_next = node.name_next\n              break\n            }\n            current = current.name_next\n          }\n        }\n      },\n      lookupNode: (parent, name) => {\n        var errCode = FS.mayLookup(parent)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode, parent)\n        }\n        var hash = FS.hashName(parent.id, name)\n        for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n          var nodeName = node.name\n          if (node.parent.id === parent.id && nodeName === name) {\n            return node\n          }\n        }\n        return FS.lookup(parent, name)\n      },\n      createNode: (parent, name, mode, rdev) => {\n        var node = new FS.FSNode(parent, name, mode, rdev)\n        FS.hashAddNode(node)\n        return node\n      },\n      destroyNode: node => {\n        FS.hashRemoveNode(node)\n      },\n      isRoot: node => {\n        return node === node.parent\n      },\n      isMountpoint: node => {\n        return !!node.mounted\n      },\n      isFile: mode => {\n        return (mode & 61440) === 32768\n      },\n      isDir: mode => {\n        return (mode & 61440) === 16384\n      },\n      isLink: mode => {\n        return (mode & 61440) === 40960\n      },\n      isChrdev: mode => {\n        return (mode & 61440) === 8192\n      },\n      isBlkdev: mode => {\n        return (mode & 61440) === 24576\n      },\n      isFIFO: mode => {\n        return (mode & 61440) === 4096\n      },\n      isSocket: mode => {\n        return (mode & 49152) === 49152\n      },\n      flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 },\n      modeStringToFlags: str => {\n        var flags = FS.flagModes[str]\n        if (typeof flags == 'undefined') {\n          throw new Error('Unknown file open mode: ' + str)\n        }\n        return flags\n      },\n      flagsToPermissionString: flag => {\n        var perms = ['r', 'w', 'rw'][flag & 3]\n        if (flag & 512) {\n          perms += 'w'\n        }\n        return perms\n      },\n      nodePermissions: (node, perms) => {\n        if (FS.ignorePermissions) {\n          return 0\n        }\n        if (perms.includes('r') && !(node.mode & 292)) {\n          return 2\n        } else if (perms.includes('w') && !(node.mode & 146)) {\n          return 2\n        } else if (perms.includes('x') && !(node.mode & 73)) {\n          return 2\n        }\n        return 0\n      },\n      mayLookup: dir => {\n        var errCode = FS.nodePermissions(dir, 'x')\n        if (errCode) return errCode\n        if (!dir.node_ops.lookup) return 2\n        return 0\n      },\n      mayCreate: (dir, name) => {\n        try {\n          var node = FS.lookupNode(dir, name)\n          return 20\n        } catch (e) {}\n        return FS.nodePermissions(dir, 'wx')\n      },\n      mayDelete: (dir, name, isdir) => {\n        var node\n        try {\n          node = FS.lookupNode(dir, name)\n        } catch (e) {\n          return e.errno\n        }\n        var errCode = FS.nodePermissions(dir, 'wx')\n        if (errCode) {\n          return errCode\n        }\n        if (isdir) {\n          if (!FS.isDir(node.mode)) {\n            return 54\n          }\n          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n            return 10\n          }\n        } else {\n          if (FS.isDir(node.mode)) {\n            return 31\n          }\n        }\n        return 0\n      },\n      mayOpen: (node, flags) => {\n        if (!node) {\n          return 44\n        }\n        if (FS.isLink(node.mode)) {\n          return 32\n        } else if (FS.isDir(node.mode)) {\n          if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) {\n            return 31\n          }\n        }\n        return FS.nodePermissions(node, FS.flagsToPermissionString(flags))\n      },\n      MAX_OPEN_FDS: 4096,\n      nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => {\n        for (var fd = fd_start; fd <= fd_end; fd++) {\n          if (!FS.streams[fd]) {\n            return fd\n          }\n        }\n        throw new FS.ErrnoError(33)\n      },\n      getStream: fd => FS.streams[fd],\n      createStream: (stream, fd_start, fd_end) => {\n        if (!FS.FSStream) {\n          FS.FSStream = function() {\n            this.shared = {}\n          }\n          FS.FSStream.prototype = {}\n          Object.defineProperties(FS.FSStream.prototype, {\n            object: {\n              get: function() {\n                return this.node\n              },\n              set: function(val) {\n                this.node = val\n              },\n            },\n            isRead: {\n              get: function() {\n                return (this.flags & 2097155) !== 1\n              },\n            },\n            isWrite: {\n              get: function() {\n                return (this.flags & 2097155) !== 0\n              },\n            },\n            isAppend: {\n              get: function() {\n                return this.flags & 1024\n              },\n            },\n            flags: {\n              get: function() {\n                return this.shared.flags\n              },\n              set: function(val) {\n                this.shared.flags = val\n              },\n            },\n            position: {\n              get: function() {\n                return this.shared.position\n              },\n              set: function(val) {\n                this.shared.position = val\n              },\n            },\n          })\n        }\n        stream = Object.assign(new FS.FSStream(), stream)\n        var fd = FS.nextfd(fd_start, fd_end)\n        stream.fd = fd\n        FS.streams[fd] = stream\n        return stream\n      },\n      closeStream: fd => {\n        FS.streams[fd] = null\n      },\n      chrdev_stream_ops: {\n        open: stream => {\n          var device = FS.getDevice(stream.node.rdev)\n          stream.stream_ops = device.stream_ops\n          if (stream.stream_ops.open) {\n            stream.stream_ops.open(stream)\n          }\n        },\n        llseek: () => {\n          throw new FS.ErrnoError(70)\n        },\n      },\n      major: dev => dev >> 8,\n      minor: dev => dev & 255,\n      makedev: (ma, mi) => (ma << 8) | mi,\n      registerDevice: (dev, ops) => {\n        FS.devices[dev] = { stream_ops: ops }\n      },\n      getDevice: dev => FS.devices[dev],\n      getMounts: mount => {\n        var mounts = []\n        var check = [mount]\n        while (check.length) {\n          var m = check.pop()\n          mounts.push(m)\n          check.push.apply(check, m.mounts)\n        }\n        return mounts\n      },\n      syncfs: (populate, callback) => {\n        if (typeof populate == 'function') {\n          callback = populate\n          populate = false\n        }\n        FS.syncFSRequests++\n        if (FS.syncFSRequests > 1) {\n          err(\n            'warning: ' +\n              FS.syncFSRequests +\n              ' FS.syncfs operations in flight at once, probably just doing extra work'\n          )\n        }\n        var mounts = FS.getMounts(FS.root.mount)\n        var completed = 0\n        function doCallback(errCode) {\n          FS.syncFSRequests--\n          return callback(errCode)\n        }\n        function done(errCode) {\n          if (errCode) {\n            if (!done.errored) {\n              done.errored = true\n              return doCallback(errCode)\n            }\n            return\n          }\n          if (++completed >= mounts.length) {\n            doCallback(null)\n          }\n        }\n        mounts.forEach(mount => {\n          if (!mount.type.syncfs) {\n            return done(null)\n          }\n          mount.type.syncfs(mount, populate, done)\n        })\n      },\n      mount: (type, opts, mountpoint) => {\n        var root = mountpoint === '/'\n        var pseudo = !mountpoint\n        var node\n        if (root && FS.root) {\n          throw new FS.ErrnoError(10)\n        } else if (!root && !pseudo) {\n          var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n          mountpoint = lookup.path\n          node = lookup.node\n          if (FS.isMountpoint(node)) {\n            throw new FS.ErrnoError(10)\n          }\n          if (!FS.isDir(node.mode)) {\n            throw new FS.ErrnoError(54)\n          }\n        }\n        var mount = {\n          type: type,\n          opts: opts,\n          mountpoint: mountpoint,\n          mounts: [],\n        }\n        var mountRoot = type.mount(mount)\n        mountRoot.mount = mount\n        mount.root = mountRoot\n        if (root) {\n          FS.root = mountRoot\n        } else if (node) {\n          node.mounted = mount\n          if (node.mount) {\n            node.mount.mounts.push(mount)\n          }\n        }\n        return mountRoot\n      },\n      unmount: mountpoint => {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n        if (!FS.isMountpoint(lookup.node)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = lookup.node\n        var mount = node.mounted\n        var mounts = FS.getMounts(mount)\n        Object.keys(FS.nameTable).forEach(hash => {\n          var current = FS.nameTable[hash]\n          while (current) {\n            var next = current.name_next\n            if (mounts.includes(current.mount)) {\n              FS.destroyNode(current)\n            }\n            current = next\n          }\n        })\n        node.mounted = null\n        var idx = node.mount.mounts.indexOf(mount)\n        node.mount.mounts.splice(idx, 1)\n      },\n      lookup: (parent, name) => {\n        return parent.node_ops.lookup(parent, name)\n      },\n      mknod: (path, mode, dev) => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        if (!name || name === '.' || name === '..') {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.mayCreate(parent, name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.mknod) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.mknod(parent, name, mode, dev)\n      },\n      create: (path, mode) => {\n        mode = mode !== undefined ? mode : 438\n        mode &= 4095\n        mode |= 32768\n        return FS.mknod(path, mode, 0)\n      },\n      mkdir: (path, mode) => {\n        mode = mode !== undefined ? mode : 511\n        mode &= 511 | 512\n        mode |= 16384\n        return FS.mknod(path, mode, 0)\n      },\n      mkdirTree: (path, mode) => {\n        var dirs = path.split('/')\n        var d = ''\n        for (var i = 0; i < dirs.length; ++i) {\n          if (!dirs[i]) continue\n          d += '/' + dirs[i]\n          try {\n            FS.mkdir(d, mode)\n          } catch (e) {\n            if (e.errno != 20) throw e\n          }\n        }\n      },\n      mkdev: (path, mode, dev) => {\n        if (typeof dev == 'undefined') {\n          dev = mode\n          mode = 438\n        }\n        mode |= 8192\n        return FS.mknod(path, mode, dev)\n      },\n      symlink: (oldpath, newpath) => {\n        if (!PATH_FS.resolve(oldpath)) {\n          throw new FS.ErrnoError(44)\n        }\n        var lookup = FS.lookupPath(newpath, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var newname = PATH.basename(newpath)\n        var errCode = FS.mayCreate(parent, newname)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.symlink) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.symlink(parent, newname, oldpath)\n      },\n      rename: (old_path, new_path) => {\n        var old_dirname = PATH.dirname(old_path)\n        var new_dirname = PATH.dirname(new_path)\n        var old_name = PATH.basename(old_path)\n        var new_name = PATH.basename(new_path)\n        var lookup, old_dir, new_dir\n        lookup = FS.lookupPath(old_path, { parent: true })\n        old_dir = lookup.node\n        lookup = FS.lookupPath(new_path, { parent: true })\n        new_dir = lookup.node\n        if (!old_dir || !new_dir) throw new FS.ErrnoError(44)\n        if (old_dir.mount !== new_dir.mount) {\n          throw new FS.ErrnoError(75)\n        }\n        var old_node = FS.lookupNode(old_dir, old_name)\n        var relative = PATH_FS.relative(old_path, new_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(28)\n        }\n        relative = PATH_FS.relative(new_path, old_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(55)\n        }\n        var new_node\n        try {\n          new_node = FS.lookupNode(new_dir, new_name)\n        } catch (e) {}\n        if (old_node === new_node) {\n          return\n        }\n        var isdir = FS.isDir(old_node.mode)\n        var errCode = FS.mayDelete(old_dir, old_name, isdir)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        errCode = new_node\n          ? FS.mayDelete(new_dir, new_name, isdir)\n          : FS.mayCreate(new_dir, new_name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!old_dir.node_ops.rename) {\n          throw new FS.ErrnoError(63)\n        }\n        if (\n          FS.isMountpoint(old_node) ||\n          (new_node && FS.isMountpoint(new_node))\n        ) {\n          throw new FS.ErrnoError(10)\n        }\n        if (new_dir !== old_dir) {\n          errCode = FS.nodePermissions(old_dir, 'w')\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        FS.hashRemoveNode(old_node)\n        try {\n          old_dir.node_ops.rename(old_node, new_dir, new_name)\n        } catch (e) {\n          throw e\n        } finally {\n          FS.hashAddNode(old_node)\n        }\n      },\n      rmdir: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, true)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.rmdir) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.rmdir(parent, name)\n        FS.destroyNode(node)\n      },\n      readdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        if (!node.node_ops.readdir) {\n          throw new FS.ErrnoError(54)\n        }\n        return node.node_ops.readdir(node)\n      },\n      unlink: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, false)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.unlink) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.unlink(parent, name)\n        FS.destroyNode(node)\n      },\n      readlink: path => {\n        var lookup = FS.lookupPath(path)\n        var link = lookup.node\n        if (!link) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!link.node_ops.readlink) {\n          throw new FS.ErrnoError(28)\n        }\n        return PATH_FS.resolve(\n          FS.getPath(link.parent),\n          link.node_ops.readlink(link)\n        )\n      },\n      stat: (path, dontFollow) => {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow })\n        var node = lookup.node\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!node.node_ops.getattr) {\n          throw new FS.ErrnoError(63)\n        }\n        return node.node_ops.getattr(node)\n      },\n      lstat: path => {\n        return FS.stat(path, true)\n      },\n      chmod: (path, mode, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, {\n          mode: (mode & 4095) | (node.mode & ~4095),\n          timestamp: Date.now(),\n        })\n      },\n      lchmod: (path, mode) => {\n        FS.chmod(path, mode, true)\n      },\n      fchmod: (fd, mode) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chmod(stream.node, mode)\n      },\n      chown: (path, uid, gid, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, { timestamp: Date.now() })\n      },\n      lchown: (path, uid, gid) => {\n        FS.chown(path, uid, gid, true)\n      },\n      fchown: (fd, uid, gid) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chown(stream.node, uid, gid)\n      },\n      truncate: (path, len) => {\n        if (len < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: true })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!FS.isFile(node.mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.nodePermissions(node, 'w')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        node.node_ops.setattr(node, { size: len, timestamp: Date.now() })\n      },\n      ftruncate: (fd, len) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(28)\n        }\n        FS.truncate(stream.node, len)\n      },\n      utime: (path, atime, mtime) => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) })\n      },\n      open: (path, flags, mode) => {\n        if (path === '') {\n          throw new FS.ErrnoError(44)\n        }\n        flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags\n        mode = typeof mode == 'undefined' ? 438 : mode\n        if (flags & 64) {\n          mode = (mode & 4095) | 32768\n        } else {\n          mode = 0\n        }\n        var node\n        if (typeof path == 'object') {\n          node = path\n        } else {\n          path = PATH.normalize(path)\n          try {\n            var lookup = FS.lookupPath(path, { follow: !(flags & 131072) })\n            node = lookup.node\n          } catch (e) {}\n        }\n        var created = false\n        if (flags & 64) {\n          if (node) {\n            if (flags & 128) {\n              throw new FS.ErrnoError(20)\n            }\n          } else {\n            node = FS.mknod(path, mode, 0)\n            created = true\n          }\n        }\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (FS.isChrdev(node.mode)) {\n          flags &= ~512\n        }\n        if (flags & 65536 && !FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        if (!created) {\n          var errCode = FS.mayOpen(node, flags)\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        if (flags & 512 && !created) {\n          FS.truncate(node, 0)\n        }\n        flags &= ~(128 | 512 | 131072)\n        var stream = FS.createStream({\n          node: node,\n          path: FS.getPath(node),\n          flags: flags,\n          seekable: true,\n          position: 0,\n          stream_ops: node.stream_ops,\n          ungotten: [],\n          error: false,\n        })\n        if (stream.stream_ops.open) {\n          stream.stream_ops.open(stream)\n        }\n        if (Module['logReadFiles'] && !(flags & 1)) {\n          if (!FS.readFiles) FS.readFiles = {}\n          if (!(path in FS.readFiles)) {\n            FS.readFiles[path] = 1\n          }\n        }\n        return stream\n      },\n      close: stream => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (stream.getdents) stream.getdents = null\n        try {\n          if (stream.stream_ops.close) {\n            stream.stream_ops.close(stream)\n          }\n        } catch (e) {\n          throw e\n        } finally {\n          FS.closeStream(stream.fd)\n        }\n        stream.fd = null\n      },\n      isClosed: stream => {\n        return stream.fd === null\n      },\n      llseek: (stream, offset, whence) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!stream.seekable || !stream.stream_ops.llseek) {\n          throw new FS.ErrnoError(70)\n        }\n        if (whence != 0 && whence != 1 && whence != 2) {\n          throw new FS.ErrnoError(28)\n        }\n        stream.position = stream.stream_ops.llseek(stream, offset, whence)\n        stream.ungotten = []\n        return stream.position\n      },\n      read: (stream, buffer, offset, length, position) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.read) {\n          throw new FS.ErrnoError(28)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesRead = stream.stream_ops.read(\n          stream,\n          buffer,\n          offset,\n          length,\n          position\n        )\n        if (!seeking) stream.position += bytesRead\n        return bytesRead\n      },\n      write: (stream, buffer, offset, length, position, canOwn) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.write) {\n          throw new FS.ErrnoError(28)\n        }\n        if (stream.seekable && stream.flags & 1024) {\n          FS.llseek(stream, 0, 2)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesWritten = stream.stream_ops.write(\n          stream,\n          buffer,\n          offset,\n          length,\n          position,\n          canOwn\n        )\n        if (!seeking) stream.position += bytesWritten\n        return bytesWritten\n      },\n      allocate: (stream, offset, length) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (offset < 0 || length <= 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (!stream.stream_ops.allocate) {\n          throw new FS.ErrnoError(138)\n        }\n        stream.stream_ops.allocate(stream, offset, length)\n      },\n      mmap: (stream, length, position, prot, flags) => {\n        if (\n          (prot & 2) !== 0 &&\n          (flags & 2) === 0 &&\n          (stream.flags & 2097155) !== 2\n        ) {\n          throw new FS.ErrnoError(2)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(2)\n        }\n        if (!stream.stream_ops.mmap) {\n          throw new FS.ErrnoError(43)\n        }\n        return stream.stream_ops.mmap(stream, length, position, prot, flags)\n      },\n      msync: (stream, buffer, offset, length, mmapFlags) => {\n        if (!stream.stream_ops.msync) {\n          return 0\n        }\n        return stream.stream_ops.msync(\n          stream,\n          buffer,\n          offset,\n          length,\n          mmapFlags\n        )\n      },\n      munmap: stream => 0,\n      ioctl: (stream, cmd, arg) => {\n        if (!stream.stream_ops.ioctl) {\n          throw new FS.ErrnoError(59)\n        }\n        return stream.stream_ops.ioctl(stream, cmd, arg)\n      },\n      readFile: (path, opts = {}) => {\n        opts.flags = opts.flags || 0\n        opts.encoding = opts.encoding || 'binary'\n        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {\n          throw new Error('Invalid encoding type \"' + opts.encoding + '\"')\n        }\n        var ret\n        var stream = FS.open(path, opts.flags)\n        var stat = FS.stat(path)\n        var length = stat.size\n        var buf = new Uint8Array(length)\n        FS.read(stream, buf, 0, length, 0)\n        if (opts.encoding === 'utf8') {\n          ret = UTF8ArrayToString(buf, 0)\n        } else if (opts.encoding === 'binary') {\n          ret = buf\n        }\n        FS.close(stream)\n        return ret\n      },\n      writeFile: (path, data, opts = {}) => {\n        opts.flags = opts.flags || 577\n        var stream = FS.open(path, opts.flags, opts.mode)\n        if (typeof data == 'string') {\n          var buf = new Uint8Array(lengthBytesUTF8(data) + 1)\n          var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length)\n          FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn)\n        } else if (ArrayBuffer.isView(data)) {\n          FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn)\n        } else {\n          throw new Error('Unsupported data type')\n        }\n        FS.close(stream)\n      },\n      cwd: () => FS.currentPath,\n      chdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        if (lookup.node === null) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!FS.isDir(lookup.node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        var errCode = FS.nodePermissions(lookup.node, 'x')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        FS.currentPath = lookup.path\n      },\n      createDefaultDirectories: () => {\n        FS.mkdir('/tmp')\n        FS.mkdir('/home')\n        FS.mkdir('/home/web_user')\n      },\n      createDefaultDevices: () => {\n        FS.mkdir('/dev')\n        FS.registerDevice(FS.makedev(1, 3), {\n          read: () => 0,\n          write: (stream, buffer, offset, length, pos) => length,\n        })\n        FS.mkdev('/dev/null', FS.makedev(1, 3))\n        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops)\n        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops)\n        FS.mkdev('/dev/tty', FS.makedev(5, 0))\n        FS.mkdev('/dev/tty1', FS.makedev(6, 0))\n        var random_device = getRandomDevice()\n        FS.createDevice('/dev', 'random', random_device)\n        FS.createDevice('/dev', 'urandom', random_device)\n        FS.mkdir('/dev/shm')\n        FS.mkdir('/dev/shm/tmp')\n      },\n      createSpecialDirectories: () => {\n        FS.mkdir('/proc')\n        var proc_self = FS.mkdir('/proc/self')\n        FS.mkdir('/proc/self/fd')\n        FS.mount(\n          {\n            mount: () => {\n              var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73)\n              node.node_ops = {\n                lookup: (parent, name) => {\n                  var fd = +name\n                  var stream = FS.getStream(fd)\n                  if (!stream) throw new FS.ErrnoError(8)\n                  var ret = {\n                    parent: null,\n                    mount: { mountpoint: 'fake' },\n                    node_ops: { readlink: () => stream.path },\n                  }\n                  ret.parent = ret\n                  return ret\n                },\n              }\n              return node\n            },\n          },\n          {},\n          '/proc/self/fd'\n        )\n      },\n      createStandardStreams: () => {\n        if (Module['stdin']) {\n          FS.createDevice('/dev', 'stdin', Module['stdin'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdin')\n        }\n        if (Module['stdout']) {\n          FS.createDevice('/dev', 'stdout', null, Module['stdout'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdout')\n        }\n        if (Module['stderr']) {\n          FS.createDevice('/dev', 'stderr', null, Module['stderr'])\n        } else {\n          FS.symlink('/dev/tty1', '/dev/stderr')\n        }\n        var stdin = FS.open('/dev/stdin', 0)\n        var stdout = FS.open('/dev/stdout', 1)\n        var stderr = FS.open('/dev/stderr', 1)\n      },\n      ensureErrnoError: () => {\n        if (FS.ErrnoError) return\n        FS.ErrnoError = function ErrnoError(errno, node) {\n          this.node = node\n          this.setErrno = function(errno) {\n            this.errno = errno\n          }\n          this.setErrno(errno)\n          this.message = 'FS error'\n        }\n        FS.ErrnoError.prototype = new Error()\n        FS.ErrnoError.prototype.constructor = FS.ErrnoError\n        ;[44].forEach(code => {\n          FS.genericErrors[code] = new FS.ErrnoError(code)\n          FS.genericErrors[code].stack = '<generic error, no stack>'\n        })\n      },\n      staticInit: () => {\n        FS.ensureErrnoError()\n        FS.nameTable = new Array(4096)\n        FS.mount(MEMFS, {}, '/')\n        FS.createDefaultDirectories()\n        FS.createDefaultDevices()\n        FS.createSpecialDirectories()\n        FS.filesystems = { MEMFS: MEMFS, NODEFS: NODEFS }\n      },\n      init: (input, output, error) => {\n        FS.init.initialized = true\n        FS.ensureErrnoError()\n        Module['stdin'] = input || Module['stdin']\n        Module['stdout'] = output || Module['stdout']\n        Module['stderr'] = error || Module['stderr']\n        FS.createStandardStreams()\n      },\n      quit: () => {\n        FS.init.initialized = false\n        for (var i = 0; i < FS.streams.length; i++) {\n          var stream = FS.streams[i]\n          if (!stream) {\n            continue\n          }\n          FS.close(stream)\n        }\n      },\n      getMode: (canRead, canWrite) => {\n        var mode = 0\n        if (canRead) mode |= 292 | 73\n        if (canWrite) mode |= 146\n        return mode\n      },\n      findObject: (path, dontResolveLastLink) => {\n        var ret = FS.analyzePath(path, dontResolveLastLink)\n        if (!ret.exists) {\n          return null\n        }\n        return ret.object\n      },\n      analyzePath: (path, dontResolveLastLink) => {\n        try {\n          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          path = lookup.path\n        } catch (e) {}\n        var ret = {\n          isRoot: false,\n          exists: false,\n          error: 0,\n          name: null,\n          path: null,\n          object: null,\n          parentExists: false,\n          parentPath: null,\n          parentObject: null,\n        }\n        try {\n          var lookup = FS.lookupPath(path, { parent: true })\n          ret.parentExists = true\n          ret.parentPath = lookup.path\n          ret.parentObject = lookup.node\n          ret.name = PATH.basename(path)\n          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          ret.exists = true\n          ret.path = lookup.path\n          ret.object = lookup.node\n          ret.name = lookup.node.name\n          ret.isRoot = lookup.path === '/'\n        } catch (e) {\n          ret.error = e.errno\n        }\n        return ret\n      },\n      createPath: (parent, path, canRead, canWrite) => {\n        parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n        var parts = path.split('/').reverse()\n        while (parts.length) {\n          var part = parts.pop()\n          if (!part) continue\n          var current = PATH.join2(parent, part)\n          try {\n            FS.mkdir(current)\n          } catch (e) {}\n          parent = current\n        }\n        return current\n      },\n      createFile: (parent, name, properties, canRead, canWrite) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(canRead, canWrite)\n        return FS.create(path, mode)\n      },\n      createDataFile: (parent, name, data, canRead, canWrite, canOwn) => {\n        var path = name\n        if (parent) {\n          parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n          path = name ? PATH.join2(parent, name) : parent\n        }\n        var mode = FS.getMode(canRead, canWrite)\n        var node = FS.create(path, mode)\n        if (data) {\n          if (typeof data == 'string') {\n            var arr = new Array(data.length)\n            for (var i = 0, len = data.length; i < len; ++i)\n              arr[i] = data.charCodeAt(i)\n            data = arr\n          }\n          FS.chmod(node, mode | 146)\n          var stream = FS.open(node, 577)\n          FS.write(stream, data, 0, data.length, 0, canOwn)\n          FS.close(stream)\n          FS.chmod(node, mode)\n        }\n        return node\n      },\n      createDevice: (parent, name, input, output) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(!!input, !!output)\n        if (!FS.createDevice.major) FS.createDevice.major = 64\n        var dev = FS.makedev(FS.createDevice.major++, 0)\n        FS.registerDevice(dev, {\n          open: stream => {\n            stream.seekable = false\n          },\n          close: stream => {\n            if (output && output.buffer && output.buffer.length) {\n              output(10)\n            }\n          },\n          read: (stream, buffer, offset, length, pos) => {\n            var bytesRead = 0\n            for (var i = 0; i < length; i++) {\n              var result\n              try {\n                result = input()\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n              if (result === undefined && bytesRead === 0) {\n                throw new FS.ErrnoError(6)\n              }\n              if (result === null || result === undefined) break\n              bytesRead++\n              buffer[offset + i] = result\n            }\n            if (bytesRead) {\n              stream.node.timestamp = Date.now()\n            }\n            return bytesRead\n          },\n          write: (stream, buffer, offset, length, pos) => {\n            for (var i = 0; i < length; i++) {\n              try {\n                output(buffer[offset + i])\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n            }\n            if (length) {\n              stream.node.timestamp = Date.now()\n            }\n            return i\n          },\n        })\n        return FS.mkdev(path, mode, dev)\n      },\n      forceLoadFile: obj => {\n        if (obj.isDevice || obj.isFolder || obj.link || obj.contents)\n          return true\n        if (typeof XMLHttpRequest != 'undefined') {\n          throw new Error(\n            'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.'\n          )\n        } else if (read_) {\n          try {\n            obj.contents = intArrayFromString(read_(obj.url), true)\n            obj.usedBytes = obj.contents.length\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n        } else {\n          throw new Error('Cannot load without read() or XMLHttpRequest.')\n        }\n      },\n      createLazyFile: (parent, name, url, canRead, canWrite) => {\n        function LazyUint8Array() {\n          this.lengthKnown = false\n          this.chunks = []\n        }\n        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n          if (idx > this.length - 1 || idx < 0) {\n            return undefined\n          }\n          var chunkOffset = idx % this.chunkSize\n          var chunkNum = (idx / this.chunkSize) | 0\n          return this.getter(chunkNum)[chunkOffset]\n        }\n        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(\n          getter\n        ) {\n          this.getter = getter\n        }\n        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n          var xhr = new XMLHttpRequest()\n          xhr.open('HEAD', url, false)\n          xhr.send(null)\n          if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n            throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n          var datalength = Number(xhr.getResponseHeader('Content-length'))\n          var header\n          var hasByteServing =\n            (header = xhr.getResponseHeader('Accept-Ranges')) &&\n            header === 'bytes'\n          var usesGzip =\n            (header = xhr.getResponseHeader('Content-Encoding')) &&\n            header === 'gzip'\n          var chunkSize = 1024 * 1024\n          if (!hasByteServing) chunkSize = datalength\n          var doXHR = (from, to) => {\n            if (from > to)\n              throw new Error(\n                'invalid range (' +\n                  from +\n                  ', ' +\n                  to +\n                  ') or no bytes requested!'\n              )\n            if (to > datalength - 1)\n              throw new Error(\n                'only ' + datalength + ' bytes available! programmer error!'\n              )\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            if (datalength !== chunkSize)\n              xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to)\n            xhr.responseType = 'arraybuffer'\n            if (xhr.overrideMimeType) {\n              xhr.overrideMimeType('text/plain; charset=x-user-defined')\n            }\n            xhr.send(null)\n            if (\n              !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)\n            )\n              throw new Error(\n                \"Couldn't load \" + url + '. Status: ' + xhr.status\n              )\n            if (xhr.response !== undefined) {\n              return new Uint8Array(xhr.response || [])\n            }\n            return intArrayFromString(xhr.responseText || '', true)\n          }\n          var lazyArray = this\n          lazyArray.setDataGetter(chunkNum => {\n            var start = chunkNum * chunkSize\n            var end = (chunkNum + 1) * chunkSize - 1\n            end = Math.min(end, datalength - 1)\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined') {\n              lazyArray.chunks[chunkNum] = doXHR(start, end)\n            }\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined')\n              throw new Error('doXHR failed!')\n            return lazyArray.chunks[chunkNum]\n          })\n          if (usesGzip || !datalength) {\n            chunkSize = datalength = 1\n            datalength = this.getter(0).length\n            chunkSize = datalength\n            out(\n              'LazyFiles on gzip forces download of the whole file when length is accessed'\n            )\n          }\n          this._length = datalength\n          this._chunkSize = chunkSize\n          this.lengthKnown = true\n        }\n        if (typeof XMLHttpRequest != 'undefined') {\n          if (!ENVIRONMENT_IS_WORKER)\n            throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'\n          var lazyArray = new LazyUint8Array()\n          Object.defineProperties(lazyArray, {\n            length: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._length\n              },\n            },\n            chunkSize: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._chunkSize\n              },\n            },\n          })\n          var properties = { isDevice: false, contents: lazyArray }\n        } else {\n          var properties = { isDevice: false, url: url }\n        }\n        var node = FS.createFile(parent, name, properties, canRead, canWrite)\n        if (properties.contents) {\n          node.contents = properties.contents\n        } else if (properties.url) {\n          node.contents = null\n          node.url = properties.url\n        }\n        Object.defineProperties(node, {\n          usedBytes: {\n            get: function() {\n              return this.contents.length\n            },\n          },\n        })\n        var stream_ops = {}\n        var keys = Object.keys(node.stream_ops)\n        keys.forEach(key => {\n          var fn = node.stream_ops[key]\n          stream_ops[key] = function forceLoadLazyFile() {\n            FS.forceLoadFile(node)\n            return fn.apply(null, arguments)\n          }\n        })\n        function writeChunks(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= contents.length) return 0\n          var size = Math.min(contents.length - position, length)\n          if (contents.slice) {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents[position + i]\n            }\n          } else {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents.get(position + i)\n            }\n          }\n          return size\n        }\n        stream_ops.read = (stream, buffer, offset, length, position) => {\n          FS.forceLoadFile(node)\n          return writeChunks(stream, buffer, offset, length, position)\n        }\n        stream_ops.mmap = (stream, length, position, prot, flags) => {\n          FS.forceLoadFile(node)\n          var ptr = mmapAlloc(length)\n          if (!ptr) {\n            throw new FS.ErrnoError(48)\n          }\n          writeChunks(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        }\n        node.stream_ops = stream_ops\n        return node\n      },\n      createPreloadedFile: (\n        parent,\n        name,\n        url,\n        canRead,\n        canWrite,\n        onload,\n        onerror,\n        dontCreateFile,\n        canOwn,\n        preFinish\n      ) => {\n        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent\n        var dep = getUniqueRunDependency('cp ' + fullname)\n        function processData(byteArray) {\n          function finish(byteArray) {\n            if (preFinish) preFinish()\n            if (!dontCreateFile) {\n              FS.createDataFile(\n                parent,\n                name,\n                byteArray,\n                canRead,\n                canWrite,\n                canOwn\n              )\n            }\n            if (onload) onload()\n            removeRunDependency(dep)\n          }\n          if (\n            Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => {\n              if (onerror) onerror()\n              removeRunDependency(dep)\n            })\n          ) {\n            return\n          }\n          finish(byteArray)\n        }\n        addRunDependency(dep)\n        if (typeof url == 'string') {\n          asyncLoad(url, byteArray => processData(byteArray), onerror)\n        } else {\n          processData(url)\n        }\n      },\n      indexedDB: () => {\n        return (\n          window.indexedDB ||\n          window.mozIndexedDB ||\n          window.webkitIndexedDB ||\n          window.msIndexedDB\n        )\n      },\n      DB_NAME: () => {\n        return 'EM_FS_' + window.location.pathname\n      },\n      DB_VERSION: 20,\n      DB_STORE_NAME: 'FILE_DATA',\n      saveFilesToDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = () => {\n          out('creating db')\n          var db = openRequest.result\n          db.createObjectStore(FS.DB_STORE_NAME)\n        }\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite')\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var putRequest = files.put(\n              FS.analyzePath(path).object.contents,\n              path\n            )\n            putRequest.onsuccess = () => {\n              ok++\n              if (ok + fail == total) finish()\n            }\n            putRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n      loadFilesFromDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = onerror\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          try {\n            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly')\n          } catch (e) {\n            onerror(e)\n            return\n          }\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var getRequest = files.get(path)\n            getRequest.onsuccess = () => {\n              if (FS.analyzePath(path).exists) {\n                FS.unlink(path)\n              }\n              FS.createDataFile(\n                PATH.dirname(path),\n                PATH.basename(path),\n                getRequest.result,\n                true,\n                true,\n                true\n              )\n              ok++\n              if (ok + fail == total) finish()\n            }\n            getRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n    }\n    var SYSCALLS = {\n      DEFAULT_POLLMASK: 5,\n      calculateAt: function(dirfd, path, allowEmpty) {\n        if (PATH.isAbs(path)) {\n          return path\n        }\n        var dir\n        if (dirfd === -100) {\n          dir = FS.cwd()\n        } else {\n          var dirstream = SYSCALLS.getStreamFromFD(dirfd)\n          dir = dirstream.path\n        }\n        if (path.length == 0) {\n          if (!allowEmpty) {\n            throw new FS.ErrnoError(44)\n          }\n          return dir\n        }\n        return PATH.join2(dir, path)\n      },\n      doStat: function(func, path, buf) {\n        try {\n          var stat = func(path)\n        } catch (e) {\n          if (\n            e &&\n            e.node &&\n            PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))\n          ) {\n            return -54\n          }\n          throw e\n        }\n        HEAP32[buf >> 2] = stat.dev\n        HEAP32[(buf + 8) >> 2] = stat.ino\n        HEAP32[(buf + 12) >> 2] = stat.mode\n        HEAPU32[(buf + 16) >> 2] = stat.nlink\n        HEAP32[(buf + 20) >> 2] = stat.uid\n        HEAP32[(buf + 24) >> 2] = stat.gid\n        HEAP32[(buf + 28) >> 2] = stat.rdev\n        ;(tempI64 = [\n          stat.size >>> 0,\n          ((tempDouble = stat.size),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 40) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 44) >> 2] = tempI64[1])\n        HEAP32[(buf + 48) >> 2] = 4096\n        HEAP32[(buf + 52) >> 2] = stat.blocks\n        var atime = stat.atime.getTime()\n        var mtime = stat.mtime.getTime()\n        var ctime = stat.ctime.getTime()\n        ;(tempI64 = [\n          Math.floor(atime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(atime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 56) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 60) >> 2] = tempI64[1])\n        HEAPU32[(buf + 64) >> 2] = (atime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(mtime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(mtime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 72) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 76) >> 2] = tempI64[1])\n        HEAPU32[(buf + 80) >> 2] = (mtime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(ctime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(ctime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 88) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 92) >> 2] = tempI64[1])\n        HEAPU32[(buf + 96) >> 2] = (ctime % 1e3) * 1e3\n        ;(tempI64 = [\n          stat.ino >>> 0,\n          ((tempDouble = stat.ino),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 104) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 108) >> 2] = tempI64[1])\n        return 0\n      },\n      doMsync: function(addr, stream, len, flags, offset) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (flags & 2) {\n          return 0\n        }\n        var buffer = HEAPU8.slice(addr, addr + len)\n        FS.msync(stream, buffer, offset, len, flags)\n      },\n      varargs: undefined,\n      get: function() {\n        SYSCALLS.varargs += 4\n        var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]\n        return ret\n      },\n      getStr: function(ptr) {\n        var ret = UTF8ToString(ptr)\n        return ret\n      },\n      getStreamFromFD: function(fd) {\n        var stream = FS.getStream(fd)\n        if (!stream) throw new FS.ErrnoError(8)\n        return stream\n      },\n    }\n    function ___syscall_fcntl64(fd, cmd, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (cmd) {\n          case 0: {\n            var arg = SYSCALLS.get()\n            if (arg < 0) {\n              return -28\n            }\n            var newStream\n            newStream = FS.createStream(stream, arg)\n            return newStream.fd\n          }\n          case 1:\n          case 2:\n            return 0\n          case 3:\n            return stream.flags\n          case 4: {\n            var arg = SYSCALLS.get()\n            stream.flags |= arg\n            return 0\n          }\n          case 5: {\n            var arg = SYSCALLS.get()\n            var offset = 0\n            HEAP16[(arg + offset) >> 1] = 2\n            return 0\n          }\n          case 6:\n          case 7:\n            return 0\n          case 16:\n          case 8:\n            return -28\n          case 9:\n            setErrNo(28)\n            return -1\n          default: {\n            return -28\n          }\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_getcwd(buf, size) {\n      try {\n        if (size === 0) return -28\n        var cwd = FS.cwd()\n        var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1\n        if (size < cwdLengthInBytes) return -68\n        stringToUTF8(cwd, buf, size)\n        return cwdLengthInBytes\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_ioctl(fd, op, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (op) {\n          case 21509:\n          case 21505: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21510:\n          case 21511:\n          case 21512:\n          case 21506:\n          case 21507:\n          case 21508: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21519: {\n            if (!stream.tty) return -59\n            var argp = SYSCALLS.get()\n            HEAP32[argp >> 2] = 0\n            return 0\n          }\n          case 21520: {\n            if (!stream.tty) return -59\n            return -28\n          }\n          case 21531: {\n            var argp = SYSCALLS.get()\n            return FS.ioctl(stream, op, argp)\n          }\n          case 21523: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21524: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          default:\n            return -28\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_openat(dirfd, path, flags, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        var mode = varargs ? SYSCALLS.get() : 0\n        return FS.open(path, flags, mode).fd\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_readlinkat(dirfd, path, buf, bufsize) {\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        if (bufsize <= 0) return -28\n        var ret = FS.readlink(path)\n        var len = Math.min(bufsize, lengthBytesUTF8(ret))\n        var endChar = HEAP8[buf + len]\n        stringToUTF8(ret, buf, bufsize + 1)\n        HEAP8[buf + len] = endChar\n        return len\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_stat64(path, buf) {\n      try {\n        path = SYSCALLS.getStr(path)\n        return SYSCALLS.doStat(FS.stat, path, buf)\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function _abort() {\n      abort('')\n    }\n    function _emscripten_memcpy_big(dest, src, num) {\n      HEAPU8.copyWithin(dest, src, src + num)\n    }\n    function getHeapMax() {\n      return 2147483648\n    }\n    function emscripten_realloc_buffer(size) {\n      try {\n        wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16)\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        return 1\n      } catch (e) {}\n    }\n    function _emscripten_resize_heap(requestedSize) {\n      var oldSize = HEAPU8.length\n      requestedSize = requestedSize >>> 0\n      var maxHeapSize = getHeapMax()\n      if (requestedSize > maxHeapSize) {\n        return false\n      }\n      let alignUp = (x, multiple) =>\n        x + ((multiple - (x % multiple)) % multiple)\n      for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {\n        var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown)\n        overGrownHeapSize = Math.min(\n          overGrownHeapSize,\n          requestedSize + 100663296\n        )\n        var newSize = Math.min(\n          maxHeapSize,\n          alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)\n        )\n        var replacement = emscripten_realloc_buffer(newSize)\n        if (replacement) {\n          return true\n        }\n      }\n      return false\n    }\n    var ENV = {}\n    function getExecutableName() {\n      return thisProgram || './this.program'\n    }\n    function getEnvStrings() {\n      if (!getEnvStrings.strings) {\n        var lang =\n          (\n            (typeof navigator == 'object' &&\n              navigator.languages &&\n              navigator.languages[0]) ||\n            'C'\n          ).replace('-', '_') + '.UTF-8'\n        var env = {\n          USER: 'web_user',\n          LOGNAME: 'web_user',\n          PATH: '/',\n          PWD: '/',\n          HOME: '/home/web_user',\n          LANG: lang,\n          _: getExecutableName(),\n        }\n        for (var x in ENV) {\n          if (ENV[x] === undefined) delete env[x]\n          else env[x] = ENV[x]\n        }\n        var strings = []\n        for (var x in env) {\n          strings.push(x + '=' + env[x])\n        }\n        getEnvStrings.strings = strings\n      }\n      return getEnvStrings.strings\n    }\n    function writeAsciiToMemory(str, buffer, dontAddNull) {\n      for (var i = 0; i < str.length; ++i) {\n        HEAP8[buffer++ >> 0] = str.charCodeAt(i)\n      }\n      if (!dontAddNull) HEAP8[buffer >> 0] = 0\n    }\n    function _environ_get(__environ, environ_buf) {\n      var bufSize = 0\n      getEnvStrings().forEach(function(string, i) {\n        var ptr = environ_buf + bufSize\n        HEAPU32[(__environ + i * 4) >> 2] = ptr\n        writeAsciiToMemory(string, ptr)\n        bufSize += string.length + 1\n      })\n      return 0\n    }\n    function _environ_sizes_get(penviron_count, penviron_buf_size) {\n      var strings = getEnvStrings()\n      HEAPU32[penviron_count >> 2] = strings.length\n      var bufSize = 0\n      strings.forEach(function(string) {\n        bufSize += string.length + 1\n      })\n      HEAPU32[penviron_buf_size >> 2] = bufSize\n      return 0\n    }\n    function _proc_exit(code) {\n      EXITSTATUS = code\n      if (!keepRuntimeAlive()) {\n        if (Module['onExit']) Module['onExit'](code)\n        ABORT = true\n      }\n      quit_(code, new ExitStatus(code))\n    }\n    function exitJS(status, implicit) {\n      EXITSTATUS = status\n      _proc_exit(status)\n    }\n    var _exit = exitJS\n    function _fd_close(fd) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.close(stream)\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doReadv(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.read(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n        if (curr < len) break\n      }\n      return ret\n    }\n    function _fd_read(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doReadv(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function convertI32PairToI53Checked(lo, hi) {\n      return (hi + 2097152) >>> 0 < 4194305 - !!lo\n        ? (lo >>> 0) + hi * 4294967296\n        : NaN\n    }\n    function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {\n      try {\n        var offset = convertI32PairToI53Checked(offset_low, offset_high)\n        if (isNaN(offset)) return 61\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.llseek(stream, offset, whence)\n        ;(tempI64 = [\n          stream.position >>> 0,\n          ((tempDouble = stream.position),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[newOffset >> 2] = tempI64[0]),\n          (HEAP32[(newOffset + 4) >> 2] = tempI64[1])\n        if (stream.getdents && offset === 0 && whence === 0)\n          stream.getdents = null\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doWritev(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.write(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n      }\n      return ret\n    }\n    function _fd_write(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doWritev(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function __isLeapYear(year) {\n      return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n    }\n    function __arraySum(array, index) {\n      var sum = 0\n      for (var i = 0; i <= index; sum += array[i++]) {}\n      return sum\n    }\n    var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    function __addDays(date, days) {\n      var newDate = new Date(date.getTime())\n      while (days > 0) {\n        var leap = __isLeapYear(newDate.getFullYear())\n        var currentMonth = newDate.getMonth()\n        var daysInCurrentMonth = (leap\n          ? __MONTH_DAYS_LEAP\n          : __MONTH_DAYS_REGULAR)[currentMonth]\n        if (days > daysInCurrentMonth - newDate.getDate()) {\n          days -= daysInCurrentMonth - newDate.getDate() + 1\n          newDate.setDate(1)\n          if (currentMonth < 11) {\n            newDate.setMonth(currentMonth + 1)\n          } else {\n            newDate.setMonth(0)\n            newDate.setFullYear(newDate.getFullYear() + 1)\n          }\n        } else {\n          newDate.setDate(newDate.getDate() + days)\n          return newDate\n        }\n      }\n      return newDate\n    }\n    function writeArrayToMemory(array, buffer) {\n      HEAP8.set(array, buffer)\n    }\n    function _strftime(s, maxsize, format, tm) {\n      var tm_zone = HEAP32[(tm + 40) >> 2]\n      var date = {\n        tm_sec: HEAP32[tm >> 2],\n        tm_min: HEAP32[(tm + 4) >> 2],\n        tm_hour: HEAP32[(tm + 8) >> 2],\n        tm_mday: HEAP32[(tm + 12) >> 2],\n        tm_mon: HEAP32[(tm + 16) >> 2],\n        tm_year: HEAP32[(tm + 20) >> 2],\n        tm_wday: HEAP32[(tm + 24) >> 2],\n        tm_yday: HEAP32[(tm + 28) >> 2],\n        tm_isdst: HEAP32[(tm + 32) >> 2],\n        tm_gmtoff: HEAP32[(tm + 36) >> 2],\n        tm_zone: tm_zone ? UTF8ToString(tm_zone) : '',\n      }\n      var pattern = UTF8ToString(format)\n      var EXPANSION_RULES_1 = {\n        '%c': '%a %b %d %H:%M:%S %Y',\n        '%D': '%m/%d/%y',\n        '%F': '%Y-%m-%d',\n        '%h': '%b',\n        '%r': '%I:%M:%S %p',\n        '%R': '%H:%M',\n        '%T': '%H:%M:%S',\n        '%x': '%m/%d/%y',\n        '%X': '%H:%M:%S',\n        '%Ec': '%c',\n        '%EC': '%C',\n        '%Ex': '%m/%d/%y',\n        '%EX': '%H:%M:%S',\n        '%Ey': '%y',\n        '%EY': '%Y',\n        '%Od': '%d',\n        '%Oe': '%e',\n        '%OH': '%H',\n        '%OI': '%I',\n        '%Om': '%m',\n        '%OM': '%M',\n        '%OS': '%S',\n        '%Ou': '%u',\n        '%OU': '%U',\n        '%OV': '%V',\n        '%Ow': '%w',\n        '%OW': '%W',\n        '%Oy': '%y',\n      }\n      for (var rule in EXPANSION_RULES_1) {\n        pattern = pattern.replace(\n          new RegExp(rule, 'g'),\n          EXPANSION_RULES_1[rule]\n        )\n      }\n      var WEEKDAYS = [\n        'Sunday',\n        'Monday',\n        'Tuesday',\n        'Wednesday',\n        'Thursday',\n        'Friday',\n        'Saturday',\n      ]\n      var MONTHS = [\n        'January',\n        'February',\n        'March',\n        'April',\n        'May',\n        'June',\n        'July',\n        'August',\n        'September',\n        'October',\n        'November',\n        'December',\n      ]\n      function leadingSomething(value, digits, character) {\n        var str = typeof value == 'number' ? value.toString() : value || ''\n        while (str.length < digits) {\n          str = character[0] + str\n        }\n        return str\n      }\n      function leadingNulls(value, digits) {\n        return leadingSomething(value, digits, '0')\n      }\n      function compareByDay(date1, date2) {\n        function sgn(value) {\n          return value < 0 ? -1 : value > 0 ? 1 : 0\n        }\n        var compare\n        if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) {\n          if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) {\n            compare = sgn(date1.getDate() - date2.getDate())\n          }\n        }\n        return compare\n      }\n      function getFirstWeekStartDate(janFourth) {\n        switch (janFourth.getDay()) {\n          case 0:\n            return new Date(janFourth.getFullYear() - 1, 11, 29)\n          case 1:\n            return janFourth\n          case 2:\n            return new Date(janFourth.getFullYear(), 0, 3)\n          case 3:\n            return new Date(janFourth.getFullYear(), 0, 2)\n          case 4:\n            return new Date(janFourth.getFullYear(), 0, 1)\n          case 5:\n            return new Date(janFourth.getFullYear() - 1, 11, 31)\n          case 6:\n            return new Date(janFourth.getFullYear() - 1, 11, 30)\n        }\n      }\n      function getWeekBasedYear(date) {\n        var thisDate = __addDays(\n          new Date(date.tm_year + 1900, 0, 1),\n          date.tm_yday\n        )\n        var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4)\n        var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4)\n        var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear)\n        var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear)\n        if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {\n          if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {\n            return thisDate.getFullYear() + 1\n          }\n          return thisDate.getFullYear()\n        }\n        return thisDate.getFullYear() - 1\n      }\n      var EXPANSION_RULES_2 = {\n        '%a': function(date) {\n          return WEEKDAYS[date.tm_wday].substring(0, 3)\n        },\n        '%A': function(date) {\n          return WEEKDAYS[date.tm_wday]\n        },\n        '%b': function(date) {\n          return MONTHS[date.tm_mon].substring(0, 3)\n        },\n        '%B': function(date) {\n          return MONTHS[date.tm_mon]\n        },\n        '%C': function(date) {\n          var year = date.tm_year + 1900\n          return leadingNulls((year / 100) | 0, 2)\n        },\n        '%d': function(date) {\n          return leadingNulls(date.tm_mday, 2)\n        },\n        '%e': function(date) {\n          return leadingSomething(date.tm_mday, 2, ' ')\n        },\n        '%g': function(date) {\n          return getWeekBasedYear(date)\n            .toString()\n            .substring(2)\n        },\n        '%G': function(date) {\n          return getWeekBasedYear(date)\n        },\n        '%H': function(date) {\n          return leadingNulls(date.tm_hour, 2)\n        },\n        '%I': function(date) {\n          var twelveHour = date.tm_hour\n          if (twelveHour == 0) twelveHour = 12\n          else if (twelveHour > 12) twelveHour -= 12\n          return leadingNulls(twelveHour, 2)\n        },\n        '%j': function(date) {\n          return leadingNulls(\n            date.tm_mday +\n              __arraySum(\n                __isLeapYear(date.tm_year + 1900)\n                  ? __MONTH_DAYS_LEAP\n                  : __MONTH_DAYS_REGULAR,\n                date.tm_mon - 1\n              ),\n            3\n          )\n        },\n        '%m': function(date) {\n          return leadingNulls(date.tm_mon + 1, 2)\n        },\n        '%M': function(date) {\n          return leadingNulls(date.tm_min, 2)\n        },\n        '%n': function() {\n          return '\\n'\n        },\n        '%p': function(date) {\n          if (date.tm_hour >= 0 && date.tm_hour < 12) {\n            return 'AM'\n          }\n          return 'PM'\n        },\n        '%S': function(date) {\n          return leadingNulls(date.tm_sec, 2)\n        },\n        '%t': function() {\n          return '\\t'\n        },\n        '%u': function(date) {\n          return date.tm_wday || 7\n        },\n        '%U': function(date) {\n          var days = date.tm_yday + 7 - date.tm_wday\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%V': function(date) {\n          var val = Math.floor(\n            (date.tm_yday + 7 - ((date.tm_wday + 6) % 7)) / 7\n          )\n          if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) {\n            val++\n          }\n          if (!val) {\n            val = 52\n            var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7\n            if (\n              dec31 == 4 ||\n              (dec31 == 5 && __isLeapYear((date.tm_year % 400) - 1))\n            ) {\n              val++\n            }\n          } else if (val == 53) {\n            var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7\n            if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) val = 1\n          }\n          return leadingNulls(val, 2)\n        },\n        '%w': function(date) {\n          return date.tm_wday\n        },\n        '%W': function(date) {\n          var days = date.tm_yday + 7 - ((date.tm_wday + 6) % 7)\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%y': function(date) {\n          return (date.tm_year + 1900).toString().substring(2)\n        },\n        '%Y': function(date) {\n          return date.tm_year + 1900\n        },\n        '%z': function(date) {\n          var off = date.tm_gmtoff\n          var ahead = off >= 0\n          off = Math.abs(off) / 60\n          off = (off / 60) * 100 + (off % 60)\n          return (ahead ? '+' : '-') + String('0000' + off).slice(-4)\n        },\n        '%Z': function(date) {\n          return date.tm_zone\n        },\n        '%%': function() {\n          return '%'\n        },\n      }\n      pattern = pattern.replace(/%%/g, '\\0\\0')\n      for (var rule in EXPANSION_RULES_2) {\n        if (pattern.includes(rule)) {\n          pattern = pattern.replace(\n            new RegExp(rule, 'g'),\n            EXPANSION_RULES_2[rule](date)\n          )\n        }\n      }\n      pattern = pattern.replace(/\\0\\0/g, '%')\n      var bytes = intArrayFromString(pattern, false)\n      if (bytes.length > maxsize) {\n        return 0\n      }\n      writeArrayToMemory(bytes, s)\n      return bytes.length - 1\n    }\n    function _strftime_l(s, maxsize, format, tm, loc) {\n      return _strftime(s, maxsize, format, tm)\n    }\n    function handleException(e) {\n      if (e instanceof ExitStatus || e == 'unwind') {\n        return EXITSTATUS\n      }\n      quit_(1, e)\n    }\n    function allocateUTF8OnStack(str) {\n      var size = lengthBytesUTF8(str) + 1\n      var ret = stackAlloc(size)\n      stringToUTF8Array(str, HEAP8, ret, size)\n      return ret\n    }\n    function getCFunc(ident) {\n      var func = Module['_' + ident]\n      return func\n    }\n    function ccall(ident, returnType, argTypes, args, opts) {\n      var toC = {\n        string: str => {\n          var ret = 0\n          if (str !== null && str !== undefined && str !== 0) {\n            var len = (str.length << 2) + 1\n            ret = stackAlloc(len)\n            stringToUTF8(str, ret, len)\n          }\n          return ret\n        },\n        array: arr => {\n          var ret = stackAlloc(arr.length)\n          writeArrayToMemory(arr, ret)\n          return ret\n        },\n      }\n      function convertReturnValue(ret) {\n        if (returnType === 'string') {\n          return UTF8ToString(ret)\n        }\n        if (returnType === 'boolean') return Boolean(ret)\n        return ret\n      }\n      var func = getCFunc(ident)\n      var cArgs = []\n      var stack = 0\n      if (args) {\n        for (var i = 0; i < args.length; i++) {\n          var converter = toC[argTypes[i]]\n          if (converter) {\n            if (stack === 0) stack = stackSave()\n            cArgs[i] = converter(args[i])\n          } else {\n            cArgs[i] = args[i]\n          }\n        }\n      }\n      var ret = func.apply(null, cArgs)\n      function onDone(ret) {\n        if (stack !== 0) stackRestore(stack)\n        return convertReturnValue(ret)\n      }\n      ret = onDone(ret)\n      return ret\n    }\n    function cwrap(ident, returnType, argTypes, opts) {\n      argTypes = argTypes || []\n      var numericArgs = argTypes.every(\n        type => type === 'number' || type === 'boolean'\n      )\n      var numericRet = returnType !== 'string'\n      if (numericRet && numericArgs && !opts) {\n        return getCFunc(ident)\n      }\n      return function() {\n        return ccall(ident, returnType, argTypes, arguments, opts)\n      }\n    }\n    function AsciiToString(ptr) {\n      var str = ''\n      while (1) {\n        var ch = HEAPU8[ptr++ >> 0]\n        if (!ch) return str\n        str += String.fromCharCode(ch)\n      }\n    }\n    var FSNode = function(parent, name, mode, rdev) {\n      if (!parent) {\n        parent = this\n      }\n      this.parent = parent\n      this.mount = parent.mount\n      this.mounted = null\n      this.id = FS.nextInode++\n      this.name = name\n      this.mode = mode\n      this.node_ops = {}\n      this.stream_ops = {}\n      this.rdev = rdev\n    }\n    var readMode = 292 | 73\n    var writeMode = 146\n    Object.defineProperties(FSNode.prototype, {\n      read: {\n        get: function() {\n          return (this.mode & readMode) === readMode\n        },\n        set: function(val) {\n          val ? (this.mode |= readMode) : (this.mode &= ~readMode)\n        },\n      },\n      write: {\n        get: function() {\n          return (this.mode & writeMode) === writeMode\n        },\n        set: function(val) {\n          val ? (this.mode |= writeMode) : (this.mode &= ~writeMode)\n        },\n      },\n      isFolder: {\n        get: function() {\n          return FS.isDir(this.mode)\n        },\n      },\n      isDevice: {\n        get: function() {\n          return FS.isChrdev(this.mode)\n        },\n      },\n    })\n    FS.FSNode = FSNode\n    FS.staticInit()\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_unlink'] = FS.unlink\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    if (ENVIRONMENT_IS_NODE) {\n      NODEFS.staticInit()\n    }\n    ERRNO_CODES = {\n      EPERM: 63,\n      ENOENT: 44,\n      ESRCH: 71,\n      EINTR: 27,\n      EIO: 29,\n      ENXIO: 60,\n      E2BIG: 1,\n      ENOEXEC: 45,\n      EBADF: 8,\n      ECHILD: 12,\n      EAGAIN: 6,\n      EWOULDBLOCK: 6,\n      ENOMEM: 48,\n      EACCES: 2,\n      EFAULT: 21,\n      ENOTBLK: 105,\n      EBUSY: 10,\n      EEXIST: 20,\n      EXDEV: 75,\n      ENODEV: 43,\n      ENOTDIR: 54,\n      EISDIR: 31,\n      EINVAL: 28,\n      ENFILE: 41,\n      EMFILE: 33,\n      ENOTTY: 59,\n      ETXTBSY: 74,\n      EFBIG: 22,\n      ENOSPC: 51,\n      ESPIPE: 70,\n      EROFS: 69,\n      EMLINK: 34,\n      EPIPE: 64,\n      EDOM: 18,\n      ERANGE: 68,\n      ENOMSG: 49,\n      EIDRM: 24,\n      ECHRNG: 106,\n      EL2NSYNC: 156,\n      EL3HLT: 107,\n      EL3RST: 108,\n      ELNRNG: 109,\n      EUNATCH: 110,\n      ENOCSI: 111,\n      EL2HLT: 112,\n      EDEADLK: 16,\n      ENOLCK: 46,\n      EBADE: 113,\n      EBADR: 114,\n      EXFULL: 115,\n      ENOANO: 104,\n      EBADRQC: 103,\n      EBADSLT: 102,\n      EDEADLOCK: 16,\n      EBFONT: 101,\n      ENOSTR: 100,\n      ENODATA: 116,\n      ETIME: 117,\n      ENOSR: 118,\n      ENONET: 119,\n      ENOPKG: 120,\n      EREMOTE: 121,\n      ENOLINK: 47,\n      EADV: 122,\n      ESRMNT: 123,\n      ECOMM: 124,\n      EPROTO: 65,\n      EMULTIHOP: 36,\n      EDOTDOT: 125,\n      EBADMSG: 9,\n      ENOTUNIQ: 126,\n      EBADFD: 127,\n      EREMCHG: 128,\n      ELIBACC: 129,\n      ELIBBAD: 130,\n      ELIBSCN: 131,\n      ELIBMAX: 132,\n      ELIBEXEC: 133,\n      ENOSYS: 52,\n      ENOTEMPTY: 55,\n      ENAMETOOLONG: 37,\n      ELOOP: 32,\n      EOPNOTSUPP: 138,\n      EPFNOSUPPORT: 139,\n      ECONNRESET: 15,\n      ENOBUFS: 42,\n      EAFNOSUPPORT: 5,\n      EPROTOTYPE: 67,\n      ENOTSOCK: 57,\n      ENOPROTOOPT: 50,\n      ESHUTDOWN: 140,\n      ECONNREFUSED: 14,\n      EADDRINUSE: 3,\n      ECONNABORTED: 13,\n      ENETUNREACH: 40,\n      ENETDOWN: 38,\n      ETIMEDOUT: 73,\n      EHOSTDOWN: 142,\n      EHOSTUNREACH: 23,\n      EINPROGRESS: 26,\n      EALREADY: 7,\n      EDESTADDRREQ: 17,\n      EMSGSIZE: 35,\n      EPROTONOSUPPORT: 66,\n      ESOCKTNOSUPPORT: 137,\n      EADDRNOTAVAIL: 4,\n      ENETRESET: 39,\n      EISCONN: 30,\n      ENOTCONN: 53,\n      ETOOMANYREFS: 141,\n      EUSERS: 136,\n      EDQUOT: 19,\n      ESTALE: 72,\n      ENOTSUP: 138,\n      ENOMEDIUM: 148,\n      EILSEQ: 25,\n      EOVERFLOW: 61,\n      ECANCELED: 11,\n      ENOTRECOVERABLE: 56,\n      EOWNERDEAD: 62,\n      ESTRPIPE: 135,\n    }\n    var asmLibraryArg = {\n      a: ___cxa_throw,\n      d: ___syscall_fcntl64,\n      r: ___syscall_getcwd,\n      i: ___syscall_ioctl,\n      j: ___syscall_openat,\n      n: ___syscall_readlinkat,\n      o: ___syscall_stat64,\n      b: _abort,\n      f: _emscripten_memcpy_big,\n      m: _emscripten_resize_heap,\n      p: _environ_get,\n      q: _environ_sizes_get,\n      c: _exit,\n      e: _fd_close,\n      h: _fd_read,\n      k: _fd_seek,\n      g: _fd_write,\n      l: _strftime_l,\n    }\n    var asm = createWasm()\n    var ___wasm_call_ctors = (Module['___wasm_call_ctors'] = function() {\n      return (___wasm_call_ctors = Module['___wasm_call_ctors'] =\n        Module['asm']['t']).apply(null, arguments)\n    })\n    var _main = (Module['_main'] = function() {\n      return (_main = Module['_main'] = Module['asm']['u']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___errno_location = (Module['___errno_location'] = function() {\n      return (___errno_location = Module['___errno_location'] =\n        Module['asm']['v']).apply(null, arguments)\n    })\n    var _itk_wasm_input_array_alloc = (Module[\n      '_itk_wasm_input_array_alloc'\n    ] = function() {\n      return (_itk_wasm_input_array_alloc = Module[\n        '_itk_wasm_input_array_alloc'\n      ] = Module['asm']['w']).apply(null, arguments)\n    })\n    var _itk_wasm_input_json_alloc = (Module[\n      '_itk_wasm_input_json_alloc'\n    ] = function() {\n      return (_itk_wasm_input_json_alloc = Module[\n        '_itk_wasm_input_json_alloc'\n      ] = Module['asm']['x']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_address = (Module[\n      '_itk_wasm_output_json_address'\n    ] = function() {\n      return (_itk_wasm_output_json_address = Module[\n        '_itk_wasm_output_json_address'\n      ] = Module['asm']['y']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_size = (Module[\n      '_itk_wasm_output_json_size'\n    ] = function() {\n      return (_itk_wasm_output_json_size = Module[\n        '_itk_wasm_output_json_size'\n      ] = Module['asm']['z']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_address = (Module[\n      '_itk_wasm_output_array_address'\n    ] = function() {\n      return (_itk_wasm_output_array_address = Module[\n        '_itk_wasm_output_array_address'\n      ] = Module['asm']['A']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_size = (Module[\n      '_itk_wasm_output_array_size'\n    ] = function() {\n      return (_itk_wasm_output_array_size = Module[\n        '_itk_wasm_output_array_size'\n      ] = Module['asm']['B']).apply(null, arguments)\n    })\n    var _itk_wasm_free_all = (Module['_itk_wasm_free_all'] = function() {\n      return (_itk_wasm_free_all = Module['_itk_wasm_free_all'] =\n        Module['asm']['C']).apply(null, arguments)\n    })\n    var stackSave = (Module['stackSave'] = function() {\n      return (stackSave = Module['stackSave'] = Module['asm']['E']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackRestore = (Module['stackRestore'] = function() {\n      return (stackRestore = Module['stackRestore'] = Module['asm']['F']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackAlloc = (Module['stackAlloc'] = function() {\n      return (stackAlloc = Module['stackAlloc'] = Module['asm']['G']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___cxa_is_pointer_type = (Module[\n      '___cxa_is_pointer_type'\n    ] = function() {\n      return (___cxa_is_pointer_type = Module['___cxa_is_pointer_type'] =\n        Module['asm']['H']).apply(null, arguments)\n    })\n    Module['addRunDependency'] = addRunDependency\n    Module['removeRunDependency'] = removeRunDependency\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    Module['FS_unlink'] = FS.unlink\n    Module['callMain'] = callMain\n    Module['ccall'] = ccall\n    Module['cwrap'] = cwrap\n    Module['AsciiToString'] = AsciiToString\n    Module['writeArrayToMemory'] = writeArrayToMemory\n    Module['writeAsciiToMemory'] = writeAsciiToMemory\n    var calledRun\n    dependenciesFulfilled = function runCaller() {\n      if (!calledRun) run()\n      if (!calledRun) dependenciesFulfilled = runCaller\n    }\n    function callMain(args) {\n      var entryFunction = Module['_main']\n      args = args || []\n      args.unshift(thisProgram)\n      var argc = args.length\n      var argv = stackAlloc((argc + 1) * 4)\n      var argv_ptr = argv >> 2\n      args.forEach(arg => {\n        HEAP32[argv_ptr++] = allocateUTF8OnStack(arg)\n      })\n      HEAP32[argv_ptr] = 0\n      try {\n        var ret = entryFunction(argc, argv)\n        exitJS(ret, true)\n        return ret\n      } catch (e) {\n        return handleException(e)\n      }\n    }\n    function run(args) {\n      args = args || arguments_\n      if (runDependencies > 0) {\n        return\n      }\n      preRun()\n      if (runDependencies > 0) {\n        return\n      }\n      function doRun() {\n        if (calledRun) return\n        calledRun = true\n        Module['calledRun'] = true\n        if (ABORT) return\n        initRuntime()\n        preMain()\n        readyPromiseResolve(Module)\n        if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']()\n        if (shouldRunNow) callMain(args)\n        postRun()\n      }\n      if (Module['setStatus']) {\n        Module['setStatus']('Running...')\n        setTimeout(function() {\n          setTimeout(function() {\n            Module['setStatus']('')\n          }, 1)\n          doRun()\n        }, 1)\n      } else {\n        doRun()\n      }\n    }\n    if (Module['preInit']) {\n      if (typeof Module['preInit'] == 'function')\n        Module['preInit'] = [Module['preInit']]\n      while (Module['preInit'].length > 0) {\n        Module['preInit'].pop()()\n      }\n    }\n    var shouldRunNow = false\n    if (Module['noInitialRun']) shouldRunNow = false\n    run()\n    Module.mountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      if (FS.isDir(containingDir) || containingDir === '/') {\n        return\n      }\n      var currentDir = '/'\n      var splitContainingDir = containingDir.split(path.sep)\n      for (var ii = 1; ii < splitContainingDir.length; ii++) {\n        currentDir += splitContainingDir[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n      FS.mount(NODEFS, { root: containingDir }, currentDir)\n      return currentDir + path.basename(filePath)\n    }\n    Module.unmountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      FS.unmount(containingDir)\n    }\n    Module.fs_mkdirs = function(dirs) {\n      var currentDir = '/'\n      var splitDirs = dirs.split('/')\n      for (var ii = 1; ii < splitDirs.length; ++ii) {\n        currentDir += splitDirs[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n    }\n    Module.fs_readFile = function(path, opts) {\n      return FS.readFile(path, opts)\n    }\n    Module.fs_writeFile = function(path, data, opts) {\n      return FS.writeFile(path, data, opts)\n    }\n    Module.fs_unlink = function(path) {\n      return FS.unlink(path)\n    }\n    Module.fs_open = function(path, flags, mode) {\n      return FS.open(path, flags, mode)\n    }\n    Module.fs_stat = function(path) {\n      return FS.stat(path)\n    }\n    Module.fs_read = function(stream, buffer, offset, length, position) {\n      return FS.read(stream, buffer, offset, length, position)\n    }\n    Module.fs_close = function(stream) {\n      return FS.close(stream)\n    }\n\n    return DownsampleLabelImage.ready\n  }\n})()\nif (typeof exports === 'object' && typeof module === 'object')\n  module.exports = DownsampleLabelImage\nelse if (typeof define === 'function' && define['amd'])\n  define([], function() {\n    return DownsampleLabelImage\n  })\nelse if (typeof exports === 'object')\n  exports['DownsampleLabelImage'] = DownsampleLabelImage\n"
  },
  {
    "path": "src/IO/Downsample/index.html",
    "content": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>itk-wasm UMD Example</title>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"stylesheet\" href=\"styles.css\">\n    <script src=\"https://cdn.jsdelivr.net/npm/itk-wasm@1.0.0-b.7/dist/umd/itk-wasm.js\"></script>\n    <script src=\"https://cdn.jsdelivr.net/npm/itk-vtk-viewer@11.12.0/dist/itkVtkViewerCDN.js\"></script>\n  </head>\n\n  <body>\n    <!-- Selector -->\n    <div>\n      <label>Select input image:</label>\n      <input name=\"inputFile\" id=\"inputImage\" type=\"file\">\n    </div>\n\n    <div>\n      <label>Label image:</label>\n      <input name=\"labelImage\" id=\"labelImage\" type=\"checkbox\">\n    </div>\n\n    <!-- File information -->\n    <textarea readonly id=\"outputImageInformation\">Output image information...</textarea>\n\n    <!-- File visualization -->\n    <div id=\"outputViewer\"></div>\n\n    <!-- Javascript -->\n    <script>\n      function processFile(event) {\n        const dataTransfer = event.dataTransfer;\n        const files = event.target.files || dataTransfer.files;\n\n        return itk.readImageFile(null, files[0]).then(async function({ image, webWorker }) {\n\n          \n          const isLabelImage = document.getElementById('labelImage').checked\n          const pipelinePath = false ? new URL('./web-build/DownsampleLabelImage', document.location) : new URL('./web-build/Downsample', document.location)\n\n          const factors = [2,2,2]\n          const inputs = [\n            {\n              type: itk.InterfaceTypes.Image,\n              data: image,\n            },\n          ]\n          const desiredOutputs = [\n            { type: itk.InterfaceTypes.Image },\n          ]\n          const args = [\n            '0',\n            '0',\n            factors.join(','),\n            // '--max-total-splits', '' + maxTotalSplits,\n            // '--split', '' + index,\n            // '--number-of-splits', '1',\n            '--memory-io',\n          ]\n\n          const { returnValue, stdout, stderr, outputs } = await itk.runPipeline(webWorker, pipelinePath, args, desiredOutputs, inputs)\n          webWorker.terminate();\n\n          console.log('stdout', stdout)\n          console.error('stderr', stderr)\n          console.log(outputs)\n          const outputImage = outputs[0].data\n\n          const outputTextArea = document.getElementById(\"outputImageInformation\");\n          outputTextArea.textContent = \"Loading...\";\n\n          function replacer(key, value) {\n            if (!!value && value.byteLength !== undefined) {\n              return String(value.slice(0, 6)) + \"...\";\n            }\n            return value;\n          }\n          outputTextArea.textContent = JSON.stringify(outputImage, replacer, 4);\n\n          const viewerElement = document.getElementById(\"outputViewer\")\n          window.itkVtkViewer.createViewer(viewerElement, { image: outputImage })\n\n        });\n      }\n\n      const fileInput = document.getElementById(\"inputImage\");\n      fileInput.addEventListener(\"change\", processFile);\n    </script>\n\n  </body>\n</html>\n\n"
  },
  {
    "path": "src/IO/Downsample/package.json",
    "content": "{\n  \"name\": \"itk-downsample\",\n  \"version\": \"1.0.1\",\n  \"description\": \"Downsample a 2D or 3D image\",\n  \"main\": \"downsample.js\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"itk-wasm build\",\n    \"start\": \"http-server .\",\n    \"cypress:open\": \"npx cypress open\",\n    \"cypress:run\": \"npx cypress run --config defaultCommandTimeout=8000\",\n    \"browser:debug\": \"start-server-and-test start http://localhost:8080 cypress:open\",\n    \"test:browser\": \"start-server-and-test start http://localhost:8080 cypress:run\",\n    \"test\": \"npm run test:node && npm run test:nodeLabelImage && npm run test:browser\",\n    \"test:node\": \"node downsample.js ./cthead1.png downsample.png\",\n    \"test:nodeLabelImage\": \"node downsample.js -l ./cthead1-bin.png downsample-bin.png\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/InsightSoftwareConsortium/itk-wasm.git\"\n  },\n  \"keywords\": [\n    \"multi-scale\"\n  ],\n  \"author\": \"Matt McCormick\",\n  \"license\": \"Apache-2.0\",\n  \"bugs\": {\n    \"url\": \"https://github.com/InsightSoftwareConsortium/itk-wasm/issues\"\n  },\n  \"homepage\": \"https://github.com/InsightSoftwareConsortium/itk-wasm#readme\",\n  \"dependencies\": {\n    \"commander\": \"^9.1.0\",\n    \"itk-image-io\": \"^1.0.0-b.84\",\n    \"itk-wasm\": \"^1.0.0-b.84\"\n  },\n  \"devDependencies\": {\n    \"cypress\": \"^13.2.0\",\n    \"http-server\": \"^14.1.0\",\n    \"start-server-and-test\": \"^2.0.3\"\n  }\n}\n"
  },
  {
    "path": "src/IO/Downsample/styles.css",
    "content": "html, body {\n  height: 90%;\n}\n\ntextarea {\n  resize: none;\n  overflow-y: scroll;\n  position: absolute;\n  box-sizing: border-box;\n  width: 600px;\n  height: 400px;\n  bottom: 0px;\n  left: 0px;\n  top: 50px;\n}\n\n#outputViewer {\n  position: relative;\n  box-sizing: border-box;\n  height: 500px;\n  width: 600px;\n  left: 5px;\n  top: 450px;\n}\n"
  },
  {
    "path": "src/IO/HttpStore.js",
    "content": "import axios from 'axios'\n\nclass HttpStore {\n  constructor(url) {\n    this.href = url.href\n  }\n\n  async getItem(item) {\n    const url = `${this.href}/${item}`\n    return (await axios.get(url, { responseType: 'arraybuffer' })).data\n  }\n}\n\nexport default HttpStore\n"
  },
  {
    "path": "src/IO/ImageDataFromChunks.worker.js",
    "content": "import registerWebworker from 'webworker-promise/lib/register'\nimport { computeRanges } from './Analyze/computeRanges'\nimport componentTypeToTypedArray from './componentTypeToTypedArray'\nimport { CXYZT, ensuredDims } from './dimensionUtils'\nimport {\n  getTypedArray,\n  ElementGetter,\n  getSize,\n  testLittleEndian,\n} from './dtypeUtils'\n\nconst haveSharedArrayBuffer = typeof self.SharedArrayBuffer === 'function'\n\nconst validateIndices = ({ chunkStart, chunkEnd, roiStart, roiEnd }) => {\n  if (\n    ['x', 'y', 'z'].some(\n      dim => chunkStart[dim] > roiEnd[dim] || chunkEnd[dim] < roiStart[dim]\n    )\n  ) {\n    // We should never get here...\n    console.error('Requested a chunk outside the region of interest!')\n  }\n}\n\nconst IS_SYSTEM_LITTLE_ENDIAN = (function() {\n  const buffer = new ArrayBuffer(2)\n  new DataView(buffer).setInt16(0, 256, true /* littleEndian */)\n  // Int16Array uses the platform's endianness.\n  return new Int16Array(buffer)[0] === 256\n})()\n\nconst makeImageDataFromChunks = ({\n  scaleInfo: info,\n  imageType,\n  chunkIndices,\n  chunks,\n  indexStart,\n  indexEnd,\n}) => {\n  const pixelArrayType = componentTypeToTypedArray.get(imageType.componentType)\n  let pixelArray = null\n  const pixelArrayElements = Array.from(info.arrayShape.values()).reduce(\n    (a, b) => a * b\n  )\n  if (haveSharedArrayBuffer) {\n    const pixelArrayBytes =\n      pixelArrayElements * pixelArrayType.BYTES_PER_ELEMENT\n    const sharedArrayBuffer = new SharedArrayBuffer(pixelArrayBytes)\n    pixelArray = new pixelArrayType(sharedArrayBuffer)\n  } else {\n    pixelArray = new pixelArrayType(pixelArrayElements)\n  }\n\n  const arrayShape = Object.fromEntries(ensuredDims(1, CXYZT, info.arrayShape))\n  const pixelStrides = {\n    z: arrayShape.c * arrayShape.x * arrayShape.y,\n    y: arrayShape.c * arrayShape.x,\n    x: arrayShape.c,\n  }\n\n  const chunkSizeDefault1 = ensuredDims(1, CXYZT, info.chunkSize)\n  const chunkSize = Object.fromEntries(chunkSizeDefault1)\n\n  // stride is the number of elements between elements in a dimension\n  const [chunkStrides] = Array.from(chunkSizeDefault1)\n    .reverse()\n    .reduce(\n      ([strides, size], [dim, dimSize]) => [\n        { [dim]: size, ...strides },\n        size * dimSize,\n      ],\n      [{}, 1]\n    )\n\n  for (let index = 0; index < chunkIndices.length; index++) {\n    const [c, x, y, z /*t*/] = chunkIndices[index]\n\n    const chunkStart = {\n      c: c * chunkSize.c,\n      z: z * chunkSize.z,\n      y: y * chunkSize.y,\n      x: x * chunkSize.x,\n    }\n    const chunkEnd = {\n      c: (c + 1) * chunkSize.c,\n      z: (z + 1) * chunkSize.z,\n      y: (y + 1) * chunkSize.y,\n      x: (x + 1) * chunkSize.x,\n    }\n    const roiStart = Object.fromEntries(ensuredDims(0, CXYZT, indexStart))\n    const roiEnd = Object.fromEntries(ensuredDims(1, CXYZT, indexEnd))\n    validateIndices({ chunkStart, chunkEnd, roiStart, roiEnd })\n\n    // iterate on image from chunk or ROI start\n    const itStart = {\n      c: Math.max(chunkStart.c, roiStart.c),\n      z: Math.max(chunkStart.z, roiStart.z),\n      y: Math.max(chunkStart.y, roiStart.y),\n      x: Math.max(chunkStart.x, roiStart.x),\n    }\n    const itEnd = {\n      c: Math.min(chunkEnd.c, roiEnd.c),\n      z: Math.min(chunkEnd.z, roiEnd.z),\n      y: Math.min(chunkEnd.y, roiEnd.y),\n      x: Math.min(chunkEnd.x, roiEnd.x),\n    }\n\n    // write pixels at the start of the output image, not where they start in source image\n    const roiStartPixelOffset = Object.keys(pixelStrides).reduce(\n      (offset, dim) => offset + pixelStrides[dim] * roiStart[dim],\n      0\n    )\n\n    // Does input data group component(s) with each pixel?\n    const dims = Array.from(info.arrayShape.keys()).join('')\n    const areComponentsInterleaved =\n      dims.endsWith('xc') || (arrayShape.c === 1 && dims.endsWith('x')) // if one component, can end with just 'x'\n    // Input data endiennes matches system or just 1 byte?\n    const dataEndiennesOK =\n      getSize(info.dtype) === 1 ||\n      IS_SYSTEM_LITTLE_ENDIAN === testLittleEndian(info.dtype)\n\n    if (areComponentsInterleaved && dataEndiennesOK) {\n      // copy by row TURBO MODE\n      const TypedArray = getTypedArray(info.dtype)\n      const typedChunk = new TypedArray(chunks[index])\n      const offsetInChunkRow = (itStart.x - x * chunkSize.x) * chunkStrides.x\n      for (let zz = itStart.z; zz < itEnd.z; zz++) {\n        const zChunkOffset = (zz - z * chunkSize.z) * chunkStrides.z\n        const zPixelOffset = zz * pixelStrides.z - roiStartPixelOffset\n        for (let yy = itStart.y; yy < itEnd.y; yy++) {\n          const yChunkOffset =\n            offsetInChunkRow +\n            (yy - y * chunkSize.y) * chunkStrides.y +\n            zChunkOffset\n          const subarray = typedChunk.subarray(\n            yChunkOffset,\n            yChunkOffset + itEnd.c * (itEnd.x - itStart.x)\n          )\n          const pixelOffset =\n            itStart.x * pixelStrides.x + // chunk's x index mapped to image's x index\n            yy * pixelStrides.y +\n            zPixelOffset\n          pixelArray.set(subarray, pixelOffset)\n        } // row\n      } // slice\n    } else {\n      // copy by element tortoise mode\n      const getChunkElement = ElementGetter(info.dtype, chunks[index])\n      for (let cc = itStart.c; cc < itEnd.c; cc++) {\n        // subtract c * chunkSize.c from cc to start at beginning of chunk despite itStart.c\n        const cChunkOffset = (cc - c * chunkSize.c) * chunkStrides.c\n        for (let zz = itStart.z; zz < itEnd.z; zz++) {\n          const zChunkOffset =\n            (zz - z * chunkSize.z) * chunkStrides.z + cChunkOffset\n          const zPixelOffset = zz * pixelStrides.z + cc - roiStartPixelOffset\n          for (let yy = itStart.y; yy < itEnd.y; yy++) {\n            const yChunkOffset =\n              (yy - y * chunkSize.y) * chunkStrides.y + zChunkOffset\n            const yPixelOffset = yy * pixelStrides.y + zPixelOffset\n            for (let xx = itStart.x; xx < itEnd.x; xx++) {\n              pixelArray[xx * pixelStrides.x + yPixelOffset] = getChunkElement(\n                (xx - x * chunkSize.x) * chunkStrides.x + yChunkOffset\n              )\n            } // column\n          } // row\n        } // slice\n      } // component\n    } // copy by row or element\n  } // chunk\n\n  return pixelArray\n}\n\nregisterWebworker().operation('imageDataFromChunks', async chunkInfo => {\n  const pixelArray = makeImageDataFromChunks(chunkInfo)\n\n  const ranges = chunkInfo.areRangesNeeded\n    ? (\n        await computeRanges(\n          pixelArray,\n          chunkInfo.scaleInfo.arrayShape.get('c') ?? 1\n        )\n      ).map(({ min, max }) => [min, max])\n    : undefined\n\n  const response = { pixelArray, ranges }\n  return haveSharedArrayBuffer\n    ? response\n    : new registerWebworker.TransferableResponse(response, [pixelArray.buffer])\n})\n"
  },
  {
    "path": "src/IO/InMemoryMultiscaleSpatialImage.js",
    "content": "import MultiscaleSpatialImage, {\n  ensure3dDirection,\n  storeImage,\n} from './MultiscaleSpatialImage'\nimport componentTypeToTypedArray from './componentTypeToTypedArray'\n\nimport {\n  WorkerPool,\n  runPipeline,\n  InterfaceTypes,\n  imageSharedBufferOrCopy,\n  stackImages,\n} from 'itk-wasm'\nimport { chunkArray, CXYZT, orderBy, toDimensionMap } from './dimensionUtils'\nimport { computeRanges } from './Analyze/computeRanges'\n\nconst numberOfWorkers = navigator.hardwareConcurrency\n  ? navigator.hardwareConcurrency\n  : 6\nconst downsampleWorkerPool = new WorkerPool(numberOfWorkers, runPipeline)\n\nclass Coords {\n  constructor(image, dims) {\n    this.coords = new Map()\n    let spatialDimIndex = 0\n    if (dims[0] == 'c') {\n      spatialDimIndex = 1\n      const coord = new Uint16Array(image.imageType.components)\n      for (let c = 0; c < image.imageType.components; c++) {\n        coord[c] = c\n      }\n      this.coords.set('c', coord)\n    }\n    let spatialIndex = 0\n    for (let d = spatialDimIndex; d < dims.length; d++) {\n      const size = image.size[spatialIndex]\n      const origin = image.origin[spatialIndex]\n      const spacing = image.spacing[spatialIndex]\n      const coord = new Float64Array(size)\n      for (let i = 0; i < size; i++) {\n        coord[i] = origin + i * spacing\n      }\n      this.coords.set(dims[d], coord)\n      spatialIndex++\n    }\n  }\n\n  async get(coord) {\n    return this.coords.get(coord)\n  }\n\n  has(coord) {\n    return this.coords.has(coord)\n  }\n}\n\nasync function chunkImage(image, chunkSize) {\n  const imageType = image.imageType\n  const componentType = imageType.componentType\n\n  const dims = ['y', 'x']\n  const sizeCXYZTElements = [\n    imageType.components,\n    image.size[0],\n    image.size[1],\n    1,\n    1,\n  ]\n  const sizeCXYZTChunks = [\n    imageType.components,\n    chunkSize[0],\n    chunkSize[1],\n    1,\n    1,\n  ]\n\n  if (imageType.components > 1) {\n    dims.push('c')\n  }\n\n  if (imageType.dimension == 3) {\n    dims.unshift('z')\n    sizeCXYZTElements[3] = image.size[2]\n    sizeCXYZTChunks[3] = chunkSize[2]\n  }\n\n  const numberOfCXYZTChunks = [1, 1, 1, 1, 1]\n  for (let i = 0; i < numberOfCXYZTChunks.length; i++) {\n    numberOfCXYZTChunks[i] = Math.ceil(\n      sizeCXYZTElements[i] / sizeCXYZTChunks[i]\n    )\n  }\n  const chunksStride = new Array(5)\n  chunksStride[0] = 1\n  chunksStride[1] = 1 * numberOfCXYZTChunks[0]\n  chunksStride[2] = 1 * numberOfCXYZTChunks[0] * numberOfCXYZTChunks[1]\n  chunksStride[3] =\n    1 * numberOfCXYZTChunks[0] * numberOfCXYZTChunks[1] * numberOfCXYZTChunks[2]\n  chunksStride[4] =\n    1 *\n    numberOfCXYZTChunks[0] *\n    numberOfCXYZTChunks[1] *\n    numberOfCXYZTChunks[2] *\n    numberOfCXYZTChunks[3]\n  let chunks = new Array(\n    numberOfCXYZTChunks[0] *\n      numberOfCXYZTChunks[1] *\n      numberOfCXYZTChunks[2] *\n      numberOfCXYZTChunks[3] *\n      numberOfCXYZTChunks[4]\n  )\n  const dataStride = new Array(5)\n  dataStride[0] = 1\n  dataStride[1] = 1 * imageType.components\n  dataStride[2] = 1 * imageType.components * image.size[0]\n  dataStride[3] = 1 * imageType.components * image.size[0] * image.size[1]\n  dataStride[4] = dataStride[3]\n  const chunkType = componentTypeToTypedArray.get(componentType)\n  const chunkElements =\n    sizeCXYZTChunks[0] *\n    sizeCXYZTChunks[1] *\n    sizeCXYZTChunks[2] *\n    sizeCXYZTChunks[3] *\n    sizeCXYZTChunks[4]\n  const data = image.data\n  //const haveSharedArrayBuffer = typeof window.SharedArrayBuffer === 'function'\n  //if (haveSharedArrayBuffer && !data.buffer instanceof SharedArrayBuffer) {\n  //const sharedBuffer = new SharedArrayBuffer(data.buffer.byteLength) // eslint-disable-line\n  //const sharedTypedArray = new data.constructor(sharedBuffer)\n  //sharedTypedArray.set(data, 0)\n  //data = sharedTypedArray\n  //}\n  let offset = 0\n  const cxElements = sizeCXYZTChunks[0] * sizeCXYZTChunks[1]\n\n  const singleChunk = numberOfCXYZTChunks.every(e => e === 1)\n  if (singleChunk) {\n    chunks[0] = data\n  } else {\n    //if (haveSharedArrayBuffer) {\n    // Poorer performance\n    //if (false) {\n    //const taskArgs = new Array(chunks.length)\n    //for (let k = 0; k < numberOfCXYZTChunks[3]; k++) {\n    //const kOffset = k * sizeCXYZTChunks[3]\n    //for (let j = 0; j < numberOfCXYZTChunks[2]; j++) {\n    //const jOffset = j * sizeCXYZTChunks[2]\n    //for (let i = 0; i < numberOfCXYZTChunks[1]; i++) {\n    //const iOffset = i * sizeCXYZTChunks[1]\n    //taskArgs[offset] = [\n    //{\n    //data,\n    //componentType,\n    //chunkElements,\n    //cxElements,\n    //sizeCXYZTChunks,\n    //dataStride,\n    //kOffset,\n    //jOffset,\n    //iOffset,\n    //},\n    //]\n    //offset++\n    //} // for every x chunk\n    //} // for every y chunk\n    //} // for every z chunk\n    //// const result = await chunkerWorkerPool.runTasks(taskArgs).promise\n    //// chunks = result.map(e => e.chunk)\n    //} else {\n    for (let k = 0; k < numberOfCXYZTChunks[3]; k++) {\n      const kOffset = k * sizeCXYZTChunks[3]\n      for (let j = 0; j < numberOfCXYZTChunks[2]; j++) {\n        const jOffset = j * sizeCXYZTChunks[2]\n        for (let i = 0; i < numberOfCXYZTChunks[1]; i++) {\n          const iOffset = i * sizeCXYZTChunks[1]\n          const chunk = new chunkType(chunkElements)\n          let cxOffset = 0\n          for (let kk = 0; kk < sizeCXYZTChunks[3]; kk++) {\n            const kaOffset = dataStride[3] * (kOffset + kk)\n            for (let jj = 0; jj < sizeCXYZTChunks[2]; jj++) {\n              const jaOffset = kaOffset + dataStride[2] * (jOffset + jj)\n              const iaOffset = jaOffset + dataStride[1] * iOffset\n              const dataSlice = data.subarray(iaOffset, iaOffset + cxElements)\n              chunk.set(dataSlice, Math.min(cxOffset, chunk.length))\n              cxOffset += cxElements\n            }\n          }\n          chunks[offset] = chunk\n          offset++\n        } // for every x chunk\n      } // for every y chunk\n    } // for every z chunk\n    //}\n  }\n\n  const ranges = (\n    await computeRanges(image.data, sizeCXYZTElements[0])\n  ).map(({ min, max }) => [min, max])\n\n  const orderByDims = orderBy(dims)\n\n  const direction3d = ensure3dDirection(image.direction)\n\n  const scaleInfo = {\n    dims,\n    coords: new Coords(image, [...dims].reverse()), // Coords assumes xyz\n    chunkCount: orderByDims(toDimensionMap(CXYZT, numberOfCXYZTChunks)),\n    chunkSize: orderByDims(toDimensionMap(CXYZT, sizeCXYZTChunks)),\n    arrayShape: orderByDims(toDimensionMap(CXYZT, sizeCXYZTElements)),\n    ranges,\n    direction: chunkArray(3, [...direction3d].reverse()), // reverse to cast xyz to zyx\n  }\n\n  return { scaleInfo, chunksStride, chunks }\n}\n\nclass InMemoryMultiscaleSpatialImage extends MultiscaleSpatialImage {\n  static async buildPyramid(\n    image,\n    chunkSize = [64, 64, 64],\n    isLabelImage = false\n  ) {\n    const scale0 = await chunkImage(image, chunkSize)\n    const scaleInfo = [scale0.scaleInfo]\n    const pyramid = [\n      {\n        chunksStride: scale0.chunksStride,\n        chunks: scale0.chunks,\n        largestImage: image,\n      },\n    ]\n\n    let currentImage = image\n    const maxTotalSplits = Math.min(\n      parseInt(numberOfWorkers / 2),\n      Math.max(currentImage.size[currentImage.size.length - 1], 1)\n    )\n    const pipelinePath = isLabelImage ? 'DownsampleLabelImage' : 'Downsample'\n    while (\n      currentImage.size.reduce((a, c, i) => a || c / chunkSize[i] >= 2.0, false)\n    ) {\n      const factors = currentImage.size.map((s, i) => {\n        const n = Math.ceil(s / 2)\n        const factor = n >= chunkSize[i] ? 2 : 1\n        return factor\n      })\n\n      const downsampleTaskArgs = []\n      for (let index = 0; index < maxTotalSplits; index++) {\n        const data = imageSharedBufferOrCopy(currentImage)\n        const inputs = [\n          {\n            type: InterfaceTypes.Image,\n            data: data,\n          },\n        ]\n\n        const desiredOutputs = [\n          { type: InterfaceTypes.Image },\n          { type: InterfaceTypes.TextStream },\n        ]\n        const args = [\n          '0',\n          '0',\n          factors.join(','),\n          '--max-total-splits',\n          '' + maxTotalSplits,\n          '--split',\n          '' + index,\n          '--number-of-splits',\n          '' + maxTotalSplits,\n          '--memory-io',\n        ]\n        downsampleTaskArgs.push([pipelinePath, args, desiredOutputs, inputs])\n      }\n      const results = await downsampleWorkerPool.runTasks(downsampleTaskArgs)\n        .promise\n      const validResults = results.filter(r => r.returnValue === 0)\n      const imageSplits = validResults.map(({ outputs }) => outputs[0].data)\n      currentImage = stackImages(imageSplits)\n\n      const scaleN = await chunkImage(currentImage, chunkSize)\n      scaleInfo.push(scaleN.scaleInfo)\n      pyramid.push({\n        chunksStride: scaleN.chunksStride,\n        chunks: scaleN.chunks,\n        largestImage: currentImage,\n      })\n    }\n\n    // scale\n    const imageType = image.imageType\n    return { scaleInfo, imageType, pyramid }\n  }\n\n  constructor(pyramid, scaleInfo, imageType, name = 'Image') {\n    super(scaleInfo, imageType, name)\n    this.pyramid = pyramid\n\n    // cache whole images for getImage to retrieve\n    pyramid.forEach((data, scale) => {\n      storeImage({\n        cache: this.cachedImages,\n        scale,\n        bounds: this.getIndexBounds(scale),\n        image: data.largestImage,\n      })\n    })\n  }\n\n  async getChunksImpl(scale, cxyztArray) {\n    const result = new Array(cxyztArray.length)\n    const strides = this.pyramid[scale].chunksStride\n    const chunks = this.pyramid[scale].chunks\n    for (let i = 0; i < result.length; i++) {\n      const cxyzt = cxyztArray[i]\n      result[i] =\n        chunks[\n          cxyzt[0] * strides[0] +\n            cxyzt[1] * strides[1] +\n            cxyzt[2] * strides[2] +\n            cxyzt[3] * strides[3] +\n            cxyzt[4] * strides[4]\n        ]\n    }\n    return result.map(a => a.buffer)\n  }\n}\n\nexport default InMemoryMultiscaleSpatialImage\n"
  },
  {
    "path": "src/IO/MultiscaleSpatialImage.js",
    "content": "import { mat4, vec3 } from 'gl-matrix'\nimport { setMatrixElement } from 'itk-wasm'\n\nimport componentTypeToTypedArray from './componentTypeToTypedArray'\n\nimport WebworkerPromise from 'webworker-promise'\nimport { chunkArray, CXYZT, ensuredDims, orderBy } from './dimensionUtils'\nimport { getDtype } from './dtypeUtils'\nimport { transformBounds } from '../transformBounds'\nimport { makeIndexToWorld } from '../internalUtils'\n\nimport ImageDataFromChunksWorker from './ImageDataFromChunks.worker'\nconst imageDataFromChunksWorkerPromise = new WebworkerPromise(\n  new ImageDataFromChunksWorker()\n)\n\n/* Every element corresponds to a pyramid scale\n     Lower scales, corresponds to a higher index, correspond to a lower\n     resolution. \n\n  scaleInfo = [{\n    // scale 0 information\n    dims: ['x', 'y'], // Valid elements: 'c', 'x', 'y', 'z', or 't'\n    coords: .get() Promise resolves a Map('x': Float64Array([0.0, 2.0, ...), 'y' ...\n    chunkCount: Map('t': 1, 'c': 1, 'z': 10, 'y': 10, 'x': 10]), // array shape in chunks\n    chunkSize: Map('t': 1, 'c': 1, 'z': 1, 'y': 64, 'x': 64]), // chunk shape in elements\n    arrayShape: Map('t': 1, 'c': 1, 'z': 1, 'y': 64, 'x': 64]), // array shape in elements\n    ranges: Map('1': [0, 140], '2': [3, 130]) // or null if unknown. Range of values for each component\n    name: 'dataset_name'\n  },\n  { scale 1 information },\n  { scale N information }\n  ]\n*/\n\nfunction inflate(bounds, delta) {\n  bounds[0] -= delta\n  bounds[1] += delta\n  bounds[2] -= delta\n  bounds[3] += delta\n  bounds[4] -= delta\n  bounds[5] += delta\n  return bounds\n}\n\n// code modfied from vtk.js/ImageData\nconst extentToBounds = (ex, indexToWorld) => {\n  // prettier-ignore\n  const corners = [\n    ex[0], ex[2], ex[4],\n    ex[1], ex[2], ex[4],\n    ex[0], ex[3], ex[4],\n    ex[1], ex[3], ex[4],\n    ex[0], ex[2], ex[5],\n    ex[1], ex[2], ex[5],\n    ex[0], ex[3], ex[5],\n    ex[1], ex[3], ex[5]];\n\n  const idx = new Float64Array([corners[0], corners[1], corners[2]])\n  const vout = new Float64Array(3)\n  vec3.transformMat4(vout, idx, indexToWorld)\n  const bounds = [vout[0], vout[0], vout[1], vout[1], vout[2], vout[2]]\n  for (let i = 3; i < 24; i += 3) {\n    vec3.set(idx, corners[i], corners[i + 1], corners[i + 2])\n    vec3.transformMat4(vout, idx, indexToWorld)\n    if (vout[0] < bounds[0]) {\n      bounds[0] = vout[0]\n    }\n    if (vout[1] < bounds[2]) {\n      bounds[2] = vout[1]\n    }\n    if (vout[2] < bounds[4]) {\n      bounds[4] = vout[2]\n    }\n    if (vout[0] > bounds[1]) {\n      bounds[1] = vout[0]\n    }\n    if (vout[1] > bounds[3]) {\n      bounds[3] = vout[1]\n    }\n    if (vout[2] > bounds[5]) {\n      bounds[5] = vout[2]\n    }\n  }\n\n  return bounds\n}\n\nexport const ensure3dDirection = d => {\n  if (d.length >= 9) {\n    return d\n  }\n  // Pad 2D with Z dimension\n  return [d[0], d[1], 0, d[2], d[3], 0, 0, 0, 1]\n}\n\nexport const worldBoundsToIndexBounds = ({\n  bounds,\n  fullIndexBounds,\n  worldToIndex,\n}) => {\n  const fullIndexBoundsWithZCT = ensuredDims([0, 1], CXYZT, fullIndexBounds)\n  if (!bounds || bounds.length === 0) {\n    // no bounds, return full image\n    return fullIndexBoundsWithZCT\n  }\n\n  const imageBounds = transformBounds(worldToIndex, bounds)\n  // clamp to existing integer indexes\n  const imageBoundsByDim = chunkArray(2, imageBounds)\n  const spaceBounds = ['x', 'y', 'z'].map((dim, idx) => {\n    const [min, max] = fullIndexBoundsWithZCT.get(dim)\n    const [bmin, bmax] = imageBoundsByDim[idx]\n    return [\n      dim,\n      [\n        Math.floor(Math.min(max, Math.max(min, bmin))),\n        Math.ceil(Math.min(max, Math.max(min, bmax))),\n      ],\n    ]\n  })\n  const ctBounds = ['c', 't'].map(dim => [dim, fullIndexBoundsWithZCT.get(dim)])\n  return new Map([...spaceBounds, ...ctBounds])\n}\n\nfunction isContained(benchmarkBounds, testedBounds) {\n  return Array.from(benchmarkBounds).every(\n    ([dim, [benchmarkMin, benchmarkMax]]) => {\n      const [testedMin, testedMax] = testedBounds.get(dim)\n      return benchmarkMin <= testedMin && testedMax <= benchmarkMax\n    }\n  )\n}\n\nfunction findImageInBounds({ cache, scale, bounds }) {\n  const imagesAtScale = cache.get(scale) ?? []\n  return imagesAtScale.find(({ bounds: cachedBounds }) =>\n    isContained(cachedBounds, bounds)\n  )?.image\n}\n\nexport function storeImage({ cache, scale, bounds, image }) {\n  cache.set(scale, [{ bounds, image }])\n}\n\nclass MultiscaleSpatialImage {\n  scaleInfo = []\n  name = 'Image'\n\n  constructor(scaleInfo, imageType, name = 'Image') {\n    this.scaleInfo = scaleInfo\n    this.name = name\n\n    this.imageType = imageType\n    this.pixelArrayType = componentTypeToTypedArray.get(imageType.componentType)\n    this.spatialDims = ['x', 'y', 'z'].slice(0, imageType.dimension)\n    this.cachedImages = new Map()\n  }\n\n  get coarsestScale() {\n    return this.scaleInfo.length - 1\n  }\n\n  async scaleOrigin(scale) {\n    const info = this.scaleInfo[scale]\n    if (info.origin) return info.origin\n\n    const origin = new Array(this.spatialDims.length)\n    for (let index = 0; index < this.spatialDims.length; index++) {\n      const dim = this.spatialDims[index]\n      if (info.coords.has(dim)) {\n        const coords = await info.coords.get(dim)\n        origin[index] = coords[0]\n      } else {\n        origin[index] = 0.0\n      }\n    }\n    info.origin = origin\n    return origin\n  }\n\n  async scaleSpacing(scale) {\n    const info = this.scaleInfo[scale]\n    if (info.spacing) return info.spacing\n\n    const spacing = new Array(this.spatialDims.length)\n    for (let index = 0; index < this.spatialDims.length; index++) {\n      const dim = this.spatialDims[index]\n      const dimCoords = await info.coords.get(dim)\n      if (dimCoords && dimCoords.length >= 2) {\n        spacing[index] = dimCoords[1] - dimCoords[0]\n      } else {\n        spacing[index] = 1.0\n      }\n    }\n    info.spacing = spacing\n    return spacing\n  }\n\n  get direction() {\n    const dimension = this.imageType.dimension\n    const direction = new Float64Array(dimension * dimension)\n    // Direction should be consistent over scales\n    const infoDirection = this.scaleInfo[0].direction\n    if (infoDirection) {\n      // Todo: verify this logic\n      const dims = this.scaleInfo[0].dims\n      for (let d1 = 0; d1 < dimension; d1++) {\n        const sd1 = this.spatialDims[d1]\n        const di1 = dims.indexOf(sd1)\n        for (let d2 = 0; d2 < dimension; d2++) {\n          const sd2 = this.spatialDims[d2]\n          const di2 = dims.indexOf(sd2)\n          setMatrixElement(\n            direction,\n            dimension,\n            d1,\n            d2,\n            infoDirection[di1][di2]\n          )\n        }\n      }\n    } else {\n      direction.fill(0.0)\n      for (let d = 0; d < dimension; d++) {\n        setMatrixElement(direction, dimension, d, d, 1.0)\n      }\n    }\n    return direction\n  }\n\n  /* Return a promise that provides the requested chunk at a given scale and\n   * chunk index. */\n  async getChunks(scale, cxyztArray) {\n    return this.getChunksImpl(scale, cxyztArray)\n  }\n\n  async getChunksImpl(/* scale, cxyztArray */) {\n    console.error('Override me in a derived class')\n  }\n\n  async buildImage(scale, indexBounds) {\n    const { chunkSize, chunkCount, pixelArrayMetadata } = this.scaleInfo[scale]\n    const [indexToWorld, spacing] = await Promise.all([\n      this.scaleIndexToWorld(scale),\n      this.scaleSpacing(scale),\n    ])\n\n    const start = new Map(\n      CXYZT.map(dim => [dim, indexBounds.get(dim)?.[0] ?? 0])\n    )\n    const end = new Map(\n      CXYZT.map(dim => [dim, (indexBounds.get(dim)?.[1] ?? 0) + 1])\n    )\n\n    const arrayShape = new Map(\n      CXYZT.map(dim => [dim, end.get(dim) - start.get(dim)])\n    )\n\n    const startXYZ = ['x', 'y', 'z'].map(dim => start.get(dim))\n    const origin = vec3\n      .transformMat4([], startXYZ, indexToWorld)\n      .slice(0, this.imageType.dimension)\n\n    const chunkSizeWith1 = ensuredDims(1, CXYZT, chunkSize)\n    const l = 0\n    const zChunkStart = Math.floor(start.get('z') / chunkSizeWith1.get('z'))\n    const zChunkEnd = Math.ceil(end.get('z') / chunkSizeWith1.get('z'))\n    const yChunkStart = Math.floor(start.get('y') / chunkSizeWith1.get('y'))\n    const yChunkEnd = Math.ceil(end.get('y') / chunkSizeWith1.get('y'))\n    const xChunkStart = Math.floor(start.get('x') / chunkSizeWith1.get('x'))\n    const xChunkEnd = Math.ceil(end.get('x') / chunkSizeWith1.get('x'))\n    const cChunkStart = 0\n    const cChunkEnd = chunkCount.get('c') ?? 1\n\n    const chunkIndices = []\n    for (let k = zChunkStart; k < zChunkEnd; k++) {\n      for (let j = yChunkStart; j < yChunkEnd; j++) {\n        for (let i = xChunkStart; i < xChunkEnd; i++) {\n          for (let h = cChunkStart; h < cChunkEnd; h++) {\n            chunkIndices.push([h, i, j, k, l])\n          } // for every cChunk\n        } // for every xChunk\n      } // for every yChunk\n    } // for every zChunk\n\n    const chunks = await this.getChunks(scale, chunkIndices)\n\n    const preComputedRanges = this.scaleInfo[scale].ranges\n\n    const args = {\n      scaleInfo: {\n        chunkSize: chunkSizeWith1,\n        arrayShape,\n        dtype: pixelArrayMetadata?.dtype ?? getDtype(this.pixelArrayType),\n      },\n      imageType: this.imageType,\n      chunkIndices,\n      chunks,\n      indexStart: start,\n      indexEnd: end,\n      areRangesNeeded: !preComputedRanges,\n    }\n    const { pixelArray, ranges } = await imageDataFromChunksWorkerPromise.exec(\n      'imageDataFromChunks',\n      args\n    )\n\n    return {\n      imageType: this.imageType,\n      name: this.scaleInfo[scale].name,\n      origin,\n      spacing,\n      direction: this.direction,\n      size: ['x', 'y', 'z']\n        .slice(0, this.imageType.dimension)\n        .map(dim => arrayShape.get(dim)),\n      data: pixelArray,\n      ranges: preComputedRanges ?? ranges,\n    }\n  }\n\n  async scaleIndexToWorld(requestedScale) {\n    const scale = Math.min(requestedScale, this.scaleInfo.length - 1)\n    if (this.scaleInfo[scale].indexToWorld)\n      return this.scaleInfo[scale].indexToWorld\n\n    // compute and cache origin/scale on info\n    await Promise.all([this.scaleOrigin(scale), this.scaleSpacing(scale)])\n\n    const { spacing, origin } = this.scaleInfo[scale]\n    const direction = ensure3dDirection(this.direction)\n\n    this.scaleInfo[scale].indexToWorld = makeIndexToWorld({\n      direction,\n      origin,\n      spacing,\n    })\n    return this.scaleInfo[scale].indexToWorld\n  }\n\n  /* Retrieve bounded image at scale. */\n  async getImage(requestedScale, worldBounds = []) {\n    const scale = Math.min(requestedScale, this.scaleInfo.length - 1)\n    const indexToWorld = await this.scaleIndexToWorld(scale)\n\n    const { dims } = this.scaleInfo[scale]\n    const indexBounds = orderBy(dims)(\n      worldBoundsToIndexBounds({\n        bounds: worldBounds,\n        fullIndexBounds: this.getIndexBounds(scale),\n        worldToIndex: mat4.invert([], indexToWorld),\n      })\n    )\n\n    const cachedImage = findImageInBounds({\n      cache: this.cachedImages,\n      scale,\n      bounds: indexBounds,\n    })\n    if (cachedImage) return cachedImage\n\n    const image = await this.buildImage(scale, indexBounds)\n    storeImage({ cache: this.cachedImages, scale, bounds: indexBounds, image })\n    return image\n  }\n\n  getIndexBounds(requestedScale) {\n    const scale = Math.min(requestedScale, this.scaleInfo.length - 1)\n    const { arrayShape } = this.scaleInfo[scale]\n    return new Map(\n      Array.from(arrayShape).map(([dim, size]) => [dim, [0, size - 1]])\n    )\n  }\n\n  // indexToWorld will be undefined if getImage() not completed on scale first\n  getWorldBounds(requestedScale) {\n    // clap scale same as getImage for when comparing images\n    const scale = Math.min(requestedScale, this.scaleInfo.length - 1)\n    const { indexToWorld } = this.scaleInfo[scale]\n    const imageBounds = ensuredDims(\n      [0, 1],\n      ['x', 'y', 'z'],\n      this.getIndexBounds(scale)\n    )\n    const bounds = ['x', 'y', 'z'].flatMap(dim => imageBounds.get(dim))\n    inflate(bounds, 0.5)\n    return extentToBounds(bounds, indexToWorld)\n  }\n}\n\nexport default MultiscaleSpatialImage\n"
  },
  {
    "path": "src/IO/ResampleLabelImage/.gitignore",
    "content": "/emscripten-build/*\n!emscripten-build/ResampleLabelImage*\nresample.png"
  },
  {
    "path": "src/IO/ResampleLabelImage/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.16)\nproject(ResampleLabelImage)\n\nset(CMAKE_CXX_STANDARD 17)\n\nset(io_components)\nif (NOT EMSCRIPTEN AND NOT WASI)\n  set(io_components\n    ITKIOPNG\n    ITKIOMeta\n    ITKIONRRD\n    )\nendif()\nfind_package(ITK REQUIRED\n  COMPONENTS\n    ${io_components}\n    WebAssemblyInterface\n    ITKImageGrid\n    ITKImageFunction\n    GenericLabelInterpolator\n  )\ninclude(${ITK_USE_FILE})\n\nadd_executable(ResampleLabelImage ResampleLabelImage.cxx)\ntarget_link_libraries(ResampleLabelImage PUBLIC ${ITK_LIBRARIES})\n\n"
  },
  {
    "path": "src/IO/ResampleLabelImage/ResampleLabelImage.cxx",
    "content": "/*=========================================================================\n *\n *  Copyright NumFOCUS\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *         http://www.apache.org/licenses/LICENSE-2.0.txt\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n *\n *=========================================================================*/\n#include \"itkBinShrinkImageFilter.h\"\n#include \"itkVectorImage.h\"\n#include \"itkResampleImageFilter.h\"\n#include \"itkLabelImageGenericInterpolateImageFunction.h\"\n#include \"itkLinearInterpolateImageFunction.h\"\n#include \"itkImageRegionSplitterSlowDimension.h\"\n#include \"itkExtractImageFilter.h\"\n#include \"itkRGBPixel.h\"\n#include \"itkRGBAPixel.h\"\n#include \"itkVectorImage.h\"\n#include \"itkOffset.h\"\n#include \"itkVector.h\"\n#include \"itkPoint.h\"\n#include \"itkCovariantVector.h\"\n#include \"itkSymmetricSecondRankTensor.h\"\n#include \"itkDiffusionTensor3D.h\"\n#include <complex>\n#include \"itkFixedArray.h\"\n#include \"itkArray.h\"\n#include \"itkMatrix.h\"\n#include \"itkVariableLengthVector.h\"\n#include \"itkVariableSizeMatrix.h\"\n#include <fstream>\n#include \"itkPipeline.h\"\n#include \"itkInputImage.h\"\n#include \"itkOutputImage.h\"\n#include \"itkOutputTextStream.h\"\n#include \"itkSupportInputImageTypes.h\"\n\ntemplate <typename TImage>\nint ResampleLabelImage(itk::wasm::Pipeline &pipeline, itk::wasm::InputImage<TImage> &inputImage)\n{\n  using ImageType = TImage;\n\n  pipeline.get_option(\"InputImage\")->required();\n\n  using OutputImageType = itk::wasm::OutputImage<ImageType>;\n  OutputImageType outputImage;\n  pipeline.add_option(\"OutputImage\", outputImage, \"Output image\")->required();\n\n  std::vector<unsigned int> outSize;\n  pipeline.add_option(\"-z,--size\", outSize, \"New image size for each direction\")->expected(2, 3)->delimiter(',');\n\n  std::vector<double> outSpacing;\n  pipeline.add_option(\"-p,--spacing\", outSpacing, \"New image spacing for each direction\")->expected(2, 3)->delimiter(',');\n\n  std::vector<double> outOrigin;\n  pipeline.add_option(\"-o,--origin\", outOrigin, \"New image origin for each direction\")->expected(2, 3)->delimiter(',');\n\n  std::vector<double> outDirection;\n  pipeline.add_option(\"-d,--direction\", outDirection, \"New image direction\")->expected(4, 9)->delimiter(',');\n\n  // split args\n  unsigned int maxTotalSplits = 1;\n  pipeline.add_option(\"-m,--max-total-splits\", maxTotalSplits, \"Maximum total splits when processed in parallel\");\n\n  unsigned int split = 0;\n  pipeline.add_option(\"-s,--split\", split, \"Current processed split\");\n\n  itk::wasm::OutputTextStream numberOfSplitsStream;\n  auto numberOfSplitsStreamOption = pipeline.add_option(\"--number-of-splits\", numberOfSplitsStream, \"Number of splits\");\n\n  ITK_WASM_PARSE(pipeline);\n\n  auto inImage = inputImage.Get();\n\n  using ResampleFilterType = itk::ResampleImageFilter<ImageType, ImageType>;\n  auto resampleFilter = ResampleFilterType::New();\n  resampleFilter->SetInput(inImage);\n\n  using InterpolatorType = itk::LabelImageGenericInterpolateImageFunction<ImageType, itk::LinearInterpolateImageFunction>;\n  resampleFilter->SetInterpolator(InterpolatorType::New());\n\n  typename ImageType::SizeType outputSize;\n  typename ImageType::SpacingType outputSpacing;\n  typename ImageType::PointType outputOrigin;\n  const int dims = outputSize.size();\n  for (int i = 0; i < dims; ++i)\n  {\n    outputSize[i] = outSize[i];\n    outputSpacing[i] = outSpacing[i];\n    outputOrigin[i] = outOrigin[i];\n  }\n  resampleFilter->SetSize(outputSize);\n  resampleFilter->SetOutputSpacing(outputSpacing);\n  resampleFilter->SetOutputOrigin(outputOrigin);\n\n  typename ImageType::DirectionType outputDirection;\n  for (int row = 0; row < dims; ++row)\n  {\n    for (int col = 0; col < dims; ++col)\n    {\n      outputDirection(row, col) = outDirection[row * dims + col];\n    }\n  }\n\n  resampleFilter->SetOutputDirection(outputDirection);\n\n  // Split handling\n  using ROIFilterType = itk::ExtractImageFilter<ImageType, ImageType>;\n  resampleFilter->UpdateOutputInformation();\n  using RegionType = typename ImageType::RegionType;\n  const RegionType largestRegion(resampleFilter->GetOutput()->GetLargestPossibleRegion());\n\n  using SplitterType = itk::ImageRegionSplitterSlowDimension;\n  auto splitter = SplitterType::New();\n  const unsigned int numberOfSplits = splitter->GetNumberOfSplits(largestRegion, maxTotalSplits);\n\n  if (split >= numberOfSplits)\n  {\n    std::cerr << \"Error: requested split: \" << split << \" is outside the number of splits: \" << numberOfSplits << std::endl;\n    return EXIT_FAILURE;\n  }\n\n  if (!numberOfSplitsStreamOption->empty())\n  {\n    numberOfSplitsStream.Get() << numberOfSplits;\n  }\n\n  RegionType requestedRegion(largestRegion);\n  splitter->GetSplit(split, numberOfSplits, requestedRegion);\n  auto roiFilter = ROIFilterType::New();\n  roiFilter->SetExtractionRegion(requestedRegion);\n  roiFilter->SetInput(resampleFilter->GetOutput());\n\n  try\n  {\n    roiFilter->Update();\n  }\n  catch (std::exception &error)\n  {\n    std::cerr << \"Error: \" << error.what() << std::endl;\n    return EXIT_FAILURE;\n  }\n\n  outputImage.Set(roiFilter->GetOutput());\n\n  return EXIT_SUCCESS;\n}\n\ntemplate <typename TImage>\nclass PipelineFunctor\n{\npublic:\n  int operator()(itk::wasm::Pipeline &pipeline)\n  {\n    using ImageType = TImage;\n\n    using InputImageType = itk::wasm::InputImage<ImageType>;\n    InputImageType inputImage;\n    pipeline.add_option(\"InputImage\", inputImage, \"Input image\");\n\n    ITK_WASM_PRE_PARSE(pipeline);\n\n    return ResampleLabelImage<ImageType>(pipeline, inputImage);\n  }\n};\n\nint main(int argc, char *argv[])\n{\n  itk::wasm::Pipeline pipeline(\"ResampleLabelImage\", \"Resample a label image\", argc, argv);\n\n  return itk::wasm::SupportInputImageTypes<PipelineFunctor,\n                                           uint8_t,\n                                           int8_t,\n                                           uint16_t,\n                                           int16_t,\n                                           uint32_t,\n                                           int32_t,\n                                           uint64_t,\n                                           int64_t,\n                                           float,\n                                           double>::Dimensions<2U, 3U>(\"InputImage\", pipeline);\n}\n"
  },
  {
    "path": "src/IO/ResampleLabelImage/emscripten-build/ResampleLabelImage.js",
    "content": "var ResampleLabelImage = (() => {\n  var _scriptDir = import.meta.url\n\n  return async function(ResampleLabelImage) {\n    ResampleLabelImage = ResampleLabelImage || {}\n\n    var Module =\n      typeof ResampleLabelImage != 'undefined' ? ResampleLabelImage : {}\n    var readyPromiseResolve, readyPromiseReject\n    Module['ready'] = new Promise(function(resolve, reject) {\n      readyPromiseResolve = resolve\n      readyPromiseReject = reject\n    })\n    var mStdout = null\n    var mStderr = null\n    Module['resetModuleStdout'] = function() {\n      mStdout = ''\n    }\n    Module['resetModuleStderr'] = function() {\n      mStderr = ''\n    }\n    Module['print'] = function(text) {\n      console.log(text)\n      mStdout += text + '\\n'\n    }\n    Module['printErr'] = function(text) {\n      console.error(text)\n      mStderr += text + '\\n'\n    }\n    Module['getModuleStdout'] = function() {\n      return mStdout\n    }\n    Module['getModuleStderr'] = function() {\n      return mStderr\n    }\n    var moduleOverrides = Object.assign({}, Module)\n    var arguments_ = []\n    var thisProgram = './this.program'\n    var quit_ = (status, toThrow) => {\n      throw toThrow\n    }\n    var ENVIRONMENT_IS_WEB = typeof window == 'object'\n    var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'\n    var ENVIRONMENT_IS_NODE =\n      typeof process == 'object' &&\n      typeof process.versions == 'object' &&\n      typeof process.versions.node == 'string'\n    var scriptDirectory = ''\n    function locateFile(path) {\n      if (Module['locateFile']) {\n        return Module['locateFile'](path, scriptDirectory)\n      }\n      return scriptDirectory + path\n    }\n    var read_, readAsync, readBinary, setWindowTitle\n    function logExceptionOnExit(e) {\n      if (e instanceof ExitStatus) return\n      let toLog = e\n      err('exiting due to exception: ' + toLog)\n    }\n    if (ENVIRONMENT_IS_NODE) {\n      const { createRequire: createRequire } = await import('module')\n      var require = createRequire(import.meta.url)\n      var fs = require('fs')\n      var nodePath = require('path')\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = nodePath.dirname(scriptDirectory) + '/'\n      } else {\n        scriptDirectory = require('url').fileURLToPath(\n          new URL('./', import.meta.url)\n        )\n      }\n      read_ = (filename, binary) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        return fs.readFileSync(filename, binary ? undefined : 'utf8')\n      }\n      readBinary = filename => {\n        var ret = read_(filename, true)\n        if (!ret.buffer) {\n          ret = new Uint8Array(ret)\n        }\n        return ret\n      }\n      readAsync = (filename, onload, onerror) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        fs.readFile(filename, function(err, data) {\n          if (err) onerror(err)\n          else onload(data.buffer)\n        })\n      }\n      if (process['argv'].length > 1) {\n        thisProgram = process['argv'][1].replace(/\\\\/g, '/')\n      }\n      arguments_ = process['argv'].slice(2)\n      process['on']('uncaughtException', function(ex) {\n        if (!(ex instanceof ExitStatus)) {\n          throw ex\n        }\n      })\n      process['on']('unhandledRejection', function(reason) {\n        throw reason\n      })\n      quit_ = (status, toThrow) => {\n        if (keepRuntimeAlive()) {\n          process['exitCode'] = status\n          throw toThrow\n        }\n        logExceptionOnExit(toThrow)\n        process['exit'](status)\n      }\n      Module['inspect'] = function() {\n        return '[Emscripten Module object]'\n      }\n    } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = self.location.href\n      } else if (typeof document != 'undefined' && document.currentScript) {\n        scriptDirectory = document.currentScript.src\n      }\n      if (_scriptDir) {\n        scriptDirectory = _scriptDir\n      }\n      if (scriptDirectory.indexOf('blob:') !== 0) {\n        scriptDirectory = scriptDirectory.substr(\n          0,\n          scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1\n        )\n      } else {\n        scriptDirectory = ''\n      }\n      {\n        read_ = url => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, false)\n          xhr.send(null)\n          return xhr.responseText\n        }\n        if (ENVIRONMENT_IS_WORKER) {\n          readBinary = url => {\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            xhr.responseType = 'arraybuffer'\n            xhr.send(null)\n            return new Uint8Array(xhr.response)\n          }\n        }\n        readAsync = (url, onload, onerror) => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, true)\n          xhr.responseType = 'arraybuffer'\n          xhr.onload = () => {\n            if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n              onload(xhr.response)\n              return\n            }\n            onerror()\n          }\n          xhr.onerror = onerror\n          xhr.send(null)\n        }\n      }\n      setWindowTitle = title => (document.title = title)\n    } else {\n    }\n    var out = Module['print'] || console.log.bind(console)\n    var err = Module['printErr'] || console.warn.bind(console)\n    Object.assign(Module, moduleOverrides)\n    moduleOverrides = null\n    if (Module['arguments']) arguments_ = Module['arguments']\n    if (Module['thisProgram']) thisProgram = Module['thisProgram']\n    if (Module['quit']) quit_ = Module['quit']\n    var wasmBinary\n    if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']\n    var noExitRuntime = Module['noExitRuntime'] || true\n    if (typeof WebAssembly != 'object') {\n      abort('no native wasm support detected')\n    }\n    var wasmMemory\n    var ABORT = false\n    var EXITSTATUS\n    function assert(condition, text) {\n      if (!condition) {\n        abort(text)\n      }\n    }\n    var UTF8Decoder =\n      typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined\n    function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {\n      var endIdx = idx + maxBytesToRead\n      var endPtr = idx\n      while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr\n      if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {\n        return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr))\n      }\n      var str = ''\n      while (idx < endPtr) {\n        var u0 = heapOrArray[idx++]\n        if (!(u0 & 128)) {\n          str += String.fromCharCode(u0)\n          continue\n        }\n        var u1 = heapOrArray[idx++] & 63\n        if ((u0 & 224) == 192) {\n          str += String.fromCharCode(((u0 & 31) << 6) | u1)\n          continue\n        }\n        var u2 = heapOrArray[idx++] & 63\n        if ((u0 & 240) == 224) {\n          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2\n        } else {\n          u0 =\n            ((u0 & 7) << 18) |\n            (u1 << 12) |\n            (u2 << 6) |\n            (heapOrArray[idx++] & 63)\n        }\n        if (u0 < 65536) {\n          str += String.fromCharCode(u0)\n        } else {\n          var ch = u0 - 65536\n          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023))\n        }\n      }\n      return str\n    }\n    function UTF8ToString(ptr, maxBytesToRead) {\n      return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''\n    }\n    function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {\n      if (!(maxBytesToWrite > 0)) return 0\n      var startIdx = outIdx\n      var endIdx = outIdx + maxBytesToWrite - 1\n      for (var i = 0; i < str.length; ++i) {\n        var u = str.charCodeAt(i)\n        if (u >= 55296 && u <= 57343) {\n          var u1 = str.charCodeAt(++i)\n          u = (65536 + ((u & 1023) << 10)) | (u1 & 1023)\n        }\n        if (u <= 127) {\n          if (outIdx >= endIdx) break\n          heap[outIdx++] = u\n        } else if (u <= 2047) {\n          if (outIdx + 1 >= endIdx) break\n          heap[outIdx++] = 192 | (u >> 6)\n          heap[outIdx++] = 128 | (u & 63)\n        } else if (u <= 65535) {\n          if (outIdx + 2 >= endIdx) break\n          heap[outIdx++] = 224 | (u >> 12)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        } else {\n          if (outIdx + 3 >= endIdx) break\n          heap[outIdx++] = 240 | (u >> 18)\n          heap[outIdx++] = 128 | ((u >> 12) & 63)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        }\n      }\n      heap[outIdx] = 0\n      return outIdx - startIdx\n    }\n    function stringToUTF8(str, outPtr, maxBytesToWrite) {\n      return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite)\n    }\n    function lengthBytesUTF8(str) {\n      var len = 0\n      for (var i = 0; i < str.length; ++i) {\n        var c = str.charCodeAt(i)\n        if (c <= 127) {\n          len++\n        } else if (c <= 2047) {\n          len += 2\n        } else if (c >= 55296 && c <= 57343) {\n          len += 4\n          ++i\n        } else {\n          len += 3\n        }\n      }\n      return len\n    }\n    var buffer,\n      HEAP8,\n      HEAPU8,\n      HEAP16,\n      HEAPU16,\n      HEAP32,\n      HEAPU32,\n      HEAPF32,\n      HEAPF64\n    function updateGlobalBufferAndViews(buf) {\n      buffer = buf\n      Module['HEAP8'] = HEAP8 = new Int8Array(buf)\n      Module['HEAP16'] = HEAP16 = new Int16Array(buf)\n      Module['HEAP32'] = HEAP32 = new Int32Array(buf)\n      Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf)\n      Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf)\n      Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf)\n      Module['HEAPF32'] = HEAPF32 = new Float32Array(buf)\n      Module['HEAPF64'] = HEAPF64 = new Float64Array(buf)\n    }\n    var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216\n    var wasmTable\n    var __ATPRERUN__ = []\n    var __ATINIT__ = []\n    var __ATMAIN__ = []\n    var __ATPOSTRUN__ = []\n    var runtimeInitialized = false\n    function keepRuntimeAlive() {\n      return noExitRuntime\n    }\n    function preRun() {\n      if (Module['preRun']) {\n        if (typeof Module['preRun'] == 'function')\n          Module['preRun'] = [Module['preRun']]\n        while (Module['preRun'].length) {\n          addOnPreRun(Module['preRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPRERUN__)\n    }\n    function initRuntime() {\n      runtimeInitialized = true\n      if (!Module['noFSInit'] && !FS.init.initialized) FS.init()\n      FS.ignorePermissions = false\n      TTY.init()\n      callRuntimeCallbacks(__ATINIT__)\n    }\n    function preMain() {\n      callRuntimeCallbacks(__ATMAIN__)\n    }\n    function postRun() {\n      if (Module['postRun']) {\n        if (typeof Module['postRun'] == 'function')\n          Module['postRun'] = [Module['postRun']]\n        while (Module['postRun'].length) {\n          addOnPostRun(Module['postRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPOSTRUN__)\n    }\n    function addOnPreRun(cb) {\n      __ATPRERUN__.unshift(cb)\n    }\n    function addOnInit(cb) {\n      __ATINIT__.unshift(cb)\n    }\n    function addOnPostRun(cb) {\n      __ATPOSTRUN__.unshift(cb)\n    }\n    var runDependencies = 0\n    var runDependencyWatcher = null\n    var dependenciesFulfilled = null\n    function getUniqueRunDependency(id) {\n      return id\n    }\n    function addRunDependency(id) {\n      runDependencies++\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n    }\n    function removeRunDependency(id) {\n      runDependencies--\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n      if (runDependencies == 0) {\n        if (runDependencyWatcher !== null) {\n          clearInterval(runDependencyWatcher)\n          runDependencyWatcher = null\n        }\n        if (dependenciesFulfilled) {\n          var callback = dependenciesFulfilled\n          dependenciesFulfilled = null\n          callback()\n        }\n      }\n    }\n    function abort(what) {\n      if (Module['onAbort']) {\n        Module['onAbort'](what)\n      }\n      what = 'Aborted(' + what + ')'\n      err(what)\n      ABORT = true\n      EXITSTATUS = 1\n      what += '. Build with -sASSERTIONS for more info.'\n      var e = new WebAssembly.RuntimeError(what)\n      readyPromiseReject(e)\n      throw e\n    }\n    var dataURIPrefix = 'data:application/octet-stream;base64,'\n    function isDataURI(filename) {\n      return filename.startsWith(dataURIPrefix)\n    }\n    function isFileURI(filename) {\n      return filename.startsWith('file://')\n    }\n    var wasmBinaryFile\n    if (Module['locateFile']) {\n      wasmBinaryFile = 'ResampleLabelImage.wasm'\n      if (!isDataURI(wasmBinaryFile)) {\n        wasmBinaryFile = locateFile(wasmBinaryFile)\n      }\n    } else {\n      wasmBinaryFile = new URL('ResampleLabelImage.wasm', import.meta.url).href\n    }\n    function getBinary(file) {\n      try {\n        if (file == wasmBinaryFile && wasmBinary) {\n          return new Uint8Array(wasmBinary)\n        }\n        if (readBinary) {\n          return readBinary(file)\n        }\n        throw 'both async and sync fetching of the wasm failed'\n      } catch (err) {\n        abort(err)\n      }\n    }\n    function getBinaryPromise() {\n      if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {\n        if (typeof fetch == 'function' && !isFileURI(wasmBinaryFile)) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' })\n            .then(function(response) {\n              if (!response['ok']) {\n                throw \"failed to load wasm binary file at '\" +\n                  wasmBinaryFile +\n                  \"'\"\n              }\n              return response['arrayBuffer']()\n            })\n            .catch(function() {\n              return getBinary(wasmBinaryFile)\n            })\n        } else {\n          if (readAsync) {\n            return new Promise(function(resolve, reject) {\n              readAsync(\n                wasmBinaryFile,\n                function(response) {\n                  resolve(new Uint8Array(response))\n                },\n                reject\n              )\n            })\n          }\n        }\n      }\n      return Promise.resolve().then(function() {\n        return getBinary(wasmBinaryFile)\n      })\n    }\n    function createWasm() {\n      var info = { a: asmLibraryArg }\n      function receiveInstance(instance, module) {\n        var exports = instance.exports\n        Module['asm'] = exports\n        wasmMemory = Module['asm']['s']\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        wasmTable = Module['asm']['D']\n        addOnInit(Module['asm']['t'])\n        removeRunDependency('wasm-instantiate')\n      }\n      addRunDependency('wasm-instantiate')\n      function receiveInstantiationResult(result) {\n        receiveInstance(result['instance'])\n      }\n      function instantiateArrayBuffer(receiver) {\n        return getBinaryPromise()\n          .then(function(binary) {\n            return WebAssembly.instantiate(binary, info)\n          })\n          .then(function(instance) {\n            return instance\n          })\n          .then(receiver, function(reason) {\n            err('failed to asynchronously prepare wasm: ' + reason)\n            abort(reason)\n          })\n      }\n      function instantiateAsync() {\n        if (\n          !wasmBinary &&\n          typeof WebAssembly.instantiateStreaming == 'function' &&\n          !isDataURI(wasmBinaryFile) &&\n          !isFileURI(wasmBinaryFile) &&\n          !ENVIRONMENT_IS_NODE &&\n          typeof fetch == 'function'\n        ) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(\n            function(response) {\n              var result = WebAssembly.instantiateStreaming(response, info)\n              return result.then(receiveInstantiationResult, function(reason) {\n                err('wasm streaming compile failed: ' + reason)\n                err('falling back to ArrayBuffer instantiation')\n                return instantiateArrayBuffer(receiveInstantiationResult)\n              })\n            }\n          )\n        } else {\n          return instantiateArrayBuffer(receiveInstantiationResult)\n        }\n      }\n      if (Module['instantiateWasm']) {\n        try {\n          var exports = Module['instantiateWasm'](info, receiveInstance)\n          return exports\n        } catch (e) {\n          err('Module.instantiateWasm callback failed with error: ' + e)\n          readyPromiseReject(e)\n        }\n      }\n      instantiateAsync().catch(readyPromiseReject)\n      return {}\n    }\n    var tempDouble\n    var tempI64\n    function ExitStatus(status) {\n      this.name = 'ExitStatus'\n      this.message = 'Program terminated with exit(' + status + ')'\n      this.status = status\n    }\n    function callRuntimeCallbacks(callbacks) {\n      while (callbacks.length > 0) {\n        callbacks.shift()(Module)\n      }\n    }\n    function ExceptionInfo(excPtr) {\n      this.excPtr = excPtr\n      this.ptr = excPtr - 24\n      this.set_type = function(type) {\n        HEAPU32[(this.ptr + 4) >> 2] = type\n      }\n      this.get_type = function() {\n        return HEAPU32[(this.ptr + 4) >> 2]\n      }\n      this.set_destructor = function(destructor) {\n        HEAPU32[(this.ptr + 8) >> 2] = destructor\n      }\n      this.get_destructor = function() {\n        return HEAPU32[(this.ptr + 8) >> 2]\n      }\n      this.set_refcount = function(refcount) {\n        HEAP32[this.ptr >> 2] = refcount\n      }\n      this.set_caught = function(caught) {\n        caught = caught ? 1 : 0\n        HEAP8[(this.ptr + 12) >> 0] = caught\n      }\n      this.get_caught = function() {\n        return HEAP8[(this.ptr + 12) >> 0] != 0\n      }\n      this.set_rethrown = function(rethrown) {\n        rethrown = rethrown ? 1 : 0\n        HEAP8[(this.ptr + 13) >> 0] = rethrown\n      }\n      this.get_rethrown = function() {\n        return HEAP8[(this.ptr + 13) >> 0] != 0\n      }\n      this.init = function(type, destructor) {\n        this.set_adjusted_ptr(0)\n        this.set_type(type)\n        this.set_destructor(destructor)\n        this.set_refcount(0)\n        this.set_caught(false)\n        this.set_rethrown(false)\n      }\n      this.add_ref = function() {\n        var value = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = value + 1\n      }\n      this.release_ref = function() {\n        var prev = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = prev - 1\n        return prev === 1\n      }\n      this.set_adjusted_ptr = function(adjustedPtr) {\n        HEAPU32[(this.ptr + 16) >> 2] = adjustedPtr\n      }\n      this.get_adjusted_ptr = function() {\n        return HEAPU32[(this.ptr + 16) >> 2]\n      }\n      this.get_exception_ptr = function() {\n        var isPointer = ___cxa_is_pointer_type(this.get_type())\n        if (isPointer) {\n          return HEAPU32[this.excPtr >> 2]\n        }\n        var adjusted = this.get_adjusted_ptr()\n        if (adjusted !== 0) return adjusted\n        return this.excPtr\n      }\n    }\n    var exceptionLast = 0\n    var uncaughtExceptionCount = 0\n    function ___cxa_throw(ptr, type, destructor) {\n      var info = new ExceptionInfo(ptr)\n      info.init(type, destructor)\n      exceptionLast = ptr\n      uncaughtExceptionCount++\n      throw ptr\n    }\n    function setErrNo(value) {\n      HEAP32[___errno_location() >> 2] = value\n      return value\n    }\n    var PATH = {\n      isAbs: path => path.charAt(0) === '/',\n      splitPath: filename => {\n        var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/\n        return splitPathRe.exec(filename).slice(1)\n      },\n      normalizeArray: (parts, allowAboveRoot) => {\n        var up = 0\n        for (var i = parts.length - 1; i >= 0; i--) {\n          var last = parts[i]\n          if (last === '.') {\n            parts.splice(i, 1)\n          } else if (last === '..') {\n            parts.splice(i, 1)\n            up++\n          } else if (up) {\n            parts.splice(i, 1)\n            up--\n          }\n        }\n        if (allowAboveRoot) {\n          for (; up; up--) {\n            parts.unshift('..')\n          }\n        }\n        return parts\n      },\n      normalize: path => {\n        var isAbsolute = PATH.isAbs(path),\n          trailingSlash = path.substr(-1) === '/'\n        path = PATH.normalizeArray(\n          path.split('/').filter(p => !!p),\n          !isAbsolute\n        ).join('/')\n        if (!path && !isAbsolute) {\n          path = '.'\n        }\n        if (path && trailingSlash) {\n          path += '/'\n        }\n        return (isAbsolute ? '/' : '') + path\n      },\n      dirname: path => {\n        var result = PATH.splitPath(path),\n          root = result[0],\n          dir = result[1]\n        if (!root && !dir) {\n          return '.'\n        }\n        if (dir) {\n          dir = dir.substr(0, dir.length - 1)\n        }\n        return root + dir\n      },\n      basename: path => {\n        if (path === '/') return '/'\n        path = PATH.normalize(path)\n        path = path.replace(/\\/$/, '')\n        var lastSlash = path.lastIndexOf('/')\n        if (lastSlash === -1) return path\n        return path.substr(lastSlash + 1)\n      },\n      join: function() {\n        var paths = Array.prototype.slice.call(arguments)\n        return PATH.normalize(paths.join('/'))\n      },\n      join2: (l, r) => {\n        return PATH.normalize(l + '/' + r)\n      },\n    }\n    function getRandomDevice() {\n      if (\n        typeof crypto == 'object' &&\n        typeof crypto['getRandomValues'] == 'function'\n      ) {\n        var randomBuffer = new Uint8Array(1)\n        return () => {\n          crypto.getRandomValues(randomBuffer)\n          return randomBuffer[0]\n        }\n      } else if (ENVIRONMENT_IS_NODE) {\n        try {\n          var crypto_module = require('crypto')\n          return () => crypto_module['randomBytes'](1)[0]\n        } catch (e) {}\n      }\n      return () => abort('randomDevice')\n    }\n    var PATH_FS = {\n      resolve: function() {\n        var resolvedPath = '',\n          resolvedAbsolute = false\n        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n          var path = i >= 0 ? arguments[i] : FS.cwd()\n          if (typeof path != 'string') {\n            throw new TypeError('Arguments to path.resolve must be strings')\n          } else if (!path) {\n            return ''\n          }\n          resolvedPath = path + '/' + resolvedPath\n          resolvedAbsolute = PATH.isAbs(path)\n        }\n        resolvedPath = PATH.normalizeArray(\n          resolvedPath.split('/').filter(p => !!p),\n          !resolvedAbsolute\n        ).join('/')\n        return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'\n      },\n      relative: (from, to) => {\n        from = PATH_FS.resolve(from).substr(1)\n        to = PATH_FS.resolve(to).substr(1)\n        function trim(arr) {\n          var start = 0\n          for (; start < arr.length; start++) {\n            if (arr[start] !== '') break\n          }\n          var end = arr.length - 1\n          for (; end >= 0; end--) {\n            if (arr[end] !== '') break\n          }\n          if (start > end) return []\n          return arr.slice(start, end - start + 1)\n        }\n        var fromParts = trim(from.split('/'))\n        var toParts = trim(to.split('/'))\n        var length = Math.min(fromParts.length, toParts.length)\n        var samePartsLength = length\n        for (var i = 0; i < length; i++) {\n          if (fromParts[i] !== toParts[i]) {\n            samePartsLength = i\n            break\n          }\n        }\n        var outputParts = []\n        for (var i = samePartsLength; i < fromParts.length; i++) {\n          outputParts.push('..')\n        }\n        outputParts = outputParts.concat(toParts.slice(samePartsLength))\n        return outputParts.join('/')\n      },\n    }\n    function intArrayFromString(stringy, dontAddNull, length) {\n      var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1\n      var u8array = new Array(len)\n      var numBytesWritten = stringToUTF8Array(\n        stringy,\n        u8array,\n        0,\n        u8array.length\n      )\n      if (dontAddNull) u8array.length = numBytesWritten\n      return u8array\n    }\n    var TTY = {\n      ttys: [],\n      init: function() {},\n      shutdown: function() {},\n      register: function(dev, ops) {\n        TTY.ttys[dev] = { input: [], output: [], ops: ops }\n        FS.registerDevice(dev, TTY.stream_ops)\n      },\n      stream_ops: {\n        open: function(stream) {\n          var tty = TTY.ttys[stream.node.rdev]\n          if (!tty) {\n            throw new FS.ErrnoError(43)\n          }\n          stream.tty = tty\n          stream.seekable = false\n        },\n        close: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        fsync: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        read: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.get_char) {\n            throw new FS.ErrnoError(60)\n          }\n          var bytesRead = 0\n          for (var i = 0; i < length; i++) {\n            var result\n            try {\n              result = stream.tty.ops.get_char(stream.tty)\n            } catch (e) {\n              throw new FS.ErrnoError(29)\n            }\n            if (result === undefined && bytesRead === 0) {\n              throw new FS.ErrnoError(6)\n            }\n            if (result === null || result === undefined) break\n            bytesRead++\n            buffer[offset + i] = result\n          }\n          if (bytesRead) {\n            stream.node.timestamp = Date.now()\n          }\n          return bytesRead\n        },\n        write: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.put_char) {\n            throw new FS.ErrnoError(60)\n          }\n          try {\n            for (var i = 0; i < length; i++) {\n              stream.tty.ops.put_char(stream.tty, buffer[offset + i])\n            }\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n          if (length) {\n            stream.node.timestamp = Date.now()\n          }\n          return i\n        },\n      },\n      default_tty_ops: {\n        get_char: function(tty) {\n          if (!tty.input.length) {\n            var result = null\n            if (ENVIRONMENT_IS_NODE) {\n              var BUFSIZE = 256\n              var buf = Buffer.alloc(BUFSIZE)\n              var bytesRead = 0\n              try {\n                bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, -1)\n              } catch (e) {\n                if (e.toString().includes('EOF')) bytesRead = 0\n                else throw e\n              }\n              if (bytesRead > 0) {\n                result = buf.slice(0, bytesRead).toString('utf-8')\n              } else {\n                result = null\n              }\n            } else if (\n              typeof window != 'undefined' &&\n              typeof window.prompt == 'function'\n            ) {\n              result = window.prompt('Input: ')\n              if (result !== null) {\n                result += '\\n'\n              }\n            } else if (typeof readline == 'function') {\n              result = readline()\n              if (result !== null) {\n                result += '\\n'\n              }\n            }\n            if (!result) {\n              return null\n            }\n            tty.input = intArrayFromString(result, true)\n          }\n          return tty.input.shift()\n        },\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n      default_tty1_ops: {\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n    }\n    function mmapAlloc(size) {\n      abort()\n    }\n    var MEMFS = {\n      ops_table: null,\n      mount: function(mount) {\n        return MEMFS.createNode(null, '/', 16384 | 511, 0)\n      },\n      createNode: function(parent, name, mode, dev) {\n        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n          throw new FS.ErrnoError(63)\n        }\n        if (!MEMFS.ops_table) {\n          MEMFS.ops_table = {\n            dir: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                lookup: MEMFS.node_ops.lookup,\n                mknod: MEMFS.node_ops.mknod,\n                rename: MEMFS.node_ops.rename,\n                unlink: MEMFS.node_ops.unlink,\n                rmdir: MEMFS.node_ops.rmdir,\n                readdir: MEMFS.node_ops.readdir,\n                symlink: MEMFS.node_ops.symlink,\n              },\n              stream: { llseek: MEMFS.stream_ops.llseek },\n            },\n            file: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: {\n                llseek: MEMFS.stream_ops.llseek,\n                read: MEMFS.stream_ops.read,\n                write: MEMFS.stream_ops.write,\n                allocate: MEMFS.stream_ops.allocate,\n                mmap: MEMFS.stream_ops.mmap,\n                msync: MEMFS.stream_ops.msync,\n              },\n            },\n            link: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                readlink: MEMFS.node_ops.readlink,\n              },\n              stream: {},\n            },\n            chrdev: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: FS.chrdev_stream_ops,\n            },\n          }\n        }\n        var node = FS.createNode(parent, name, mode, dev)\n        if (FS.isDir(node.mode)) {\n          node.node_ops = MEMFS.ops_table.dir.node\n          node.stream_ops = MEMFS.ops_table.dir.stream\n          node.contents = {}\n        } else if (FS.isFile(node.mode)) {\n          node.node_ops = MEMFS.ops_table.file.node\n          node.stream_ops = MEMFS.ops_table.file.stream\n          node.usedBytes = 0\n          node.contents = null\n        } else if (FS.isLink(node.mode)) {\n          node.node_ops = MEMFS.ops_table.link.node\n          node.stream_ops = MEMFS.ops_table.link.stream\n        } else if (FS.isChrdev(node.mode)) {\n          node.node_ops = MEMFS.ops_table.chrdev.node\n          node.stream_ops = MEMFS.ops_table.chrdev.stream\n        }\n        node.timestamp = Date.now()\n        if (parent) {\n          parent.contents[name] = node\n          parent.timestamp = node.timestamp\n        }\n        return node\n      },\n      getFileDataAsTypedArray: function(node) {\n        if (!node.contents) return new Uint8Array(0)\n        if (node.contents.subarray)\n          return node.contents.subarray(0, node.usedBytes)\n        return new Uint8Array(node.contents)\n      },\n      expandFileStorage: function(node, newCapacity) {\n        var prevCapacity = node.contents ? node.contents.length : 0\n        if (prevCapacity >= newCapacity) return\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024\n        newCapacity = Math.max(\n          newCapacity,\n          (prevCapacity *\n            (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>>\n            0\n        )\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256)\n        var oldContents = node.contents\n        node.contents = new Uint8Array(newCapacity)\n        if (node.usedBytes > 0)\n          node.contents.set(oldContents.subarray(0, node.usedBytes), 0)\n      },\n      resizeFileStorage: function(node, newSize) {\n        if (node.usedBytes == newSize) return\n        if (newSize == 0) {\n          node.contents = null\n          node.usedBytes = 0\n        } else {\n          var oldContents = node.contents\n          node.contents = new Uint8Array(newSize)\n          if (oldContents) {\n            node.contents.set(\n              oldContents.subarray(0, Math.min(newSize, node.usedBytes))\n            )\n          }\n          node.usedBytes = newSize\n        }\n      },\n      node_ops: {\n        getattr: function(node) {\n          var attr = {}\n          attr.dev = FS.isChrdev(node.mode) ? node.id : 1\n          attr.ino = node.id\n          attr.mode = node.mode\n          attr.nlink = 1\n          attr.uid = 0\n          attr.gid = 0\n          attr.rdev = node.rdev\n          if (FS.isDir(node.mode)) {\n            attr.size = 4096\n          } else if (FS.isFile(node.mode)) {\n            attr.size = node.usedBytes\n          } else if (FS.isLink(node.mode)) {\n            attr.size = node.link.length\n          } else {\n            attr.size = 0\n          }\n          attr.atime = new Date(node.timestamp)\n          attr.mtime = new Date(node.timestamp)\n          attr.ctime = new Date(node.timestamp)\n          attr.blksize = 4096\n          attr.blocks = Math.ceil(attr.size / attr.blksize)\n          return attr\n        },\n        setattr: function(node, attr) {\n          if (attr.mode !== undefined) {\n            node.mode = attr.mode\n          }\n          if (attr.timestamp !== undefined) {\n            node.timestamp = attr.timestamp\n          }\n          if (attr.size !== undefined) {\n            MEMFS.resizeFileStorage(node, attr.size)\n          }\n        },\n        lookup: function(parent, name) {\n          throw FS.genericErrors[44]\n        },\n        mknod: function(parent, name, mode, dev) {\n          return MEMFS.createNode(parent, name, mode, dev)\n        },\n        rename: function(old_node, new_dir, new_name) {\n          if (FS.isDir(old_node.mode)) {\n            var new_node\n            try {\n              new_node = FS.lookupNode(new_dir, new_name)\n            } catch (e) {}\n            if (new_node) {\n              for (var i in new_node.contents) {\n                throw new FS.ErrnoError(55)\n              }\n            }\n          }\n          delete old_node.parent.contents[old_node.name]\n          old_node.parent.timestamp = Date.now()\n          old_node.name = new_name\n          new_dir.contents[new_name] = old_node\n          new_dir.timestamp = old_node.parent.timestamp\n          old_node.parent = new_dir\n        },\n        unlink: function(parent, name) {\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        rmdir: function(parent, name) {\n          var node = FS.lookupNode(parent, name)\n          for (var i in node.contents) {\n            throw new FS.ErrnoError(55)\n          }\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        readdir: function(node) {\n          var entries = ['.', '..']\n          for (var key in node.contents) {\n            if (!node.contents.hasOwnProperty(key)) {\n              continue\n            }\n            entries.push(key)\n          }\n          return entries\n        },\n        symlink: function(parent, newname, oldpath) {\n          var node = MEMFS.createNode(parent, newname, 511 | 40960, 0)\n          node.link = oldpath\n          return node\n        },\n        readlink: function(node) {\n          if (!FS.isLink(node.mode)) {\n            throw new FS.ErrnoError(28)\n          }\n          return node.link\n        },\n      },\n      stream_ops: {\n        read: function(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= stream.node.usedBytes) return 0\n          var size = Math.min(stream.node.usedBytes - position, length)\n          if (size > 8 && contents.subarray) {\n            buffer.set(contents.subarray(position, position + size), offset)\n          } else {\n            for (var i = 0; i < size; i++)\n              buffer[offset + i] = contents[position + i]\n          }\n          return size\n        },\n        write: function(stream, buffer, offset, length, position, canOwn) {\n          if (buffer.buffer === HEAP8.buffer) {\n            canOwn = false\n          }\n          if (!length) return 0\n          var node = stream.node\n          node.timestamp = Date.now()\n          if (buffer.subarray && (!node.contents || node.contents.subarray)) {\n            if (canOwn) {\n              node.contents = buffer.subarray(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (node.usedBytes === 0 && position === 0) {\n              node.contents = buffer.slice(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (position + length <= node.usedBytes) {\n              node.contents.set(\n                buffer.subarray(offset, offset + length),\n                position\n              )\n              return length\n            }\n          }\n          MEMFS.expandFileStorage(node, position + length)\n          if (node.contents.subarray && buffer.subarray) {\n            node.contents.set(\n              buffer.subarray(offset, offset + length),\n              position\n            )\n          } else {\n            for (var i = 0; i < length; i++) {\n              node.contents[position + i] = buffer[offset + i]\n            }\n          }\n          node.usedBytes = Math.max(node.usedBytes, position + length)\n          return length\n        },\n        llseek: function(stream, offset, whence) {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              position += stream.node.usedBytes\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        allocate: function(stream, offset, length) {\n          MEMFS.expandFileStorage(stream.node, offset + length)\n          stream.node.usedBytes = Math.max(\n            stream.node.usedBytes,\n            offset + length\n          )\n        },\n        mmap: function(stream, length, position, prot, flags) {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr\n          var allocated\n          var contents = stream.node.contents\n          if (!(flags & 2) && contents.buffer === buffer) {\n            allocated = false\n            ptr = contents.byteOffset\n          } else {\n            if (position > 0 || position + length < contents.length) {\n              if (contents.subarray) {\n                contents = contents.subarray(position, position + length)\n              } else {\n                contents = Array.prototype.slice.call(\n                  contents,\n                  position,\n                  position + length\n                )\n              }\n            }\n            allocated = true\n            ptr = mmapAlloc(length)\n            if (!ptr) {\n              throw new FS.ErrnoError(48)\n            }\n            HEAP8.set(contents, ptr)\n          }\n          return { ptr: ptr, allocated: allocated }\n        },\n        msync: function(stream, buffer, offset, length, mmapFlags) {\n          MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    function asyncLoad(url, onload, onerror, noRunDep) {\n      var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''\n      readAsync(\n        url,\n        arrayBuffer => {\n          assert(\n            arrayBuffer,\n            'Loading data file \"' + url + '\" failed (no arrayBuffer).'\n          )\n          onload(new Uint8Array(arrayBuffer))\n          if (dep) removeRunDependency(dep)\n        },\n        event => {\n          if (onerror) {\n            onerror()\n          } else {\n            throw 'Loading data file \"' + url + '\" failed.'\n          }\n        }\n      )\n      if (dep) addRunDependency(dep)\n    }\n    var ERRNO_CODES = {}\n    var NODEFS = {\n      isWindows: false,\n      staticInit: () => {\n        NODEFS.isWindows = !!process.platform.match(/^win/)\n        var flags = process['binding']('constants')\n        if (flags['fs']) {\n          flags = flags['fs']\n        }\n        NODEFS.flagsForNodeMap = {\n          1024: flags['O_APPEND'],\n          64: flags['O_CREAT'],\n          128: flags['O_EXCL'],\n          256: flags['O_NOCTTY'],\n          0: flags['O_RDONLY'],\n          2: flags['O_RDWR'],\n          4096: flags['O_SYNC'],\n          512: flags['O_TRUNC'],\n          1: flags['O_WRONLY'],\n          131072: flags['O_NOFOLLOW'],\n        }\n      },\n      convertNodeCode: e => {\n        var code = e.code\n        return ERRNO_CODES[code]\n      },\n      mount: mount => {\n        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0)\n      },\n      createNode: (parent, name, mode, dev) => {\n        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = FS.createNode(parent, name, mode)\n        node.node_ops = NODEFS.node_ops\n        node.stream_ops = NODEFS.stream_ops\n        return node\n      },\n      getMode: path => {\n        var stat\n        try {\n          stat = fs.lstatSync(path)\n          if (NODEFS.isWindows) {\n            stat.mode = stat.mode | ((stat.mode & 292) >> 2)\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n        }\n        return stat.mode\n      },\n      realPath: node => {\n        var parts = []\n        while (node.parent !== node) {\n          parts.push(node.name)\n          node = node.parent\n        }\n        parts.push(node.mount.opts.root)\n        parts.reverse()\n        return PATH.join.apply(null, parts)\n      },\n      flagsForNode: flags => {\n        flags &= ~2097152\n        flags &= ~2048\n        flags &= ~32768\n        flags &= ~524288\n        flags &= ~65536\n        var newFlags = 0\n        for (var k in NODEFS.flagsForNodeMap) {\n          if (flags & k) {\n            newFlags |= NODEFS.flagsForNodeMap[k]\n            flags ^= k\n          }\n        }\n        if (flags) {\n          throw new FS.ErrnoError(28)\n        }\n        return newFlags\n      },\n      node_ops: {\n        getattr: node => {\n          var path = NODEFS.realPath(node)\n          var stat\n          try {\n            stat = fs.lstatSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          if (NODEFS.isWindows && !stat.blksize) {\n            stat.blksize = 4096\n          }\n          if (NODEFS.isWindows && !stat.blocks) {\n            stat.blocks = ((stat.size + stat.blksize - 1) / stat.blksize) | 0\n          }\n          return {\n            dev: stat.dev,\n            ino: stat.ino,\n            mode: stat.mode,\n            nlink: stat.nlink,\n            uid: stat.uid,\n            gid: stat.gid,\n            rdev: stat.rdev,\n            size: stat.size,\n            atime: stat.atime,\n            mtime: stat.mtime,\n            ctime: stat.ctime,\n            blksize: stat.blksize,\n            blocks: stat.blocks,\n          }\n        },\n        setattr: (node, attr) => {\n          var path = NODEFS.realPath(node)\n          try {\n            if (attr.mode !== undefined) {\n              fs.chmodSync(path, attr.mode)\n              node.mode = attr.mode\n            }\n            if (attr.timestamp !== undefined) {\n              var date = new Date(attr.timestamp)\n              fs.utimesSync(path, date, date)\n            }\n            if (attr.size !== undefined) {\n              fs.truncateSync(path, attr.size)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        lookup: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          var mode = NODEFS.getMode(path)\n          return NODEFS.createNode(parent, name, mode)\n        },\n        mknod: (parent, name, mode, dev) => {\n          var node = NODEFS.createNode(parent, name, mode, dev)\n          var path = NODEFS.realPath(node)\n          try {\n            if (FS.isDir(node.mode)) {\n              fs.mkdirSync(path, node.mode)\n            } else {\n              fs.writeFileSync(path, '', { mode: node.mode })\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          return node\n        },\n        rename: (oldNode, newDir, newName) => {\n          var oldPath = NODEFS.realPath(oldNode)\n          var newPath = PATH.join2(NODEFS.realPath(newDir), newName)\n          try {\n            fs.renameSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          oldNode.name = newName\n        },\n        unlink: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.unlinkSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        rmdir: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.rmdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readdir: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            return fs.readdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        symlink: (parent, newName, oldPath) => {\n          var newPath = PATH.join2(NODEFS.realPath(parent), newName)\n          try {\n            fs.symlinkSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readlink: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            path = fs.readlinkSync(path)\n            path = nodePath.relative(\n              nodePath.resolve(node.mount.opts.root),\n              path\n            )\n            return path\n          } catch (e) {\n            if (!e.code) throw e\n            if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28)\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n      },\n      stream_ops: {\n        open: stream => {\n          var path = NODEFS.realPath(stream.node)\n          try {\n            if (FS.isFile(stream.node.mode)) {\n              stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags))\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        close: stream => {\n          try {\n            if (FS.isFile(stream.node.mode) && stream.nfd) {\n              fs.closeSync(stream.nfd)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        read: (stream, buffer, offset, length, position) => {\n          if (length === 0) return 0\n          try {\n            return fs.readSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        write: (stream, buffer, offset, length, position) => {\n          try {\n            return fs.writeSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        llseek: (stream, offset, whence) => {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              try {\n                var stat = fs.fstatSync(stream.nfd)\n                position += stat.size\n              } catch (e) {\n                throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n              }\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        mmap: (stream, length, position, prot, flags) => {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr = mmapAlloc(length)\n          NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        },\n        msync: (stream, buffer, offset, length, mmapFlags) => {\n          NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    var FS = {\n      root: null,\n      mounts: [],\n      devices: {},\n      streams: [],\n      nextInode: 1,\n      nameTable: null,\n      currentPath: '/',\n      initialized: false,\n      ignorePermissions: true,\n      ErrnoError: null,\n      genericErrors: {},\n      filesystems: null,\n      syncFSRequests: 0,\n      lookupPath: (path, opts = {}) => {\n        path = PATH_FS.resolve(path)\n        if (!path) return { path: '', node: null }\n        var defaults = { follow_mount: true, recurse_count: 0 }\n        opts = Object.assign(defaults, opts)\n        if (opts.recurse_count > 8) {\n          throw new FS.ErrnoError(32)\n        }\n        var parts = path.split('/').filter(p => !!p)\n        var current = FS.root\n        var current_path = '/'\n        for (var i = 0; i < parts.length; i++) {\n          var islast = i === parts.length - 1\n          if (islast && opts.parent) {\n            break\n          }\n          current = FS.lookupNode(current, parts[i])\n          current_path = PATH.join2(current_path, parts[i])\n          if (FS.isMountpoint(current)) {\n            if (!islast || (islast && opts.follow_mount)) {\n              current = current.mounted.root\n            }\n          }\n          if (!islast || opts.follow) {\n            var count = 0\n            while (FS.isLink(current.mode)) {\n              var link = FS.readlink(current_path)\n              current_path = PATH_FS.resolve(PATH.dirname(current_path), link)\n              var lookup = FS.lookupPath(current_path, {\n                recurse_count: opts.recurse_count + 1,\n              })\n              current = lookup.node\n              if (count++ > 40) {\n                throw new FS.ErrnoError(32)\n              }\n            }\n          }\n        }\n        return { path: current_path, node: current }\n      },\n      getPath: node => {\n        var path\n        while (true) {\n          if (FS.isRoot(node)) {\n            var mount = node.mount.mountpoint\n            if (!path) return mount\n            return mount[mount.length - 1] !== '/'\n              ? mount + '/' + path\n              : mount + path\n          }\n          path = path ? node.name + '/' + path : node.name\n          node = node.parent\n        }\n      },\n      hashName: (parentid, name) => {\n        var hash = 0\n        for (var i = 0; i < name.length; i++) {\n          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0\n        }\n        return ((parentid + hash) >>> 0) % FS.nameTable.length\n      },\n      hashAddNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        node.name_next = FS.nameTable[hash]\n        FS.nameTable[hash] = node\n      },\n      hashRemoveNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        if (FS.nameTable[hash] === node) {\n          FS.nameTable[hash] = node.name_next\n        } else {\n          var current = FS.nameTable[hash]\n          while (current) {\n            if (current.name_next === node) {\n              current.name_next = node.name_next\n              break\n            }\n            current = current.name_next\n          }\n        }\n      },\n      lookupNode: (parent, name) => {\n        var errCode = FS.mayLookup(parent)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode, parent)\n        }\n        var hash = FS.hashName(parent.id, name)\n        for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n          var nodeName = node.name\n          if (node.parent.id === parent.id && nodeName === name) {\n            return node\n          }\n        }\n        return FS.lookup(parent, name)\n      },\n      createNode: (parent, name, mode, rdev) => {\n        var node = new FS.FSNode(parent, name, mode, rdev)\n        FS.hashAddNode(node)\n        return node\n      },\n      destroyNode: node => {\n        FS.hashRemoveNode(node)\n      },\n      isRoot: node => {\n        return node === node.parent\n      },\n      isMountpoint: node => {\n        return !!node.mounted\n      },\n      isFile: mode => {\n        return (mode & 61440) === 32768\n      },\n      isDir: mode => {\n        return (mode & 61440) === 16384\n      },\n      isLink: mode => {\n        return (mode & 61440) === 40960\n      },\n      isChrdev: mode => {\n        return (mode & 61440) === 8192\n      },\n      isBlkdev: mode => {\n        return (mode & 61440) === 24576\n      },\n      isFIFO: mode => {\n        return (mode & 61440) === 4096\n      },\n      isSocket: mode => {\n        return (mode & 49152) === 49152\n      },\n      flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 },\n      modeStringToFlags: str => {\n        var flags = FS.flagModes[str]\n        if (typeof flags == 'undefined') {\n          throw new Error('Unknown file open mode: ' + str)\n        }\n        return flags\n      },\n      flagsToPermissionString: flag => {\n        var perms = ['r', 'w', 'rw'][flag & 3]\n        if (flag & 512) {\n          perms += 'w'\n        }\n        return perms\n      },\n      nodePermissions: (node, perms) => {\n        if (FS.ignorePermissions) {\n          return 0\n        }\n        if (perms.includes('r') && !(node.mode & 292)) {\n          return 2\n        } else if (perms.includes('w') && !(node.mode & 146)) {\n          return 2\n        } else if (perms.includes('x') && !(node.mode & 73)) {\n          return 2\n        }\n        return 0\n      },\n      mayLookup: dir => {\n        var errCode = FS.nodePermissions(dir, 'x')\n        if (errCode) return errCode\n        if (!dir.node_ops.lookup) return 2\n        return 0\n      },\n      mayCreate: (dir, name) => {\n        try {\n          var node = FS.lookupNode(dir, name)\n          return 20\n        } catch (e) {}\n        return FS.nodePermissions(dir, 'wx')\n      },\n      mayDelete: (dir, name, isdir) => {\n        var node\n        try {\n          node = FS.lookupNode(dir, name)\n        } catch (e) {\n          return e.errno\n        }\n        var errCode = FS.nodePermissions(dir, 'wx')\n        if (errCode) {\n          return errCode\n        }\n        if (isdir) {\n          if (!FS.isDir(node.mode)) {\n            return 54\n          }\n          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n            return 10\n          }\n        } else {\n          if (FS.isDir(node.mode)) {\n            return 31\n          }\n        }\n        return 0\n      },\n      mayOpen: (node, flags) => {\n        if (!node) {\n          return 44\n        }\n        if (FS.isLink(node.mode)) {\n          return 32\n        } else if (FS.isDir(node.mode)) {\n          if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) {\n            return 31\n          }\n        }\n        return FS.nodePermissions(node, FS.flagsToPermissionString(flags))\n      },\n      MAX_OPEN_FDS: 4096,\n      nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => {\n        for (var fd = fd_start; fd <= fd_end; fd++) {\n          if (!FS.streams[fd]) {\n            return fd\n          }\n        }\n        throw new FS.ErrnoError(33)\n      },\n      getStream: fd => FS.streams[fd],\n      createStream: (stream, fd_start, fd_end) => {\n        if (!FS.FSStream) {\n          FS.FSStream = function() {\n            this.shared = {}\n          }\n          FS.FSStream.prototype = {}\n          Object.defineProperties(FS.FSStream.prototype, {\n            object: {\n              get: function() {\n                return this.node\n              },\n              set: function(val) {\n                this.node = val\n              },\n            },\n            isRead: {\n              get: function() {\n                return (this.flags & 2097155) !== 1\n              },\n            },\n            isWrite: {\n              get: function() {\n                return (this.flags & 2097155) !== 0\n              },\n            },\n            isAppend: {\n              get: function() {\n                return this.flags & 1024\n              },\n            },\n            flags: {\n              get: function() {\n                return this.shared.flags\n              },\n              set: function(val) {\n                this.shared.flags = val\n              },\n            },\n            position: {\n              get: function() {\n                return this.shared.position\n              },\n              set: function(val) {\n                this.shared.position = val\n              },\n            },\n          })\n        }\n        stream = Object.assign(new FS.FSStream(), stream)\n        var fd = FS.nextfd(fd_start, fd_end)\n        stream.fd = fd\n        FS.streams[fd] = stream\n        return stream\n      },\n      closeStream: fd => {\n        FS.streams[fd] = null\n      },\n      chrdev_stream_ops: {\n        open: stream => {\n          var device = FS.getDevice(stream.node.rdev)\n          stream.stream_ops = device.stream_ops\n          if (stream.stream_ops.open) {\n            stream.stream_ops.open(stream)\n          }\n        },\n        llseek: () => {\n          throw new FS.ErrnoError(70)\n        },\n      },\n      major: dev => dev >> 8,\n      minor: dev => dev & 255,\n      makedev: (ma, mi) => (ma << 8) | mi,\n      registerDevice: (dev, ops) => {\n        FS.devices[dev] = { stream_ops: ops }\n      },\n      getDevice: dev => FS.devices[dev],\n      getMounts: mount => {\n        var mounts = []\n        var check = [mount]\n        while (check.length) {\n          var m = check.pop()\n          mounts.push(m)\n          check.push.apply(check, m.mounts)\n        }\n        return mounts\n      },\n      syncfs: (populate, callback) => {\n        if (typeof populate == 'function') {\n          callback = populate\n          populate = false\n        }\n        FS.syncFSRequests++\n        if (FS.syncFSRequests > 1) {\n          err(\n            'warning: ' +\n              FS.syncFSRequests +\n              ' FS.syncfs operations in flight at once, probably just doing extra work'\n          )\n        }\n        var mounts = FS.getMounts(FS.root.mount)\n        var completed = 0\n        function doCallback(errCode) {\n          FS.syncFSRequests--\n          return callback(errCode)\n        }\n        function done(errCode) {\n          if (errCode) {\n            if (!done.errored) {\n              done.errored = true\n              return doCallback(errCode)\n            }\n            return\n          }\n          if (++completed >= mounts.length) {\n            doCallback(null)\n          }\n        }\n        mounts.forEach(mount => {\n          if (!mount.type.syncfs) {\n            return done(null)\n          }\n          mount.type.syncfs(mount, populate, done)\n        })\n      },\n      mount: (type, opts, mountpoint) => {\n        var root = mountpoint === '/'\n        var pseudo = !mountpoint\n        var node\n        if (root && FS.root) {\n          throw new FS.ErrnoError(10)\n        } else if (!root && !pseudo) {\n          var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n          mountpoint = lookup.path\n          node = lookup.node\n          if (FS.isMountpoint(node)) {\n            throw new FS.ErrnoError(10)\n          }\n          if (!FS.isDir(node.mode)) {\n            throw new FS.ErrnoError(54)\n          }\n        }\n        var mount = {\n          type: type,\n          opts: opts,\n          mountpoint: mountpoint,\n          mounts: [],\n        }\n        var mountRoot = type.mount(mount)\n        mountRoot.mount = mount\n        mount.root = mountRoot\n        if (root) {\n          FS.root = mountRoot\n        } else if (node) {\n          node.mounted = mount\n          if (node.mount) {\n            node.mount.mounts.push(mount)\n          }\n        }\n        return mountRoot\n      },\n      unmount: mountpoint => {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n        if (!FS.isMountpoint(lookup.node)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = lookup.node\n        var mount = node.mounted\n        var mounts = FS.getMounts(mount)\n        Object.keys(FS.nameTable).forEach(hash => {\n          var current = FS.nameTable[hash]\n          while (current) {\n            var next = current.name_next\n            if (mounts.includes(current.mount)) {\n              FS.destroyNode(current)\n            }\n            current = next\n          }\n        })\n        node.mounted = null\n        var idx = node.mount.mounts.indexOf(mount)\n        node.mount.mounts.splice(idx, 1)\n      },\n      lookup: (parent, name) => {\n        return parent.node_ops.lookup(parent, name)\n      },\n      mknod: (path, mode, dev) => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        if (!name || name === '.' || name === '..') {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.mayCreate(parent, name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.mknod) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.mknod(parent, name, mode, dev)\n      },\n      create: (path, mode) => {\n        mode = mode !== undefined ? mode : 438\n        mode &= 4095\n        mode |= 32768\n        return FS.mknod(path, mode, 0)\n      },\n      mkdir: (path, mode) => {\n        mode = mode !== undefined ? mode : 511\n        mode &= 511 | 512\n        mode |= 16384\n        return FS.mknod(path, mode, 0)\n      },\n      mkdirTree: (path, mode) => {\n        var dirs = path.split('/')\n        var d = ''\n        for (var i = 0; i < dirs.length; ++i) {\n          if (!dirs[i]) continue\n          d += '/' + dirs[i]\n          try {\n            FS.mkdir(d, mode)\n          } catch (e) {\n            if (e.errno != 20) throw e\n          }\n        }\n      },\n      mkdev: (path, mode, dev) => {\n        if (typeof dev == 'undefined') {\n          dev = mode\n          mode = 438\n        }\n        mode |= 8192\n        return FS.mknod(path, mode, dev)\n      },\n      symlink: (oldpath, newpath) => {\n        if (!PATH_FS.resolve(oldpath)) {\n          throw new FS.ErrnoError(44)\n        }\n        var lookup = FS.lookupPath(newpath, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var newname = PATH.basename(newpath)\n        var errCode = FS.mayCreate(parent, newname)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.symlink) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.symlink(parent, newname, oldpath)\n      },\n      rename: (old_path, new_path) => {\n        var old_dirname = PATH.dirname(old_path)\n        var new_dirname = PATH.dirname(new_path)\n        var old_name = PATH.basename(old_path)\n        var new_name = PATH.basename(new_path)\n        var lookup, old_dir, new_dir\n        lookup = FS.lookupPath(old_path, { parent: true })\n        old_dir = lookup.node\n        lookup = FS.lookupPath(new_path, { parent: true })\n        new_dir = lookup.node\n        if (!old_dir || !new_dir) throw new FS.ErrnoError(44)\n        if (old_dir.mount !== new_dir.mount) {\n          throw new FS.ErrnoError(75)\n        }\n        var old_node = FS.lookupNode(old_dir, old_name)\n        var relative = PATH_FS.relative(old_path, new_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(28)\n        }\n        relative = PATH_FS.relative(new_path, old_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(55)\n        }\n        var new_node\n        try {\n          new_node = FS.lookupNode(new_dir, new_name)\n        } catch (e) {}\n        if (old_node === new_node) {\n          return\n        }\n        var isdir = FS.isDir(old_node.mode)\n        var errCode = FS.mayDelete(old_dir, old_name, isdir)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        errCode = new_node\n          ? FS.mayDelete(new_dir, new_name, isdir)\n          : FS.mayCreate(new_dir, new_name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!old_dir.node_ops.rename) {\n          throw new FS.ErrnoError(63)\n        }\n        if (\n          FS.isMountpoint(old_node) ||\n          (new_node && FS.isMountpoint(new_node))\n        ) {\n          throw new FS.ErrnoError(10)\n        }\n        if (new_dir !== old_dir) {\n          errCode = FS.nodePermissions(old_dir, 'w')\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        FS.hashRemoveNode(old_node)\n        try {\n          old_dir.node_ops.rename(old_node, new_dir, new_name)\n        } catch (e) {\n          throw e\n        } finally {\n          FS.hashAddNode(old_node)\n        }\n      },\n      rmdir: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, true)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.rmdir) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.rmdir(parent, name)\n        FS.destroyNode(node)\n      },\n      readdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        if (!node.node_ops.readdir) {\n          throw new FS.ErrnoError(54)\n        }\n        return node.node_ops.readdir(node)\n      },\n      unlink: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, false)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.unlink) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.unlink(parent, name)\n        FS.destroyNode(node)\n      },\n      readlink: path => {\n        var lookup = FS.lookupPath(path)\n        var link = lookup.node\n        if (!link) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!link.node_ops.readlink) {\n          throw new FS.ErrnoError(28)\n        }\n        return PATH_FS.resolve(\n          FS.getPath(link.parent),\n          link.node_ops.readlink(link)\n        )\n      },\n      stat: (path, dontFollow) => {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow })\n        var node = lookup.node\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!node.node_ops.getattr) {\n          throw new FS.ErrnoError(63)\n        }\n        return node.node_ops.getattr(node)\n      },\n      lstat: path => {\n        return FS.stat(path, true)\n      },\n      chmod: (path, mode, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, {\n          mode: (mode & 4095) | (node.mode & ~4095),\n          timestamp: Date.now(),\n        })\n      },\n      lchmod: (path, mode) => {\n        FS.chmod(path, mode, true)\n      },\n      fchmod: (fd, mode) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chmod(stream.node, mode)\n      },\n      chown: (path, uid, gid, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, { timestamp: Date.now() })\n      },\n      lchown: (path, uid, gid) => {\n        FS.chown(path, uid, gid, true)\n      },\n      fchown: (fd, uid, gid) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chown(stream.node, uid, gid)\n      },\n      truncate: (path, len) => {\n        if (len < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: true })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!FS.isFile(node.mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.nodePermissions(node, 'w')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        node.node_ops.setattr(node, { size: len, timestamp: Date.now() })\n      },\n      ftruncate: (fd, len) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(28)\n        }\n        FS.truncate(stream.node, len)\n      },\n      utime: (path, atime, mtime) => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) })\n      },\n      open: (path, flags, mode) => {\n        if (path === '') {\n          throw new FS.ErrnoError(44)\n        }\n        flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags\n        mode = typeof mode == 'undefined' ? 438 : mode\n        if (flags & 64) {\n          mode = (mode & 4095) | 32768\n        } else {\n          mode = 0\n        }\n        var node\n        if (typeof path == 'object') {\n          node = path\n        } else {\n          path = PATH.normalize(path)\n          try {\n            var lookup = FS.lookupPath(path, { follow: !(flags & 131072) })\n            node = lookup.node\n          } catch (e) {}\n        }\n        var created = false\n        if (flags & 64) {\n          if (node) {\n            if (flags & 128) {\n              throw new FS.ErrnoError(20)\n            }\n          } else {\n            node = FS.mknod(path, mode, 0)\n            created = true\n          }\n        }\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (FS.isChrdev(node.mode)) {\n          flags &= ~512\n        }\n        if (flags & 65536 && !FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        if (!created) {\n          var errCode = FS.mayOpen(node, flags)\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        if (flags & 512 && !created) {\n          FS.truncate(node, 0)\n        }\n        flags &= ~(128 | 512 | 131072)\n        var stream = FS.createStream({\n          node: node,\n          path: FS.getPath(node),\n          flags: flags,\n          seekable: true,\n          position: 0,\n          stream_ops: node.stream_ops,\n          ungotten: [],\n          error: false,\n        })\n        if (stream.stream_ops.open) {\n          stream.stream_ops.open(stream)\n        }\n        if (Module['logReadFiles'] && !(flags & 1)) {\n          if (!FS.readFiles) FS.readFiles = {}\n          if (!(path in FS.readFiles)) {\n            FS.readFiles[path] = 1\n          }\n        }\n        return stream\n      },\n      close: stream => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (stream.getdents) stream.getdents = null\n        try {\n          if (stream.stream_ops.close) {\n            stream.stream_ops.close(stream)\n          }\n        } catch (e) {\n          throw e\n        } finally {\n          FS.closeStream(stream.fd)\n        }\n        stream.fd = null\n      },\n      isClosed: stream => {\n        return stream.fd === null\n      },\n      llseek: (stream, offset, whence) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!stream.seekable || !stream.stream_ops.llseek) {\n          throw new FS.ErrnoError(70)\n        }\n        if (whence != 0 && whence != 1 && whence != 2) {\n          throw new FS.ErrnoError(28)\n        }\n        stream.position = stream.stream_ops.llseek(stream, offset, whence)\n        stream.ungotten = []\n        return stream.position\n      },\n      read: (stream, buffer, offset, length, position) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.read) {\n          throw new FS.ErrnoError(28)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesRead = stream.stream_ops.read(\n          stream,\n          buffer,\n          offset,\n          length,\n          position\n        )\n        if (!seeking) stream.position += bytesRead\n        return bytesRead\n      },\n      write: (stream, buffer, offset, length, position, canOwn) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.write) {\n          throw new FS.ErrnoError(28)\n        }\n        if (stream.seekable && stream.flags & 1024) {\n          FS.llseek(stream, 0, 2)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesWritten = stream.stream_ops.write(\n          stream,\n          buffer,\n          offset,\n          length,\n          position,\n          canOwn\n        )\n        if (!seeking) stream.position += bytesWritten\n        return bytesWritten\n      },\n      allocate: (stream, offset, length) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (offset < 0 || length <= 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (!stream.stream_ops.allocate) {\n          throw new FS.ErrnoError(138)\n        }\n        stream.stream_ops.allocate(stream, offset, length)\n      },\n      mmap: (stream, length, position, prot, flags) => {\n        if (\n          (prot & 2) !== 0 &&\n          (flags & 2) === 0 &&\n          (stream.flags & 2097155) !== 2\n        ) {\n          throw new FS.ErrnoError(2)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(2)\n        }\n        if (!stream.stream_ops.mmap) {\n          throw new FS.ErrnoError(43)\n        }\n        return stream.stream_ops.mmap(stream, length, position, prot, flags)\n      },\n      msync: (stream, buffer, offset, length, mmapFlags) => {\n        if (!stream.stream_ops.msync) {\n          return 0\n        }\n        return stream.stream_ops.msync(\n          stream,\n          buffer,\n          offset,\n          length,\n          mmapFlags\n        )\n      },\n      munmap: stream => 0,\n      ioctl: (stream, cmd, arg) => {\n        if (!stream.stream_ops.ioctl) {\n          throw new FS.ErrnoError(59)\n        }\n        return stream.stream_ops.ioctl(stream, cmd, arg)\n      },\n      readFile: (path, opts = {}) => {\n        opts.flags = opts.flags || 0\n        opts.encoding = opts.encoding || 'binary'\n        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {\n          throw new Error('Invalid encoding type \"' + opts.encoding + '\"')\n        }\n        var ret\n        var stream = FS.open(path, opts.flags)\n        var stat = FS.stat(path)\n        var length = stat.size\n        var buf = new Uint8Array(length)\n        FS.read(stream, buf, 0, length, 0)\n        if (opts.encoding === 'utf8') {\n          ret = UTF8ArrayToString(buf, 0)\n        } else if (opts.encoding === 'binary') {\n          ret = buf\n        }\n        FS.close(stream)\n        return ret\n      },\n      writeFile: (path, data, opts = {}) => {\n        opts.flags = opts.flags || 577\n        var stream = FS.open(path, opts.flags, opts.mode)\n        if (typeof data == 'string') {\n          var buf = new Uint8Array(lengthBytesUTF8(data) + 1)\n          var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length)\n          FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn)\n        } else if (ArrayBuffer.isView(data)) {\n          FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn)\n        } else {\n          throw new Error('Unsupported data type')\n        }\n        FS.close(stream)\n      },\n      cwd: () => FS.currentPath,\n      chdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        if (lookup.node === null) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!FS.isDir(lookup.node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        var errCode = FS.nodePermissions(lookup.node, 'x')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        FS.currentPath = lookup.path\n      },\n      createDefaultDirectories: () => {\n        FS.mkdir('/tmp')\n        FS.mkdir('/home')\n        FS.mkdir('/home/web_user')\n      },\n      createDefaultDevices: () => {\n        FS.mkdir('/dev')\n        FS.registerDevice(FS.makedev(1, 3), {\n          read: () => 0,\n          write: (stream, buffer, offset, length, pos) => length,\n        })\n        FS.mkdev('/dev/null', FS.makedev(1, 3))\n        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops)\n        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops)\n        FS.mkdev('/dev/tty', FS.makedev(5, 0))\n        FS.mkdev('/dev/tty1', FS.makedev(6, 0))\n        var random_device = getRandomDevice()\n        FS.createDevice('/dev', 'random', random_device)\n        FS.createDevice('/dev', 'urandom', random_device)\n        FS.mkdir('/dev/shm')\n        FS.mkdir('/dev/shm/tmp')\n      },\n      createSpecialDirectories: () => {\n        FS.mkdir('/proc')\n        var proc_self = FS.mkdir('/proc/self')\n        FS.mkdir('/proc/self/fd')\n        FS.mount(\n          {\n            mount: () => {\n              var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73)\n              node.node_ops = {\n                lookup: (parent, name) => {\n                  var fd = +name\n                  var stream = FS.getStream(fd)\n                  if (!stream) throw new FS.ErrnoError(8)\n                  var ret = {\n                    parent: null,\n                    mount: { mountpoint: 'fake' },\n                    node_ops: { readlink: () => stream.path },\n                  }\n                  ret.parent = ret\n                  return ret\n                },\n              }\n              return node\n            },\n          },\n          {},\n          '/proc/self/fd'\n        )\n      },\n      createStandardStreams: () => {\n        if (Module['stdin']) {\n          FS.createDevice('/dev', 'stdin', Module['stdin'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdin')\n        }\n        if (Module['stdout']) {\n          FS.createDevice('/dev', 'stdout', null, Module['stdout'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdout')\n        }\n        if (Module['stderr']) {\n          FS.createDevice('/dev', 'stderr', null, Module['stderr'])\n        } else {\n          FS.symlink('/dev/tty1', '/dev/stderr')\n        }\n        var stdin = FS.open('/dev/stdin', 0)\n        var stdout = FS.open('/dev/stdout', 1)\n        var stderr = FS.open('/dev/stderr', 1)\n      },\n      ensureErrnoError: () => {\n        if (FS.ErrnoError) return\n        FS.ErrnoError = function ErrnoError(errno, node) {\n          this.node = node\n          this.setErrno = function(errno) {\n            this.errno = errno\n          }\n          this.setErrno(errno)\n          this.message = 'FS error'\n        }\n        FS.ErrnoError.prototype = new Error()\n        FS.ErrnoError.prototype.constructor = FS.ErrnoError\n        ;[44].forEach(code => {\n          FS.genericErrors[code] = new FS.ErrnoError(code)\n          FS.genericErrors[code].stack = '<generic error, no stack>'\n        })\n      },\n      staticInit: () => {\n        FS.ensureErrnoError()\n        FS.nameTable = new Array(4096)\n        FS.mount(MEMFS, {}, '/')\n        FS.createDefaultDirectories()\n        FS.createDefaultDevices()\n        FS.createSpecialDirectories()\n        FS.filesystems = { MEMFS: MEMFS, NODEFS: NODEFS }\n      },\n      init: (input, output, error) => {\n        FS.init.initialized = true\n        FS.ensureErrnoError()\n        Module['stdin'] = input || Module['stdin']\n        Module['stdout'] = output || Module['stdout']\n        Module['stderr'] = error || Module['stderr']\n        FS.createStandardStreams()\n      },\n      quit: () => {\n        FS.init.initialized = false\n        for (var i = 0; i < FS.streams.length; i++) {\n          var stream = FS.streams[i]\n          if (!stream) {\n            continue\n          }\n          FS.close(stream)\n        }\n      },\n      getMode: (canRead, canWrite) => {\n        var mode = 0\n        if (canRead) mode |= 292 | 73\n        if (canWrite) mode |= 146\n        return mode\n      },\n      findObject: (path, dontResolveLastLink) => {\n        var ret = FS.analyzePath(path, dontResolveLastLink)\n        if (!ret.exists) {\n          return null\n        }\n        return ret.object\n      },\n      analyzePath: (path, dontResolveLastLink) => {\n        try {\n          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          path = lookup.path\n        } catch (e) {}\n        var ret = {\n          isRoot: false,\n          exists: false,\n          error: 0,\n          name: null,\n          path: null,\n          object: null,\n          parentExists: false,\n          parentPath: null,\n          parentObject: null,\n        }\n        try {\n          var lookup = FS.lookupPath(path, { parent: true })\n          ret.parentExists = true\n          ret.parentPath = lookup.path\n          ret.parentObject = lookup.node\n          ret.name = PATH.basename(path)\n          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          ret.exists = true\n          ret.path = lookup.path\n          ret.object = lookup.node\n          ret.name = lookup.node.name\n          ret.isRoot = lookup.path === '/'\n        } catch (e) {\n          ret.error = e.errno\n        }\n        return ret\n      },\n      createPath: (parent, path, canRead, canWrite) => {\n        parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n        var parts = path.split('/').reverse()\n        while (parts.length) {\n          var part = parts.pop()\n          if (!part) continue\n          var current = PATH.join2(parent, part)\n          try {\n            FS.mkdir(current)\n          } catch (e) {}\n          parent = current\n        }\n        return current\n      },\n      createFile: (parent, name, properties, canRead, canWrite) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(canRead, canWrite)\n        return FS.create(path, mode)\n      },\n      createDataFile: (parent, name, data, canRead, canWrite, canOwn) => {\n        var path = name\n        if (parent) {\n          parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n          path = name ? PATH.join2(parent, name) : parent\n        }\n        var mode = FS.getMode(canRead, canWrite)\n        var node = FS.create(path, mode)\n        if (data) {\n          if (typeof data == 'string') {\n            var arr = new Array(data.length)\n            for (var i = 0, len = data.length; i < len; ++i)\n              arr[i] = data.charCodeAt(i)\n            data = arr\n          }\n          FS.chmod(node, mode | 146)\n          var stream = FS.open(node, 577)\n          FS.write(stream, data, 0, data.length, 0, canOwn)\n          FS.close(stream)\n          FS.chmod(node, mode)\n        }\n        return node\n      },\n      createDevice: (parent, name, input, output) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(!!input, !!output)\n        if (!FS.createDevice.major) FS.createDevice.major = 64\n        var dev = FS.makedev(FS.createDevice.major++, 0)\n        FS.registerDevice(dev, {\n          open: stream => {\n            stream.seekable = false\n          },\n          close: stream => {\n            if (output && output.buffer && output.buffer.length) {\n              output(10)\n            }\n          },\n          read: (stream, buffer, offset, length, pos) => {\n            var bytesRead = 0\n            for (var i = 0; i < length; i++) {\n              var result\n              try {\n                result = input()\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n              if (result === undefined && bytesRead === 0) {\n                throw new FS.ErrnoError(6)\n              }\n              if (result === null || result === undefined) break\n              bytesRead++\n              buffer[offset + i] = result\n            }\n            if (bytesRead) {\n              stream.node.timestamp = Date.now()\n            }\n            return bytesRead\n          },\n          write: (stream, buffer, offset, length, pos) => {\n            for (var i = 0; i < length; i++) {\n              try {\n                output(buffer[offset + i])\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n            }\n            if (length) {\n              stream.node.timestamp = Date.now()\n            }\n            return i\n          },\n        })\n        return FS.mkdev(path, mode, dev)\n      },\n      forceLoadFile: obj => {\n        if (obj.isDevice || obj.isFolder || obj.link || obj.contents)\n          return true\n        if (typeof XMLHttpRequest != 'undefined') {\n          throw new Error(\n            'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.'\n          )\n        } else if (read_) {\n          try {\n            obj.contents = intArrayFromString(read_(obj.url), true)\n            obj.usedBytes = obj.contents.length\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n        } else {\n          throw new Error('Cannot load without read() or XMLHttpRequest.')\n        }\n      },\n      createLazyFile: (parent, name, url, canRead, canWrite) => {\n        function LazyUint8Array() {\n          this.lengthKnown = false\n          this.chunks = []\n        }\n        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n          if (idx > this.length - 1 || idx < 0) {\n            return undefined\n          }\n          var chunkOffset = idx % this.chunkSize\n          var chunkNum = (idx / this.chunkSize) | 0\n          return this.getter(chunkNum)[chunkOffset]\n        }\n        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(\n          getter\n        ) {\n          this.getter = getter\n        }\n        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n          var xhr = new XMLHttpRequest()\n          xhr.open('HEAD', url, false)\n          xhr.send(null)\n          if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n            throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n          var datalength = Number(xhr.getResponseHeader('Content-length'))\n          var header\n          var hasByteServing =\n            (header = xhr.getResponseHeader('Accept-Ranges')) &&\n            header === 'bytes'\n          var usesGzip =\n            (header = xhr.getResponseHeader('Content-Encoding')) &&\n            header === 'gzip'\n          var chunkSize = 1024 * 1024\n          if (!hasByteServing) chunkSize = datalength\n          var doXHR = (from, to) => {\n            if (from > to)\n              throw new Error(\n                'invalid range (' +\n                  from +\n                  ', ' +\n                  to +\n                  ') or no bytes requested!'\n              )\n            if (to > datalength - 1)\n              throw new Error(\n                'only ' + datalength + ' bytes available! programmer error!'\n              )\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            if (datalength !== chunkSize)\n              xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to)\n            xhr.responseType = 'arraybuffer'\n            if (xhr.overrideMimeType) {\n              xhr.overrideMimeType('text/plain; charset=x-user-defined')\n            }\n            xhr.send(null)\n            if (\n              !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)\n            )\n              throw new Error(\n                \"Couldn't load \" + url + '. Status: ' + xhr.status\n              )\n            if (xhr.response !== undefined) {\n              return new Uint8Array(xhr.response || [])\n            }\n            return intArrayFromString(xhr.responseText || '', true)\n          }\n          var lazyArray = this\n          lazyArray.setDataGetter(chunkNum => {\n            var start = chunkNum * chunkSize\n            var end = (chunkNum + 1) * chunkSize - 1\n            end = Math.min(end, datalength - 1)\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined') {\n              lazyArray.chunks[chunkNum] = doXHR(start, end)\n            }\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined')\n              throw new Error('doXHR failed!')\n            return lazyArray.chunks[chunkNum]\n          })\n          if (usesGzip || !datalength) {\n            chunkSize = datalength = 1\n            datalength = this.getter(0).length\n            chunkSize = datalength\n            out(\n              'LazyFiles on gzip forces download of the whole file when length is accessed'\n            )\n          }\n          this._length = datalength\n          this._chunkSize = chunkSize\n          this.lengthKnown = true\n        }\n        if (typeof XMLHttpRequest != 'undefined') {\n          if (!ENVIRONMENT_IS_WORKER)\n            throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'\n          var lazyArray = new LazyUint8Array()\n          Object.defineProperties(lazyArray, {\n            length: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._length\n              },\n            },\n            chunkSize: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._chunkSize\n              },\n            },\n          })\n          var properties = { isDevice: false, contents: lazyArray }\n        } else {\n          var properties = { isDevice: false, url: url }\n        }\n        var node = FS.createFile(parent, name, properties, canRead, canWrite)\n        if (properties.contents) {\n          node.contents = properties.contents\n        } else if (properties.url) {\n          node.contents = null\n          node.url = properties.url\n        }\n        Object.defineProperties(node, {\n          usedBytes: {\n            get: function() {\n              return this.contents.length\n            },\n          },\n        })\n        var stream_ops = {}\n        var keys = Object.keys(node.stream_ops)\n        keys.forEach(key => {\n          var fn = node.stream_ops[key]\n          stream_ops[key] = function forceLoadLazyFile() {\n            FS.forceLoadFile(node)\n            return fn.apply(null, arguments)\n          }\n        })\n        function writeChunks(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= contents.length) return 0\n          var size = Math.min(contents.length - position, length)\n          if (contents.slice) {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents[position + i]\n            }\n          } else {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents.get(position + i)\n            }\n          }\n          return size\n        }\n        stream_ops.read = (stream, buffer, offset, length, position) => {\n          FS.forceLoadFile(node)\n          return writeChunks(stream, buffer, offset, length, position)\n        }\n        stream_ops.mmap = (stream, length, position, prot, flags) => {\n          FS.forceLoadFile(node)\n          var ptr = mmapAlloc(length)\n          if (!ptr) {\n            throw new FS.ErrnoError(48)\n          }\n          writeChunks(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        }\n        node.stream_ops = stream_ops\n        return node\n      },\n      createPreloadedFile: (\n        parent,\n        name,\n        url,\n        canRead,\n        canWrite,\n        onload,\n        onerror,\n        dontCreateFile,\n        canOwn,\n        preFinish\n      ) => {\n        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent\n        var dep = getUniqueRunDependency('cp ' + fullname)\n        function processData(byteArray) {\n          function finish(byteArray) {\n            if (preFinish) preFinish()\n            if (!dontCreateFile) {\n              FS.createDataFile(\n                parent,\n                name,\n                byteArray,\n                canRead,\n                canWrite,\n                canOwn\n              )\n            }\n            if (onload) onload()\n            removeRunDependency(dep)\n          }\n          if (\n            Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => {\n              if (onerror) onerror()\n              removeRunDependency(dep)\n            })\n          ) {\n            return\n          }\n          finish(byteArray)\n        }\n        addRunDependency(dep)\n        if (typeof url == 'string') {\n          asyncLoad(url, byteArray => processData(byteArray), onerror)\n        } else {\n          processData(url)\n        }\n      },\n      indexedDB: () => {\n        return (\n          window.indexedDB ||\n          window.mozIndexedDB ||\n          window.webkitIndexedDB ||\n          window.msIndexedDB\n        )\n      },\n      DB_NAME: () => {\n        return 'EM_FS_' + window.location.pathname\n      },\n      DB_VERSION: 20,\n      DB_STORE_NAME: 'FILE_DATA',\n      saveFilesToDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = () => {\n          out('creating db')\n          var db = openRequest.result\n          db.createObjectStore(FS.DB_STORE_NAME)\n        }\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite')\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var putRequest = files.put(\n              FS.analyzePath(path).object.contents,\n              path\n            )\n            putRequest.onsuccess = () => {\n              ok++\n              if (ok + fail == total) finish()\n            }\n            putRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n      loadFilesFromDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = onerror\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          try {\n            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly')\n          } catch (e) {\n            onerror(e)\n            return\n          }\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var getRequest = files.get(path)\n            getRequest.onsuccess = () => {\n              if (FS.analyzePath(path).exists) {\n                FS.unlink(path)\n              }\n              FS.createDataFile(\n                PATH.dirname(path),\n                PATH.basename(path),\n                getRequest.result,\n                true,\n                true,\n                true\n              )\n              ok++\n              if (ok + fail == total) finish()\n            }\n            getRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n    }\n    var SYSCALLS = {\n      DEFAULT_POLLMASK: 5,\n      calculateAt: function(dirfd, path, allowEmpty) {\n        if (PATH.isAbs(path)) {\n          return path\n        }\n        var dir\n        if (dirfd === -100) {\n          dir = FS.cwd()\n        } else {\n          var dirstream = SYSCALLS.getStreamFromFD(dirfd)\n          dir = dirstream.path\n        }\n        if (path.length == 0) {\n          if (!allowEmpty) {\n            throw new FS.ErrnoError(44)\n          }\n          return dir\n        }\n        return PATH.join2(dir, path)\n      },\n      doStat: function(func, path, buf) {\n        try {\n          var stat = func(path)\n        } catch (e) {\n          if (\n            e &&\n            e.node &&\n            PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))\n          ) {\n            return -54\n          }\n          throw e\n        }\n        HEAP32[buf >> 2] = stat.dev\n        HEAP32[(buf + 8) >> 2] = stat.ino\n        HEAP32[(buf + 12) >> 2] = stat.mode\n        HEAPU32[(buf + 16) >> 2] = stat.nlink\n        HEAP32[(buf + 20) >> 2] = stat.uid\n        HEAP32[(buf + 24) >> 2] = stat.gid\n        HEAP32[(buf + 28) >> 2] = stat.rdev\n        ;(tempI64 = [\n          stat.size >>> 0,\n          ((tempDouble = stat.size),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 40) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 44) >> 2] = tempI64[1])\n        HEAP32[(buf + 48) >> 2] = 4096\n        HEAP32[(buf + 52) >> 2] = stat.blocks\n        var atime = stat.atime.getTime()\n        var mtime = stat.mtime.getTime()\n        var ctime = stat.ctime.getTime()\n        ;(tempI64 = [\n          Math.floor(atime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(atime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 56) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 60) >> 2] = tempI64[1])\n        HEAPU32[(buf + 64) >> 2] = (atime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(mtime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(mtime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 72) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 76) >> 2] = tempI64[1])\n        HEAPU32[(buf + 80) >> 2] = (mtime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(ctime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(ctime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 88) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 92) >> 2] = tempI64[1])\n        HEAPU32[(buf + 96) >> 2] = (ctime % 1e3) * 1e3\n        ;(tempI64 = [\n          stat.ino >>> 0,\n          ((tempDouble = stat.ino),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 104) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 108) >> 2] = tempI64[1])\n        return 0\n      },\n      doMsync: function(addr, stream, len, flags, offset) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (flags & 2) {\n          return 0\n        }\n        var buffer = HEAPU8.slice(addr, addr + len)\n        FS.msync(stream, buffer, offset, len, flags)\n      },\n      varargs: undefined,\n      get: function() {\n        SYSCALLS.varargs += 4\n        var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]\n        return ret\n      },\n      getStr: function(ptr) {\n        var ret = UTF8ToString(ptr)\n        return ret\n      },\n      getStreamFromFD: function(fd) {\n        var stream = FS.getStream(fd)\n        if (!stream) throw new FS.ErrnoError(8)\n        return stream\n      },\n    }\n    function ___syscall_fcntl64(fd, cmd, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (cmd) {\n          case 0: {\n            var arg = SYSCALLS.get()\n            if (arg < 0) {\n              return -28\n            }\n            var newStream\n            newStream = FS.createStream(stream, arg)\n            return newStream.fd\n          }\n          case 1:\n          case 2:\n            return 0\n          case 3:\n            return stream.flags\n          case 4: {\n            var arg = SYSCALLS.get()\n            stream.flags |= arg\n            return 0\n          }\n          case 5: {\n            var arg = SYSCALLS.get()\n            var offset = 0\n            HEAP16[(arg + offset) >> 1] = 2\n            return 0\n          }\n          case 6:\n          case 7:\n            return 0\n          case 16:\n          case 8:\n            return -28\n          case 9:\n            setErrNo(28)\n            return -1\n          default: {\n            return -28\n          }\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_getcwd(buf, size) {\n      try {\n        if (size === 0) return -28\n        var cwd = FS.cwd()\n        var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1\n        if (size < cwdLengthInBytes) return -68\n        stringToUTF8(cwd, buf, size)\n        return cwdLengthInBytes\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_ioctl(fd, op, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (op) {\n          case 21509:\n          case 21505: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21510:\n          case 21511:\n          case 21512:\n          case 21506:\n          case 21507:\n          case 21508: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21519: {\n            if (!stream.tty) return -59\n            var argp = SYSCALLS.get()\n            HEAP32[argp >> 2] = 0\n            return 0\n          }\n          case 21520: {\n            if (!stream.tty) return -59\n            return -28\n          }\n          case 21531: {\n            var argp = SYSCALLS.get()\n            return FS.ioctl(stream, op, argp)\n          }\n          case 21523: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21524: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          default:\n            return -28\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_openat(dirfd, path, flags, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        var mode = varargs ? SYSCALLS.get() : 0\n        return FS.open(path, flags, mode).fd\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_readlinkat(dirfd, path, buf, bufsize) {\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        if (bufsize <= 0) return -28\n        var ret = FS.readlink(path)\n        var len = Math.min(bufsize, lengthBytesUTF8(ret))\n        var endChar = HEAP8[buf + len]\n        stringToUTF8(ret, buf, bufsize + 1)\n        HEAP8[buf + len] = endChar\n        return len\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_stat64(path, buf) {\n      try {\n        path = SYSCALLS.getStr(path)\n        return SYSCALLS.doStat(FS.stat, path, buf)\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function _abort() {\n      abort('')\n    }\n    function _emscripten_memcpy_big(dest, src, num) {\n      HEAPU8.copyWithin(dest, src, src + num)\n    }\n    function getHeapMax() {\n      return 2147483648\n    }\n    function emscripten_realloc_buffer(size) {\n      try {\n        wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16)\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        return 1\n      } catch (e) {}\n    }\n    function _emscripten_resize_heap(requestedSize) {\n      var oldSize = HEAPU8.length\n      requestedSize = requestedSize >>> 0\n      var maxHeapSize = getHeapMax()\n      if (requestedSize > maxHeapSize) {\n        return false\n      }\n      let alignUp = (x, multiple) =>\n        x + ((multiple - (x % multiple)) % multiple)\n      for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {\n        var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown)\n        overGrownHeapSize = Math.min(\n          overGrownHeapSize,\n          requestedSize + 100663296\n        )\n        var newSize = Math.min(\n          maxHeapSize,\n          alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)\n        )\n        var replacement = emscripten_realloc_buffer(newSize)\n        if (replacement) {\n          return true\n        }\n      }\n      return false\n    }\n    var ENV = {}\n    function getExecutableName() {\n      return thisProgram || './this.program'\n    }\n    function getEnvStrings() {\n      if (!getEnvStrings.strings) {\n        var lang =\n          (\n            (typeof navigator == 'object' &&\n              navigator.languages &&\n              navigator.languages[0]) ||\n            'C'\n          ).replace('-', '_') + '.UTF-8'\n        var env = {\n          USER: 'web_user',\n          LOGNAME: 'web_user',\n          PATH: '/',\n          PWD: '/',\n          HOME: '/home/web_user',\n          LANG: lang,\n          _: getExecutableName(),\n        }\n        for (var x in ENV) {\n          if (ENV[x] === undefined) delete env[x]\n          else env[x] = ENV[x]\n        }\n        var strings = []\n        for (var x in env) {\n          strings.push(x + '=' + env[x])\n        }\n        getEnvStrings.strings = strings\n      }\n      return getEnvStrings.strings\n    }\n    function writeAsciiToMemory(str, buffer, dontAddNull) {\n      for (var i = 0; i < str.length; ++i) {\n        HEAP8[buffer++ >> 0] = str.charCodeAt(i)\n      }\n      if (!dontAddNull) HEAP8[buffer >> 0] = 0\n    }\n    function _environ_get(__environ, environ_buf) {\n      var bufSize = 0\n      getEnvStrings().forEach(function(string, i) {\n        var ptr = environ_buf + bufSize\n        HEAPU32[(__environ + i * 4) >> 2] = ptr\n        writeAsciiToMemory(string, ptr)\n        bufSize += string.length + 1\n      })\n      return 0\n    }\n    function _environ_sizes_get(penviron_count, penviron_buf_size) {\n      var strings = getEnvStrings()\n      HEAPU32[penviron_count >> 2] = strings.length\n      var bufSize = 0\n      strings.forEach(function(string) {\n        bufSize += string.length + 1\n      })\n      HEAPU32[penviron_buf_size >> 2] = bufSize\n      return 0\n    }\n    function _proc_exit(code) {\n      EXITSTATUS = code\n      if (!keepRuntimeAlive()) {\n        if (Module['onExit']) Module['onExit'](code)\n        ABORT = true\n      }\n      quit_(code, new ExitStatus(code))\n    }\n    function exitJS(status, implicit) {\n      EXITSTATUS = status\n      _proc_exit(status)\n    }\n    var _exit = exitJS\n    function _fd_close(fd) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.close(stream)\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doReadv(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.read(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n        if (curr < len) break\n      }\n      return ret\n    }\n    function _fd_read(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doReadv(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function convertI32PairToI53Checked(lo, hi) {\n      return (hi + 2097152) >>> 0 < 4194305 - !!lo\n        ? (lo >>> 0) + hi * 4294967296\n        : NaN\n    }\n    function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {\n      try {\n        var offset = convertI32PairToI53Checked(offset_low, offset_high)\n        if (isNaN(offset)) return 61\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.llseek(stream, offset, whence)\n        ;(tempI64 = [\n          stream.position >>> 0,\n          ((tempDouble = stream.position),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[newOffset >> 2] = tempI64[0]),\n          (HEAP32[(newOffset + 4) >> 2] = tempI64[1])\n        if (stream.getdents && offset === 0 && whence === 0)\n          stream.getdents = null\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doWritev(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.write(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n      }\n      return ret\n    }\n    function _fd_write(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doWritev(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function __isLeapYear(year) {\n      return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n    }\n    function __arraySum(array, index) {\n      var sum = 0\n      for (var i = 0; i <= index; sum += array[i++]) {}\n      return sum\n    }\n    var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    function __addDays(date, days) {\n      var newDate = new Date(date.getTime())\n      while (days > 0) {\n        var leap = __isLeapYear(newDate.getFullYear())\n        var currentMonth = newDate.getMonth()\n        var daysInCurrentMonth = (leap\n          ? __MONTH_DAYS_LEAP\n          : __MONTH_DAYS_REGULAR)[currentMonth]\n        if (days > daysInCurrentMonth - newDate.getDate()) {\n          days -= daysInCurrentMonth - newDate.getDate() + 1\n          newDate.setDate(1)\n          if (currentMonth < 11) {\n            newDate.setMonth(currentMonth + 1)\n          } else {\n            newDate.setMonth(0)\n            newDate.setFullYear(newDate.getFullYear() + 1)\n          }\n        } else {\n          newDate.setDate(newDate.getDate() + days)\n          return newDate\n        }\n      }\n      return newDate\n    }\n    function writeArrayToMemory(array, buffer) {\n      HEAP8.set(array, buffer)\n    }\n    function _strftime(s, maxsize, format, tm) {\n      var tm_zone = HEAP32[(tm + 40) >> 2]\n      var date = {\n        tm_sec: HEAP32[tm >> 2],\n        tm_min: HEAP32[(tm + 4) >> 2],\n        tm_hour: HEAP32[(tm + 8) >> 2],\n        tm_mday: HEAP32[(tm + 12) >> 2],\n        tm_mon: HEAP32[(tm + 16) >> 2],\n        tm_year: HEAP32[(tm + 20) >> 2],\n        tm_wday: HEAP32[(tm + 24) >> 2],\n        tm_yday: HEAP32[(tm + 28) >> 2],\n        tm_isdst: HEAP32[(tm + 32) >> 2],\n        tm_gmtoff: HEAP32[(tm + 36) >> 2],\n        tm_zone: tm_zone ? UTF8ToString(tm_zone) : '',\n      }\n      var pattern = UTF8ToString(format)\n      var EXPANSION_RULES_1 = {\n        '%c': '%a %b %d %H:%M:%S %Y',\n        '%D': '%m/%d/%y',\n        '%F': '%Y-%m-%d',\n        '%h': '%b',\n        '%r': '%I:%M:%S %p',\n        '%R': '%H:%M',\n        '%T': '%H:%M:%S',\n        '%x': '%m/%d/%y',\n        '%X': '%H:%M:%S',\n        '%Ec': '%c',\n        '%EC': '%C',\n        '%Ex': '%m/%d/%y',\n        '%EX': '%H:%M:%S',\n        '%Ey': '%y',\n        '%EY': '%Y',\n        '%Od': '%d',\n        '%Oe': '%e',\n        '%OH': '%H',\n        '%OI': '%I',\n        '%Om': '%m',\n        '%OM': '%M',\n        '%OS': '%S',\n        '%Ou': '%u',\n        '%OU': '%U',\n        '%OV': '%V',\n        '%Ow': '%w',\n        '%OW': '%W',\n        '%Oy': '%y',\n      }\n      for (var rule in EXPANSION_RULES_1) {\n        pattern = pattern.replace(\n          new RegExp(rule, 'g'),\n          EXPANSION_RULES_1[rule]\n        )\n      }\n      var WEEKDAYS = [\n        'Sunday',\n        'Monday',\n        'Tuesday',\n        'Wednesday',\n        'Thursday',\n        'Friday',\n        'Saturday',\n      ]\n      var MONTHS = [\n        'January',\n        'February',\n        'March',\n        'April',\n        'May',\n        'June',\n        'July',\n        'August',\n        'September',\n        'October',\n        'November',\n        'December',\n      ]\n      function leadingSomething(value, digits, character) {\n        var str = typeof value == 'number' ? value.toString() : value || ''\n        while (str.length < digits) {\n          str = character[0] + str\n        }\n        return str\n      }\n      function leadingNulls(value, digits) {\n        return leadingSomething(value, digits, '0')\n      }\n      function compareByDay(date1, date2) {\n        function sgn(value) {\n          return value < 0 ? -1 : value > 0 ? 1 : 0\n        }\n        var compare\n        if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) {\n          if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) {\n            compare = sgn(date1.getDate() - date2.getDate())\n          }\n        }\n        return compare\n      }\n      function getFirstWeekStartDate(janFourth) {\n        switch (janFourth.getDay()) {\n          case 0:\n            return new Date(janFourth.getFullYear() - 1, 11, 29)\n          case 1:\n            return janFourth\n          case 2:\n            return new Date(janFourth.getFullYear(), 0, 3)\n          case 3:\n            return new Date(janFourth.getFullYear(), 0, 2)\n          case 4:\n            return new Date(janFourth.getFullYear(), 0, 1)\n          case 5:\n            return new Date(janFourth.getFullYear() - 1, 11, 31)\n          case 6:\n            return new Date(janFourth.getFullYear() - 1, 11, 30)\n        }\n      }\n      function getWeekBasedYear(date) {\n        var thisDate = __addDays(\n          new Date(date.tm_year + 1900, 0, 1),\n          date.tm_yday\n        )\n        var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4)\n        var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4)\n        var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear)\n        var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear)\n        if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {\n          if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {\n            return thisDate.getFullYear() + 1\n          }\n          return thisDate.getFullYear()\n        }\n        return thisDate.getFullYear() - 1\n      }\n      var EXPANSION_RULES_2 = {\n        '%a': function(date) {\n          return WEEKDAYS[date.tm_wday].substring(0, 3)\n        },\n        '%A': function(date) {\n          return WEEKDAYS[date.tm_wday]\n        },\n        '%b': function(date) {\n          return MONTHS[date.tm_mon].substring(0, 3)\n        },\n        '%B': function(date) {\n          return MONTHS[date.tm_mon]\n        },\n        '%C': function(date) {\n          var year = date.tm_year + 1900\n          return leadingNulls((year / 100) | 0, 2)\n        },\n        '%d': function(date) {\n          return leadingNulls(date.tm_mday, 2)\n        },\n        '%e': function(date) {\n          return leadingSomething(date.tm_mday, 2, ' ')\n        },\n        '%g': function(date) {\n          return getWeekBasedYear(date)\n            .toString()\n            .substring(2)\n        },\n        '%G': function(date) {\n          return getWeekBasedYear(date)\n        },\n        '%H': function(date) {\n          return leadingNulls(date.tm_hour, 2)\n        },\n        '%I': function(date) {\n          var twelveHour = date.tm_hour\n          if (twelveHour == 0) twelveHour = 12\n          else if (twelveHour > 12) twelveHour -= 12\n          return leadingNulls(twelveHour, 2)\n        },\n        '%j': function(date) {\n          return leadingNulls(\n            date.tm_mday +\n              __arraySum(\n                __isLeapYear(date.tm_year + 1900)\n                  ? __MONTH_DAYS_LEAP\n                  : __MONTH_DAYS_REGULAR,\n                date.tm_mon - 1\n              ),\n            3\n          )\n        },\n        '%m': function(date) {\n          return leadingNulls(date.tm_mon + 1, 2)\n        },\n        '%M': function(date) {\n          return leadingNulls(date.tm_min, 2)\n        },\n        '%n': function() {\n          return '\\n'\n        },\n        '%p': function(date) {\n          if (date.tm_hour >= 0 && date.tm_hour < 12) {\n            return 'AM'\n          }\n          return 'PM'\n        },\n        '%S': function(date) {\n          return leadingNulls(date.tm_sec, 2)\n        },\n        '%t': function() {\n          return '\\t'\n        },\n        '%u': function(date) {\n          return date.tm_wday || 7\n        },\n        '%U': function(date) {\n          var days = date.tm_yday + 7 - date.tm_wday\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%V': function(date) {\n          var val = Math.floor(\n            (date.tm_yday + 7 - ((date.tm_wday + 6) % 7)) / 7\n          )\n          if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) {\n            val++\n          }\n          if (!val) {\n            val = 52\n            var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7\n            if (\n              dec31 == 4 ||\n              (dec31 == 5 && __isLeapYear((date.tm_year % 400) - 1))\n            ) {\n              val++\n            }\n          } else if (val == 53) {\n            var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7\n            if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) val = 1\n          }\n          return leadingNulls(val, 2)\n        },\n        '%w': function(date) {\n          return date.tm_wday\n        },\n        '%W': function(date) {\n          var days = date.tm_yday + 7 - ((date.tm_wday + 6) % 7)\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%y': function(date) {\n          return (date.tm_year + 1900).toString().substring(2)\n        },\n        '%Y': function(date) {\n          return date.tm_year + 1900\n        },\n        '%z': function(date) {\n          var off = date.tm_gmtoff\n          var ahead = off >= 0\n          off = Math.abs(off) / 60\n          off = (off / 60) * 100 + (off % 60)\n          return (ahead ? '+' : '-') + String('0000' + off).slice(-4)\n        },\n        '%Z': function(date) {\n          return date.tm_zone\n        },\n        '%%': function() {\n          return '%'\n        },\n      }\n      pattern = pattern.replace(/%%/g, '\\0\\0')\n      for (var rule in EXPANSION_RULES_2) {\n        if (pattern.includes(rule)) {\n          pattern = pattern.replace(\n            new RegExp(rule, 'g'),\n            EXPANSION_RULES_2[rule](date)\n          )\n        }\n      }\n      pattern = pattern.replace(/\\0\\0/g, '%')\n      var bytes = intArrayFromString(pattern, false)\n      if (bytes.length > maxsize) {\n        return 0\n      }\n      writeArrayToMemory(bytes, s)\n      return bytes.length - 1\n    }\n    function _strftime_l(s, maxsize, format, tm, loc) {\n      return _strftime(s, maxsize, format, tm)\n    }\n    function handleException(e) {\n      if (e instanceof ExitStatus || e == 'unwind') {\n        return EXITSTATUS\n      }\n      quit_(1, e)\n    }\n    function allocateUTF8OnStack(str) {\n      var size = lengthBytesUTF8(str) + 1\n      var ret = stackAlloc(size)\n      stringToUTF8Array(str, HEAP8, ret, size)\n      return ret\n    }\n    function getCFunc(ident) {\n      var func = Module['_' + ident]\n      return func\n    }\n    function ccall(ident, returnType, argTypes, args, opts) {\n      var toC = {\n        string: str => {\n          var ret = 0\n          if (str !== null && str !== undefined && str !== 0) {\n            var len = (str.length << 2) + 1\n            ret = stackAlloc(len)\n            stringToUTF8(str, ret, len)\n          }\n          return ret\n        },\n        array: arr => {\n          var ret = stackAlloc(arr.length)\n          writeArrayToMemory(arr, ret)\n          return ret\n        },\n      }\n      function convertReturnValue(ret) {\n        if (returnType === 'string') {\n          return UTF8ToString(ret)\n        }\n        if (returnType === 'boolean') return Boolean(ret)\n        return ret\n      }\n      var func = getCFunc(ident)\n      var cArgs = []\n      var stack = 0\n      if (args) {\n        for (var i = 0; i < args.length; i++) {\n          var converter = toC[argTypes[i]]\n          if (converter) {\n            if (stack === 0) stack = stackSave()\n            cArgs[i] = converter(args[i])\n          } else {\n            cArgs[i] = args[i]\n          }\n        }\n      }\n      var ret = func.apply(null, cArgs)\n      function onDone(ret) {\n        if (stack !== 0) stackRestore(stack)\n        return convertReturnValue(ret)\n      }\n      ret = onDone(ret)\n      return ret\n    }\n    function cwrap(ident, returnType, argTypes, opts) {\n      argTypes = argTypes || []\n      var numericArgs = argTypes.every(\n        type => type === 'number' || type === 'boolean'\n      )\n      var numericRet = returnType !== 'string'\n      if (numericRet && numericArgs && !opts) {\n        return getCFunc(ident)\n      }\n      return function() {\n        return ccall(ident, returnType, argTypes, arguments, opts)\n      }\n    }\n    function AsciiToString(ptr) {\n      var str = ''\n      while (1) {\n        var ch = HEAPU8[ptr++ >> 0]\n        if (!ch) return str\n        str += String.fromCharCode(ch)\n      }\n    }\n    var FSNode = function(parent, name, mode, rdev) {\n      if (!parent) {\n        parent = this\n      }\n      this.parent = parent\n      this.mount = parent.mount\n      this.mounted = null\n      this.id = FS.nextInode++\n      this.name = name\n      this.mode = mode\n      this.node_ops = {}\n      this.stream_ops = {}\n      this.rdev = rdev\n    }\n    var readMode = 292 | 73\n    var writeMode = 146\n    Object.defineProperties(FSNode.prototype, {\n      read: {\n        get: function() {\n          return (this.mode & readMode) === readMode\n        },\n        set: function(val) {\n          val ? (this.mode |= readMode) : (this.mode &= ~readMode)\n        },\n      },\n      write: {\n        get: function() {\n          return (this.mode & writeMode) === writeMode\n        },\n        set: function(val) {\n          val ? (this.mode |= writeMode) : (this.mode &= ~writeMode)\n        },\n      },\n      isFolder: {\n        get: function() {\n          return FS.isDir(this.mode)\n        },\n      },\n      isDevice: {\n        get: function() {\n          return FS.isChrdev(this.mode)\n        },\n      },\n    })\n    FS.FSNode = FSNode\n    FS.staticInit()\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_unlink'] = FS.unlink\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    if (ENVIRONMENT_IS_NODE) {\n      NODEFS.staticInit()\n    }\n    ERRNO_CODES = {\n      EPERM: 63,\n      ENOENT: 44,\n      ESRCH: 71,\n      EINTR: 27,\n      EIO: 29,\n      ENXIO: 60,\n      E2BIG: 1,\n      ENOEXEC: 45,\n      EBADF: 8,\n      ECHILD: 12,\n      EAGAIN: 6,\n      EWOULDBLOCK: 6,\n      ENOMEM: 48,\n      EACCES: 2,\n      EFAULT: 21,\n      ENOTBLK: 105,\n      EBUSY: 10,\n      EEXIST: 20,\n      EXDEV: 75,\n      ENODEV: 43,\n      ENOTDIR: 54,\n      EISDIR: 31,\n      EINVAL: 28,\n      ENFILE: 41,\n      EMFILE: 33,\n      ENOTTY: 59,\n      ETXTBSY: 74,\n      EFBIG: 22,\n      ENOSPC: 51,\n      ESPIPE: 70,\n      EROFS: 69,\n      EMLINK: 34,\n      EPIPE: 64,\n      EDOM: 18,\n      ERANGE: 68,\n      ENOMSG: 49,\n      EIDRM: 24,\n      ECHRNG: 106,\n      EL2NSYNC: 156,\n      EL3HLT: 107,\n      EL3RST: 108,\n      ELNRNG: 109,\n      EUNATCH: 110,\n      ENOCSI: 111,\n      EL2HLT: 112,\n      EDEADLK: 16,\n      ENOLCK: 46,\n      EBADE: 113,\n      EBADR: 114,\n      EXFULL: 115,\n      ENOANO: 104,\n      EBADRQC: 103,\n      EBADSLT: 102,\n      EDEADLOCK: 16,\n      EBFONT: 101,\n      ENOSTR: 100,\n      ENODATA: 116,\n      ETIME: 117,\n      ENOSR: 118,\n      ENONET: 119,\n      ENOPKG: 120,\n      EREMOTE: 121,\n      ENOLINK: 47,\n      EADV: 122,\n      ESRMNT: 123,\n      ECOMM: 124,\n      EPROTO: 65,\n      EMULTIHOP: 36,\n      EDOTDOT: 125,\n      EBADMSG: 9,\n      ENOTUNIQ: 126,\n      EBADFD: 127,\n      EREMCHG: 128,\n      ELIBACC: 129,\n      ELIBBAD: 130,\n      ELIBSCN: 131,\n      ELIBMAX: 132,\n      ELIBEXEC: 133,\n      ENOSYS: 52,\n      ENOTEMPTY: 55,\n      ENAMETOOLONG: 37,\n      ELOOP: 32,\n      EOPNOTSUPP: 138,\n      EPFNOSUPPORT: 139,\n      ECONNRESET: 15,\n      ENOBUFS: 42,\n      EAFNOSUPPORT: 5,\n      EPROTOTYPE: 67,\n      ENOTSOCK: 57,\n      ENOPROTOOPT: 50,\n      ESHUTDOWN: 140,\n      ECONNREFUSED: 14,\n      EADDRINUSE: 3,\n      ECONNABORTED: 13,\n      ENETUNREACH: 40,\n      ENETDOWN: 38,\n      ETIMEDOUT: 73,\n      EHOSTDOWN: 142,\n      EHOSTUNREACH: 23,\n      EINPROGRESS: 26,\n      EALREADY: 7,\n      EDESTADDRREQ: 17,\n      EMSGSIZE: 35,\n      EPROTONOSUPPORT: 66,\n      ESOCKTNOSUPPORT: 137,\n      EADDRNOTAVAIL: 4,\n      ENETRESET: 39,\n      EISCONN: 30,\n      ENOTCONN: 53,\n      ETOOMANYREFS: 141,\n      EUSERS: 136,\n      EDQUOT: 19,\n      ESTALE: 72,\n      ENOTSUP: 138,\n      ENOMEDIUM: 148,\n      EILSEQ: 25,\n      EOVERFLOW: 61,\n      ECANCELED: 11,\n      ENOTRECOVERABLE: 56,\n      EOWNERDEAD: 62,\n      ESTRPIPE: 135,\n    }\n    var asmLibraryArg = {\n      a: ___cxa_throw,\n      d: ___syscall_fcntl64,\n      r: ___syscall_getcwd,\n      i: ___syscall_ioctl,\n      j: ___syscall_openat,\n      n: ___syscall_readlinkat,\n      o: ___syscall_stat64,\n      b: _abort,\n      f: _emscripten_memcpy_big,\n      m: _emscripten_resize_heap,\n      p: _environ_get,\n      q: _environ_sizes_get,\n      c: _exit,\n      e: _fd_close,\n      h: _fd_read,\n      k: _fd_seek,\n      g: _fd_write,\n      l: _strftime_l,\n    }\n    var asm = createWasm()\n    var ___wasm_call_ctors = (Module['___wasm_call_ctors'] = function() {\n      return (___wasm_call_ctors = Module['___wasm_call_ctors'] =\n        Module['asm']['t']).apply(null, arguments)\n    })\n    var _main = (Module['_main'] = function() {\n      return (_main = Module['_main'] = Module['asm']['u']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___errno_location = (Module['___errno_location'] = function() {\n      return (___errno_location = Module['___errno_location'] =\n        Module['asm']['v']).apply(null, arguments)\n    })\n    var _itk_wasm_input_array_alloc = (Module[\n      '_itk_wasm_input_array_alloc'\n    ] = function() {\n      return (_itk_wasm_input_array_alloc = Module[\n        '_itk_wasm_input_array_alloc'\n      ] = Module['asm']['w']).apply(null, arguments)\n    })\n    var _itk_wasm_input_json_alloc = (Module[\n      '_itk_wasm_input_json_alloc'\n    ] = function() {\n      return (_itk_wasm_input_json_alloc = Module[\n        '_itk_wasm_input_json_alloc'\n      ] = Module['asm']['x']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_address = (Module[\n      '_itk_wasm_output_json_address'\n    ] = function() {\n      return (_itk_wasm_output_json_address = Module[\n        '_itk_wasm_output_json_address'\n      ] = Module['asm']['y']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_size = (Module[\n      '_itk_wasm_output_json_size'\n    ] = function() {\n      return (_itk_wasm_output_json_size = Module[\n        '_itk_wasm_output_json_size'\n      ] = Module['asm']['z']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_address = (Module[\n      '_itk_wasm_output_array_address'\n    ] = function() {\n      return (_itk_wasm_output_array_address = Module[\n        '_itk_wasm_output_array_address'\n      ] = Module['asm']['A']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_size = (Module[\n      '_itk_wasm_output_array_size'\n    ] = function() {\n      return (_itk_wasm_output_array_size = Module[\n        '_itk_wasm_output_array_size'\n      ] = Module['asm']['B']).apply(null, arguments)\n    })\n    var _itk_wasm_free_all = (Module['_itk_wasm_free_all'] = function() {\n      return (_itk_wasm_free_all = Module['_itk_wasm_free_all'] =\n        Module['asm']['C']).apply(null, arguments)\n    })\n    var stackSave = (Module['stackSave'] = function() {\n      return (stackSave = Module['stackSave'] = Module['asm']['E']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackRestore = (Module['stackRestore'] = function() {\n      return (stackRestore = Module['stackRestore'] = Module['asm']['F']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackAlloc = (Module['stackAlloc'] = function() {\n      return (stackAlloc = Module['stackAlloc'] = Module['asm']['G']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___cxa_is_pointer_type = (Module[\n      '___cxa_is_pointer_type'\n    ] = function() {\n      return (___cxa_is_pointer_type = Module['___cxa_is_pointer_type'] =\n        Module['asm']['H']).apply(null, arguments)\n    })\n    Module['addRunDependency'] = addRunDependency\n    Module['removeRunDependency'] = removeRunDependency\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    Module['FS_unlink'] = FS.unlink\n    Module['callMain'] = callMain\n    Module['ccall'] = ccall\n    Module['cwrap'] = cwrap\n    Module['AsciiToString'] = AsciiToString\n    Module['writeArrayToMemory'] = writeArrayToMemory\n    Module['writeAsciiToMemory'] = writeAsciiToMemory\n    var calledRun\n    dependenciesFulfilled = function runCaller() {\n      if (!calledRun) run()\n      if (!calledRun) dependenciesFulfilled = runCaller\n    }\n    function callMain(args) {\n      var entryFunction = Module['_main']\n      args = args || []\n      args.unshift(thisProgram)\n      var argc = args.length\n      var argv = stackAlloc((argc + 1) * 4)\n      var argv_ptr = argv >> 2\n      args.forEach(arg => {\n        HEAP32[argv_ptr++] = allocateUTF8OnStack(arg)\n      })\n      HEAP32[argv_ptr] = 0\n      try {\n        var ret = entryFunction(argc, argv)\n        exitJS(ret, true)\n        return ret\n      } catch (e) {\n        return handleException(e)\n      }\n    }\n    function run(args) {\n      args = args || arguments_\n      if (runDependencies > 0) {\n        return\n      }\n      preRun()\n      if (runDependencies > 0) {\n        return\n      }\n      function doRun() {\n        if (calledRun) return\n        calledRun = true\n        Module['calledRun'] = true\n        if (ABORT) return\n        initRuntime()\n        preMain()\n        readyPromiseResolve(Module)\n        if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']()\n        if (shouldRunNow) callMain(args)\n        postRun()\n      }\n      if (Module['setStatus']) {\n        Module['setStatus']('Running...')\n        setTimeout(function() {\n          setTimeout(function() {\n            Module['setStatus']('')\n          }, 1)\n          doRun()\n        }, 1)\n      } else {\n        doRun()\n      }\n    }\n    if (Module['preInit']) {\n      if (typeof Module['preInit'] == 'function')\n        Module['preInit'] = [Module['preInit']]\n      while (Module['preInit'].length > 0) {\n        Module['preInit'].pop()()\n      }\n    }\n    var shouldRunNow = false\n    if (Module['noInitialRun']) shouldRunNow = false\n    run()\n    Module.mountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      if (FS.isDir(containingDir) || containingDir === '/') {\n        return\n      }\n      var currentDir = '/'\n      var splitContainingDir = containingDir.split(path.sep)\n      for (var ii = 1; ii < splitContainingDir.length; ii++) {\n        currentDir += splitContainingDir[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n      FS.mount(NODEFS, { root: containingDir }, currentDir)\n      return currentDir + path.basename(filePath)\n    }\n    Module.unmountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      FS.unmount(containingDir)\n    }\n    Module.fs_mkdirs = function(dirs) {\n      var currentDir = '/'\n      var splitDirs = dirs.split('/')\n      for (var ii = 1; ii < splitDirs.length; ++ii) {\n        currentDir += splitDirs[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n    }\n    Module.fs_readFile = function(path, opts) {\n      return FS.readFile(path, opts)\n    }\n    Module.fs_writeFile = function(path, data, opts) {\n      return FS.writeFile(path, data, opts)\n    }\n    Module.fs_unlink = function(path) {\n      return FS.unlink(path)\n    }\n    Module.fs_open = function(path, flags, mode) {\n      return FS.open(path, flags, mode)\n    }\n    Module.fs_stat = function(path) {\n      return FS.stat(path)\n    }\n    Module.fs_read = function(stream, buffer, offset, length, position) {\n      return FS.read(stream, buffer, offset, length, position)\n    }\n    Module.fs_close = function(stream) {\n      return FS.close(stream)\n    }\n\n    return ResampleLabelImage.ready\n  }\n})()\nexport default ResampleLabelImage\n"
  },
  {
    "path": "src/IO/ResampleLabelImage/emscripten-build/ResampleLabelImage.umd.js",
    "content": "var ResampleLabelImage = (() => {\n  var _scriptDir =\n    typeof document !== 'undefined' && document.currentScript\n      ? document.currentScript.src\n      : undefined\n  if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename\n  return function(ResampleLabelImage) {\n    ResampleLabelImage = ResampleLabelImage || {}\n\n    var Module =\n      typeof ResampleLabelImage != 'undefined' ? ResampleLabelImage : {}\n    var readyPromiseResolve, readyPromiseReject\n    Module['ready'] = new Promise(function(resolve, reject) {\n      readyPromiseResolve = resolve\n      readyPromiseReject = reject\n    })\n    var mStdout = null\n    var mStderr = null\n    Module['resetModuleStdout'] = function() {\n      mStdout = ''\n    }\n    Module['resetModuleStderr'] = function() {\n      mStderr = ''\n    }\n    Module['print'] = function(text) {\n      console.log(text)\n      mStdout += text + '\\n'\n    }\n    Module['printErr'] = function(text) {\n      console.error(text)\n      mStderr += text + '\\n'\n    }\n    Module['getModuleStdout'] = function() {\n      return mStdout\n    }\n    Module['getModuleStderr'] = function() {\n      return mStderr\n    }\n    var moduleOverrides = Object.assign({}, Module)\n    var arguments_ = []\n    var thisProgram = './this.program'\n    var quit_ = (status, toThrow) => {\n      throw toThrow\n    }\n    var ENVIRONMENT_IS_WEB = typeof window == 'object'\n    var ENVIRONMENT_IS_WORKER = typeof importScripts == 'function'\n    var ENVIRONMENT_IS_NODE =\n      typeof process == 'object' &&\n      typeof process.versions == 'object' &&\n      typeof process.versions.node == 'string'\n    var scriptDirectory = ''\n    function locateFile(path) {\n      if (Module['locateFile']) {\n        return Module['locateFile'](path, scriptDirectory)\n      }\n      return scriptDirectory + path\n    }\n    var read_, readAsync, readBinary, setWindowTitle\n    function logExceptionOnExit(e) {\n      if (e instanceof ExitStatus) return\n      let toLog = e\n      err('exiting due to exception: ' + toLog)\n    }\n    if (ENVIRONMENT_IS_NODE) {\n      var fs = require('fs')\n      var nodePath = require('path')\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = nodePath.dirname(scriptDirectory) + '/'\n      } else {\n        scriptDirectory = __dirname + '/'\n      }\n      read_ = (filename, binary) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        return fs.readFileSync(filename, binary ? undefined : 'utf8')\n      }\n      readBinary = filename => {\n        var ret = read_(filename, true)\n        if (!ret.buffer) {\n          ret = new Uint8Array(ret)\n        }\n        return ret\n      }\n      readAsync = (filename, onload, onerror) => {\n        filename = isFileURI(filename)\n          ? new URL(filename)\n          : nodePath.normalize(filename)\n        fs.readFile(filename, function(err, data) {\n          if (err) onerror(err)\n          else onload(data.buffer)\n        })\n      }\n      if (process['argv'].length > 1) {\n        thisProgram = process['argv'][1].replace(/\\\\/g, '/')\n      }\n      arguments_ = process['argv'].slice(2)\n      process['on']('uncaughtException', function(ex) {\n        if (!(ex instanceof ExitStatus)) {\n          throw ex\n        }\n      })\n      process['on']('unhandledRejection', function(reason) {\n        throw reason\n      })\n      quit_ = (status, toThrow) => {\n        if (keepRuntimeAlive()) {\n          process['exitCode'] = status\n          throw toThrow\n        }\n        logExceptionOnExit(toThrow)\n        process['exit'](status)\n      }\n      Module['inspect'] = function() {\n        return '[Emscripten Module object]'\n      }\n    } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) {\n      if (ENVIRONMENT_IS_WORKER) {\n        scriptDirectory = self.location.href\n      } else if (typeof document != 'undefined' && document.currentScript) {\n        scriptDirectory = document.currentScript.src\n      }\n      if (_scriptDir) {\n        scriptDirectory = _scriptDir\n      }\n      if (scriptDirectory.indexOf('blob:') !== 0) {\n        scriptDirectory = scriptDirectory.substr(\n          0,\n          scriptDirectory.replace(/[?#].*/, '').lastIndexOf('/') + 1\n        )\n      } else {\n        scriptDirectory = ''\n      }\n      {\n        read_ = url => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, false)\n          xhr.send(null)\n          return xhr.responseText\n        }\n        if (ENVIRONMENT_IS_WORKER) {\n          readBinary = url => {\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            xhr.responseType = 'arraybuffer'\n            xhr.send(null)\n            return new Uint8Array(xhr.response)\n          }\n        }\n        readAsync = (url, onload, onerror) => {\n          var xhr = new XMLHttpRequest()\n          xhr.open('GET', url, true)\n          xhr.responseType = 'arraybuffer'\n          xhr.onload = () => {\n            if (xhr.status == 200 || (xhr.status == 0 && xhr.response)) {\n              onload(xhr.response)\n              return\n            }\n            onerror()\n          }\n          xhr.onerror = onerror\n          xhr.send(null)\n        }\n      }\n      setWindowTitle = title => (document.title = title)\n    } else {\n    }\n    var out = Module['print'] || console.log.bind(console)\n    var err = Module['printErr'] || console.warn.bind(console)\n    Object.assign(Module, moduleOverrides)\n    moduleOverrides = null\n    if (Module['arguments']) arguments_ = Module['arguments']\n    if (Module['thisProgram']) thisProgram = Module['thisProgram']\n    if (Module['quit']) quit_ = Module['quit']\n    var wasmBinary\n    if (Module['wasmBinary']) wasmBinary = Module['wasmBinary']\n    var noExitRuntime = Module['noExitRuntime'] || true\n    if (typeof WebAssembly != 'object') {\n      abort('no native wasm support detected')\n    }\n    var wasmMemory\n    var ABORT = false\n    var EXITSTATUS\n    function assert(condition, text) {\n      if (!condition) {\n        abort(text)\n      }\n    }\n    var UTF8Decoder =\n      typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined\n    function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) {\n      var endIdx = idx + maxBytesToRead\n      var endPtr = idx\n      while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr\n      if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) {\n        return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr))\n      }\n      var str = ''\n      while (idx < endPtr) {\n        var u0 = heapOrArray[idx++]\n        if (!(u0 & 128)) {\n          str += String.fromCharCode(u0)\n          continue\n        }\n        var u1 = heapOrArray[idx++] & 63\n        if ((u0 & 224) == 192) {\n          str += String.fromCharCode(((u0 & 31) << 6) | u1)\n          continue\n        }\n        var u2 = heapOrArray[idx++] & 63\n        if ((u0 & 240) == 224) {\n          u0 = ((u0 & 15) << 12) | (u1 << 6) | u2\n        } else {\n          u0 =\n            ((u0 & 7) << 18) |\n            (u1 << 12) |\n            (u2 << 6) |\n            (heapOrArray[idx++] & 63)\n        }\n        if (u0 < 65536) {\n          str += String.fromCharCode(u0)\n        } else {\n          var ch = u0 - 65536\n          str += String.fromCharCode(55296 | (ch >> 10), 56320 | (ch & 1023))\n        }\n      }\n      return str\n    }\n    function UTF8ToString(ptr, maxBytesToRead) {\n      return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''\n    }\n    function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) {\n      if (!(maxBytesToWrite > 0)) return 0\n      var startIdx = outIdx\n      var endIdx = outIdx + maxBytesToWrite - 1\n      for (var i = 0; i < str.length; ++i) {\n        var u = str.charCodeAt(i)\n        if (u >= 55296 && u <= 57343) {\n          var u1 = str.charCodeAt(++i)\n          u = (65536 + ((u & 1023) << 10)) | (u1 & 1023)\n        }\n        if (u <= 127) {\n          if (outIdx >= endIdx) break\n          heap[outIdx++] = u\n        } else if (u <= 2047) {\n          if (outIdx + 1 >= endIdx) break\n          heap[outIdx++] = 192 | (u >> 6)\n          heap[outIdx++] = 128 | (u & 63)\n        } else if (u <= 65535) {\n          if (outIdx + 2 >= endIdx) break\n          heap[outIdx++] = 224 | (u >> 12)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        } else {\n          if (outIdx + 3 >= endIdx) break\n          heap[outIdx++] = 240 | (u >> 18)\n          heap[outIdx++] = 128 | ((u >> 12) & 63)\n          heap[outIdx++] = 128 | ((u >> 6) & 63)\n          heap[outIdx++] = 128 | (u & 63)\n        }\n      }\n      heap[outIdx] = 0\n      return outIdx - startIdx\n    }\n    function stringToUTF8(str, outPtr, maxBytesToWrite) {\n      return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite)\n    }\n    function lengthBytesUTF8(str) {\n      var len = 0\n      for (var i = 0; i < str.length; ++i) {\n        var c = str.charCodeAt(i)\n        if (c <= 127) {\n          len++\n        } else if (c <= 2047) {\n          len += 2\n        } else if (c >= 55296 && c <= 57343) {\n          len += 4\n          ++i\n        } else {\n          len += 3\n        }\n      }\n      return len\n    }\n    var buffer,\n      HEAP8,\n      HEAPU8,\n      HEAP16,\n      HEAPU16,\n      HEAP32,\n      HEAPU32,\n      HEAPF32,\n      HEAPF64\n    function updateGlobalBufferAndViews(buf) {\n      buffer = buf\n      Module['HEAP8'] = HEAP8 = new Int8Array(buf)\n      Module['HEAP16'] = HEAP16 = new Int16Array(buf)\n      Module['HEAP32'] = HEAP32 = new Int32Array(buf)\n      Module['HEAPU8'] = HEAPU8 = new Uint8Array(buf)\n      Module['HEAPU16'] = HEAPU16 = new Uint16Array(buf)\n      Module['HEAPU32'] = HEAPU32 = new Uint32Array(buf)\n      Module['HEAPF32'] = HEAPF32 = new Float32Array(buf)\n      Module['HEAPF64'] = HEAPF64 = new Float64Array(buf)\n    }\n    var INITIAL_MEMORY = Module['INITIAL_MEMORY'] || 16777216\n    var wasmTable\n    var __ATPRERUN__ = []\n    var __ATINIT__ = []\n    var __ATMAIN__ = []\n    var __ATPOSTRUN__ = []\n    var runtimeInitialized = false\n    function keepRuntimeAlive() {\n      return noExitRuntime\n    }\n    function preRun() {\n      if (Module['preRun']) {\n        if (typeof Module['preRun'] == 'function')\n          Module['preRun'] = [Module['preRun']]\n        while (Module['preRun'].length) {\n          addOnPreRun(Module['preRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPRERUN__)\n    }\n    function initRuntime() {\n      runtimeInitialized = true\n      if (!Module['noFSInit'] && !FS.init.initialized) FS.init()\n      FS.ignorePermissions = false\n      TTY.init()\n      callRuntimeCallbacks(__ATINIT__)\n    }\n    function preMain() {\n      callRuntimeCallbacks(__ATMAIN__)\n    }\n    function postRun() {\n      if (Module['postRun']) {\n        if (typeof Module['postRun'] == 'function')\n          Module['postRun'] = [Module['postRun']]\n        while (Module['postRun'].length) {\n          addOnPostRun(Module['postRun'].shift())\n        }\n      }\n      callRuntimeCallbacks(__ATPOSTRUN__)\n    }\n    function addOnPreRun(cb) {\n      __ATPRERUN__.unshift(cb)\n    }\n    function addOnInit(cb) {\n      __ATINIT__.unshift(cb)\n    }\n    function addOnPostRun(cb) {\n      __ATPOSTRUN__.unshift(cb)\n    }\n    var runDependencies = 0\n    var runDependencyWatcher = null\n    var dependenciesFulfilled = null\n    function getUniqueRunDependency(id) {\n      return id\n    }\n    function addRunDependency(id) {\n      runDependencies++\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n    }\n    function removeRunDependency(id) {\n      runDependencies--\n      if (Module['monitorRunDependencies']) {\n        Module['monitorRunDependencies'](runDependencies)\n      }\n      if (runDependencies == 0) {\n        if (runDependencyWatcher !== null) {\n          clearInterval(runDependencyWatcher)\n          runDependencyWatcher = null\n        }\n        if (dependenciesFulfilled) {\n          var callback = dependenciesFulfilled\n          dependenciesFulfilled = null\n          callback()\n        }\n      }\n    }\n    function abort(what) {\n      if (Module['onAbort']) {\n        Module['onAbort'](what)\n      }\n      what = 'Aborted(' + what + ')'\n      err(what)\n      ABORT = true\n      EXITSTATUS = 1\n      what += '. Build with -sASSERTIONS for more info.'\n      var e = new WebAssembly.RuntimeError(what)\n      readyPromiseReject(e)\n      throw e\n    }\n    var dataURIPrefix = 'data:application/octet-stream;base64,'\n    function isDataURI(filename) {\n      return filename.startsWith(dataURIPrefix)\n    }\n    function isFileURI(filename) {\n      return filename.startsWith('file://')\n    }\n    var wasmBinaryFile\n    wasmBinaryFile = 'ResampleLabelImage.umd.wasm'\n    if (!isDataURI(wasmBinaryFile)) {\n      wasmBinaryFile = locateFile(wasmBinaryFile)\n    }\n    function getBinary(file) {\n      try {\n        if (file == wasmBinaryFile && wasmBinary) {\n          return new Uint8Array(wasmBinary)\n        }\n        if (readBinary) {\n          return readBinary(file)\n        }\n        throw 'both async and sync fetching of the wasm failed'\n      } catch (err) {\n        abort(err)\n      }\n    }\n    function getBinaryPromise() {\n      if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) {\n        if (typeof fetch == 'function' && !isFileURI(wasmBinaryFile)) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' })\n            .then(function(response) {\n              if (!response['ok']) {\n                throw \"failed to load wasm binary file at '\" +\n                  wasmBinaryFile +\n                  \"'\"\n              }\n              return response['arrayBuffer']()\n            })\n            .catch(function() {\n              return getBinary(wasmBinaryFile)\n            })\n        } else {\n          if (readAsync) {\n            return new Promise(function(resolve, reject) {\n              readAsync(\n                wasmBinaryFile,\n                function(response) {\n                  resolve(new Uint8Array(response))\n                },\n                reject\n              )\n            })\n          }\n        }\n      }\n      return Promise.resolve().then(function() {\n        return getBinary(wasmBinaryFile)\n      })\n    }\n    function createWasm() {\n      var info = { a: asmLibraryArg }\n      function receiveInstance(instance, module) {\n        var exports = instance.exports\n        Module['asm'] = exports\n        wasmMemory = Module['asm']['s']\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        wasmTable = Module['asm']['D']\n        addOnInit(Module['asm']['t'])\n        removeRunDependency('wasm-instantiate')\n      }\n      addRunDependency('wasm-instantiate')\n      function receiveInstantiationResult(result) {\n        receiveInstance(result['instance'])\n      }\n      function instantiateArrayBuffer(receiver) {\n        return getBinaryPromise()\n          .then(function(binary) {\n            return WebAssembly.instantiate(binary, info)\n          })\n          .then(function(instance) {\n            return instance\n          })\n          .then(receiver, function(reason) {\n            err('failed to asynchronously prepare wasm: ' + reason)\n            abort(reason)\n          })\n      }\n      function instantiateAsync() {\n        if (\n          !wasmBinary &&\n          typeof WebAssembly.instantiateStreaming == 'function' &&\n          !isDataURI(wasmBinaryFile) &&\n          !isFileURI(wasmBinaryFile) &&\n          !ENVIRONMENT_IS_NODE &&\n          typeof fetch == 'function'\n        ) {\n          return fetch(wasmBinaryFile, { credentials: 'same-origin' }).then(\n            function(response) {\n              var result = WebAssembly.instantiateStreaming(response, info)\n              return result.then(receiveInstantiationResult, function(reason) {\n                err('wasm streaming compile failed: ' + reason)\n                err('falling back to ArrayBuffer instantiation')\n                return instantiateArrayBuffer(receiveInstantiationResult)\n              })\n            }\n          )\n        } else {\n          return instantiateArrayBuffer(receiveInstantiationResult)\n        }\n      }\n      if (Module['instantiateWasm']) {\n        try {\n          var exports = Module['instantiateWasm'](info, receiveInstance)\n          return exports\n        } catch (e) {\n          err('Module.instantiateWasm callback failed with error: ' + e)\n          readyPromiseReject(e)\n        }\n      }\n      instantiateAsync().catch(readyPromiseReject)\n      return {}\n    }\n    var tempDouble\n    var tempI64\n    function ExitStatus(status) {\n      this.name = 'ExitStatus'\n      this.message = 'Program terminated with exit(' + status + ')'\n      this.status = status\n    }\n    function callRuntimeCallbacks(callbacks) {\n      while (callbacks.length > 0) {\n        callbacks.shift()(Module)\n      }\n    }\n    function ExceptionInfo(excPtr) {\n      this.excPtr = excPtr\n      this.ptr = excPtr - 24\n      this.set_type = function(type) {\n        HEAPU32[(this.ptr + 4) >> 2] = type\n      }\n      this.get_type = function() {\n        return HEAPU32[(this.ptr + 4) >> 2]\n      }\n      this.set_destructor = function(destructor) {\n        HEAPU32[(this.ptr + 8) >> 2] = destructor\n      }\n      this.get_destructor = function() {\n        return HEAPU32[(this.ptr + 8) >> 2]\n      }\n      this.set_refcount = function(refcount) {\n        HEAP32[this.ptr >> 2] = refcount\n      }\n      this.set_caught = function(caught) {\n        caught = caught ? 1 : 0\n        HEAP8[(this.ptr + 12) >> 0] = caught\n      }\n      this.get_caught = function() {\n        return HEAP8[(this.ptr + 12) >> 0] != 0\n      }\n      this.set_rethrown = function(rethrown) {\n        rethrown = rethrown ? 1 : 0\n        HEAP8[(this.ptr + 13) >> 0] = rethrown\n      }\n      this.get_rethrown = function() {\n        return HEAP8[(this.ptr + 13) >> 0] != 0\n      }\n      this.init = function(type, destructor) {\n        this.set_adjusted_ptr(0)\n        this.set_type(type)\n        this.set_destructor(destructor)\n        this.set_refcount(0)\n        this.set_caught(false)\n        this.set_rethrown(false)\n      }\n      this.add_ref = function() {\n        var value = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = value + 1\n      }\n      this.release_ref = function() {\n        var prev = HEAP32[this.ptr >> 2]\n        HEAP32[this.ptr >> 2] = prev - 1\n        return prev === 1\n      }\n      this.set_adjusted_ptr = function(adjustedPtr) {\n        HEAPU32[(this.ptr + 16) >> 2] = adjustedPtr\n      }\n      this.get_adjusted_ptr = function() {\n        return HEAPU32[(this.ptr + 16) >> 2]\n      }\n      this.get_exception_ptr = function() {\n        var isPointer = ___cxa_is_pointer_type(this.get_type())\n        if (isPointer) {\n          return HEAPU32[this.excPtr >> 2]\n        }\n        var adjusted = this.get_adjusted_ptr()\n        if (adjusted !== 0) return adjusted\n        return this.excPtr\n      }\n    }\n    var exceptionLast = 0\n    var uncaughtExceptionCount = 0\n    function ___cxa_throw(ptr, type, destructor) {\n      var info = new ExceptionInfo(ptr)\n      info.init(type, destructor)\n      exceptionLast = ptr\n      uncaughtExceptionCount++\n      throw ptr\n    }\n    function setErrNo(value) {\n      HEAP32[___errno_location() >> 2] = value\n      return value\n    }\n    var PATH = {\n      isAbs: path => path.charAt(0) === '/',\n      splitPath: filename => {\n        var splitPathRe = /^(\\/?|)([\\s\\S]*?)((?:\\.{1,2}|[^\\/]+?|)(\\.[^.\\/]*|))(?:[\\/]*)$/\n        return splitPathRe.exec(filename).slice(1)\n      },\n      normalizeArray: (parts, allowAboveRoot) => {\n        var up = 0\n        for (var i = parts.length - 1; i >= 0; i--) {\n          var last = parts[i]\n          if (last === '.') {\n            parts.splice(i, 1)\n          } else if (last === '..') {\n            parts.splice(i, 1)\n            up++\n          } else if (up) {\n            parts.splice(i, 1)\n            up--\n          }\n        }\n        if (allowAboveRoot) {\n          for (; up; up--) {\n            parts.unshift('..')\n          }\n        }\n        return parts\n      },\n      normalize: path => {\n        var isAbsolute = PATH.isAbs(path),\n          trailingSlash = path.substr(-1) === '/'\n        path = PATH.normalizeArray(\n          path.split('/').filter(p => !!p),\n          !isAbsolute\n        ).join('/')\n        if (!path && !isAbsolute) {\n          path = '.'\n        }\n        if (path && trailingSlash) {\n          path += '/'\n        }\n        return (isAbsolute ? '/' : '') + path\n      },\n      dirname: path => {\n        var result = PATH.splitPath(path),\n          root = result[0],\n          dir = result[1]\n        if (!root && !dir) {\n          return '.'\n        }\n        if (dir) {\n          dir = dir.substr(0, dir.length - 1)\n        }\n        return root + dir\n      },\n      basename: path => {\n        if (path === '/') return '/'\n        path = PATH.normalize(path)\n        path = path.replace(/\\/$/, '')\n        var lastSlash = path.lastIndexOf('/')\n        if (lastSlash === -1) return path\n        return path.substr(lastSlash + 1)\n      },\n      join: function() {\n        var paths = Array.prototype.slice.call(arguments)\n        return PATH.normalize(paths.join('/'))\n      },\n      join2: (l, r) => {\n        return PATH.normalize(l + '/' + r)\n      },\n    }\n    function getRandomDevice() {\n      if (\n        typeof crypto == 'object' &&\n        typeof crypto['getRandomValues'] == 'function'\n      ) {\n        var randomBuffer = new Uint8Array(1)\n        return () => {\n          crypto.getRandomValues(randomBuffer)\n          return randomBuffer[0]\n        }\n      } else if (ENVIRONMENT_IS_NODE) {\n        try {\n          var crypto_module = require('crypto')\n          return () => crypto_module['randomBytes'](1)[0]\n        } catch (e) {}\n      }\n      return () => abort('randomDevice')\n    }\n    var PATH_FS = {\n      resolve: function() {\n        var resolvedPath = '',\n          resolvedAbsolute = false\n        for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n          var path = i >= 0 ? arguments[i] : FS.cwd()\n          if (typeof path != 'string') {\n            throw new TypeError('Arguments to path.resolve must be strings')\n          } else if (!path) {\n            return ''\n          }\n          resolvedPath = path + '/' + resolvedPath\n          resolvedAbsolute = PATH.isAbs(path)\n        }\n        resolvedPath = PATH.normalizeArray(\n          resolvedPath.split('/').filter(p => !!p),\n          !resolvedAbsolute\n        ).join('/')\n        return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'\n      },\n      relative: (from, to) => {\n        from = PATH_FS.resolve(from).substr(1)\n        to = PATH_FS.resolve(to).substr(1)\n        function trim(arr) {\n          var start = 0\n          for (; start < arr.length; start++) {\n            if (arr[start] !== '') break\n          }\n          var end = arr.length - 1\n          for (; end >= 0; end--) {\n            if (arr[end] !== '') break\n          }\n          if (start > end) return []\n          return arr.slice(start, end - start + 1)\n        }\n        var fromParts = trim(from.split('/'))\n        var toParts = trim(to.split('/'))\n        var length = Math.min(fromParts.length, toParts.length)\n        var samePartsLength = length\n        for (var i = 0; i < length; i++) {\n          if (fromParts[i] !== toParts[i]) {\n            samePartsLength = i\n            break\n          }\n        }\n        var outputParts = []\n        for (var i = samePartsLength; i < fromParts.length; i++) {\n          outputParts.push('..')\n        }\n        outputParts = outputParts.concat(toParts.slice(samePartsLength))\n        return outputParts.join('/')\n      },\n    }\n    function intArrayFromString(stringy, dontAddNull, length) {\n      var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1\n      var u8array = new Array(len)\n      var numBytesWritten = stringToUTF8Array(\n        stringy,\n        u8array,\n        0,\n        u8array.length\n      )\n      if (dontAddNull) u8array.length = numBytesWritten\n      return u8array\n    }\n    var TTY = {\n      ttys: [],\n      init: function() {},\n      shutdown: function() {},\n      register: function(dev, ops) {\n        TTY.ttys[dev] = { input: [], output: [], ops: ops }\n        FS.registerDevice(dev, TTY.stream_ops)\n      },\n      stream_ops: {\n        open: function(stream) {\n          var tty = TTY.ttys[stream.node.rdev]\n          if (!tty) {\n            throw new FS.ErrnoError(43)\n          }\n          stream.tty = tty\n          stream.seekable = false\n        },\n        close: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        fsync: function(stream) {\n          stream.tty.ops.fsync(stream.tty)\n        },\n        read: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.get_char) {\n            throw new FS.ErrnoError(60)\n          }\n          var bytesRead = 0\n          for (var i = 0; i < length; i++) {\n            var result\n            try {\n              result = stream.tty.ops.get_char(stream.tty)\n            } catch (e) {\n              throw new FS.ErrnoError(29)\n            }\n            if (result === undefined && bytesRead === 0) {\n              throw new FS.ErrnoError(6)\n            }\n            if (result === null || result === undefined) break\n            bytesRead++\n            buffer[offset + i] = result\n          }\n          if (bytesRead) {\n            stream.node.timestamp = Date.now()\n          }\n          return bytesRead\n        },\n        write: function(stream, buffer, offset, length, pos) {\n          if (!stream.tty || !stream.tty.ops.put_char) {\n            throw new FS.ErrnoError(60)\n          }\n          try {\n            for (var i = 0; i < length; i++) {\n              stream.tty.ops.put_char(stream.tty, buffer[offset + i])\n            }\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n          if (length) {\n            stream.node.timestamp = Date.now()\n          }\n          return i\n        },\n      },\n      default_tty_ops: {\n        get_char: function(tty) {\n          if (!tty.input.length) {\n            var result = null\n            if (ENVIRONMENT_IS_NODE) {\n              var BUFSIZE = 256\n              var buf = Buffer.alloc(BUFSIZE)\n              var bytesRead = 0\n              try {\n                bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE, -1)\n              } catch (e) {\n                if (e.toString().includes('EOF')) bytesRead = 0\n                else throw e\n              }\n              if (bytesRead > 0) {\n                result = buf.slice(0, bytesRead).toString('utf-8')\n              } else {\n                result = null\n              }\n            } else if (\n              typeof window != 'undefined' &&\n              typeof window.prompt == 'function'\n            ) {\n              result = window.prompt('Input: ')\n              if (result !== null) {\n                result += '\\n'\n              }\n            } else if (typeof readline == 'function') {\n              result = readline()\n              if (result !== null) {\n                result += '\\n'\n              }\n            }\n            if (!result) {\n              return null\n            }\n            tty.input = intArrayFromString(result, true)\n          }\n          return tty.input.shift()\n        },\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            out(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n      default_tty1_ops: {\n        put_char: function(tty, val) {\n          if (val === null || val === 10) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          } else {\n            if (val != 0) tty.output.push(val)\n          }\n        },\n        fsync: function(tty) {\n          if (tty.output && tty.output.length > 0) {\n            err(UTF8ArrayToString(tty.output, 0))\n            tty.output = []\n          }\n        },\n      },\n    }\n    function mmapAlloc(size) {\n      abort()\n    }\n    var MEMFS = {\n      ops_table: null,\n      mount: function(mount) {\n        return MEMFS.createNode(null, '/', 16384 | 511, 0)\n      },\n      createNode: function(parent, name, mode, dev) {\n        if (FS.isBlkdev(mode) || FS.isFIFO(mode)) {\n          throw new FS.ErrnoError(63)\n        }\n        if (!MEMFS.ops_table) {\n          MEMFS.ops_table = {\n            dir: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                lookup: MEMFS.node_ops.lookup,\n                mknod: MEMFS.node_ops.mknod,\n                rename: MEMFS.node_ops.rename,\n                unlink: MEMFS.node_ops.unlink,\n                rmdir: MEMFS.node_ops.rmdir,\n                readdir: MEMFS.node_ops.readdir,\n                symlink: MEMFS.node_ops.symlink,\n              },\n              stream: { llseek: MEMFS.stream_ops.llseek },\n            },\n            file: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: {\n                llseek: MEMFS.stream_ops.llseek,\n                read: MEMFS.stream_ops.read,\n                write: MEMFS.stream_ops.write,\n                allocate: MEMFS.stream_ops.allocate,\n                mmap: MEMFS.stream_ops.mmap,\n                msync: MEMFS.stream_ops.msync,\n              },\n            },\n            link: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n                readlink: MEMFS.node_ops.readlink,\n              },\n              stream: {},\n            },\n            chrdev: {\n              node: {\n                getattr: MEMFS.node_ops.getattr,\n                setattr: MEMFS.node_ops.setattr,\n              },\n              stream: FS.chrdev_stream_ops,\n            },\n          }\n        }\n        var node = FS.createNode(parent, name, mode, dev)\n        if (FS.isDir(node.mode)) {\n          node.node_ops = MEMFS.ops_table.dir.node\n          node.stream_ops = MEMFS.ops_table.dir.stream\n          node.contents = {}\n        } else if (FS.isFile(node.mode)) {\n          node.node_ops = MEMFS.ops_table.file.node\n          node.stream_ops = MEMFS.ops_table.file.stream\n          node.usedBytes = 0\n          node.contents = null\n        } else if (FS.isLink(node.mode)) {\n          node.node_ops = MEMFS.ops_table.link.node\n          node.stream_ops = MEMFS.ops_table.link.stream\n        } else if (FS.isChrdev(node.mode)) {\n          node.node_ops = MEMFS.ops_table.chrdev.node\n          node.stream_ops = MEMFS.ops_table.chrdev.stream\n        }\n        node.timestamp = Date.now()\n        if (parent) {\n          parent.contents[name] = node\n          parent.timestamp = node.timestamp\n        }\n        return node\n      },\n      getFileDataAsTypedArray: function(node) {\n        if (!node.contents) return new Uint8Array(0)\n        if (node.contents.subarray)\n          return node.contents.subarray(0, node.usedBytes)\n        return new Uint8Array(node.contents)\n      },\n      expandFileStorage: function(node, newCapacity) {\n        var prevCapacity = node.contents ? node.contents.length : 0\n        if (prevCapacity >= newCapacity) return\n        var CAPACITY_DOUBLING_MAX = 1024 * 1024\n        newCapacity = Math.max(\n          newCapacity,\n          (prevCapacity *\n            (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125)) >>>\n            0\n        )\n        if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256)\n        var oldContents = node.contents\n        node.contents = new Uint8Array(newCapacity)\n        if (node.usedBytes > 0)\n          node.contents.set(oldContents.subarray(0, node.usedBytes), 0)\n      },\n      resizeFileStorage: function(node, newSize) {\n        if (node.usedBytes == newSize) return\n        if (newSize == 0) {\n          node.contents = null\n          node.usedBytes = 0\n        } else {\n          var oldContents = node.contents\n          node.contents = new Uint8Array(newSize)\n          if (oldContents) {\n            node.contents.set(\n              oldContents.subarray(0, Math.min(newSize, node.usedBytes))\n            )\n          }\n          node.usedBytes = newSize\n        }\n      },\n      node_ops: {\n        getattr: function(node) {\n          var attr = {}\n          attr.dev = FS.isChrdev(node.mode) ? node.id : 1\n          attr.ino = node.id\n          attr.mode = node.mode\n          attr.nlink = 1\n          attr.uid = 0\n          attr.gid = 0\n          attr.rdev = node.rdev\n          if (FS.isDir(node.mode)) {\n            attr.size = 4096\n          } else if (FS.isFile(node.mode)) {\n            attr.size = node.usedBytes\n          } else if (FS.isLink(node.mode)) {\n            attr.size = node.link.length\n          } else {\n            attr.size = 0\n          }\n          attr.atime = new Date(node.timestamp)\n          attr.mtime = new Date(node.timestamp)\n          attr.ctime = new Date(node.timestamp)\n          attr.blksize = 4096\n          attr.blocks = Math.ceil(attr.size / attr.blksize)\n          return attr\n        },\n        setattr: function(node, attr) {\n          if (attr.mode !== undefined) {\n            node.mode = attr.mode\n          }\n          if (attr.timestamp !== undefined) {\n            node.timestamp = attr.timestamp\n          }\n          if (attr.size !== undefined) {\n            MEMFS.resizeFileStorage(node, attr.size)\n          }\n        },\n        lookup: function(parent, name) {\n          throw FS.genericErrors[44]\n        },\n        mknod: function(parent, name, mode, dev) {\n          return MEMFS.createNode(parent, name, mode, dev)\n        },\n        rename: function(old_node, new_dir, new_name) {\n          if (FS.isDir(old_node.mode)) {\n            var new_node\n            try {\n              new_node = FS.lookupNode(new_dir, new_name)\n            } catch (e) {}\n            if (new_node) {\n              for (var i in new_node.contents) {\n                throw new FS.ErrnoError(55)\n              }\n            }\n          }\n          delete old_node.parent.contents[old_node.name]\n          old_node.parent.timestamp = Date.now()\n          old_node.name = new_name\n          new_dir.contents[new_name] = old_node\n          new_dir.timestamp = old_node.parent.timestamp\n          old_node.parent = new_dir\n        },\n        unlink: function(parent, name) {\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        rmdir: function(parent, name) {\n          var node = FS.lookupNode(parent, name)\n          for (var i in node.contents) {\n            throw new FS.ErrnoError(55)\n          }\n          delete parent.contents[name]\n          parent.timestamp = Date.now()\n        },\n        readdir: function(node) {\n          var entries = ['.', '..']\n          for (var key in node.contents) {\n            if (!node.contents.hasOwnProperty(key)) {\n              continue\n            }\n            entries.push(key)\n          }\n          return entries\n        },\n        symlink: function(parent, newname, oldpath) {\n          var node = MEMFS.createNode(parent, newname, 511 | 40960, 0)\n          node.link = oldpath\n          return node\n        },\n        readlink: function(node) {\n          if (!FS.isLink(node.mode)) {\n            throw new FS.ErrnoError(28)\n          }\n          return node.link\n        },\n      },\n      stream_ops: {\n        read: function(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= stream.node.usedBytes) return 0\n          var size = Math.min(stream.node.usedBytes - position, length)\n          if (size > 8 && contents.subarray) {\n            buffer.set(contents.subarray(position, position + size), offset)\n          } else {\n            for (var i = 0; i < size; i++)\n              buffer[offset + i] = contents[position + i]\n          }\n          return size\n        },\n        write: function(stream, buffer, offset, length, position, canOwn) {\n          if (buffer.buffer === HEAP8.buffer) {\n            canOwn = false\n          }\n          if (!length) return 0\n          var node = stream.node\n          node.timestamp = Date.now()\n          if (buffer.subarray && (!node.contents || node.contents.subarray)) {\n            if (canOwn) {\n              node.contents = buffer.subarray(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (node.usedBytes === 0 && position === 0) {\n              node.contents = buffer.slice(offset, offset + length)\n              node.usedBytes = length\n              return length\n            } else if (position + length <= node.usedBytes) {\n              node.contents.set(\n                buffer.subarray(offset, offset + length),\n                position\n              )\n              return length\n            }\n          }\n          MEMFS.expandFileStorage(node, position + length)\n          if (node.contents.subarray && buffer.subarray) {\n            node.contents.set(\n              buffer.subarray(offset, offset + length),\n              position\n            )\n          } else {\n            for (var i = 0; i < length; i++) {\n              node.contents[position + i] = buffer[offset + i]\n            }\n          }\n          node.usedBytes = Math.max(node.usedBytes, position + length)\n          return length\n        },\n        llseek: function(stream, offset, whence) {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              position += stream.node.usedBytes\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        allocate: function(stream, offset, length) {\n          MEMFS.expandFileStorage(stream.node, offset + length)\n          stream.node.usedBytes = Math.max(\n            stream.node.usedBytes,\n            offset + length\n          )\n        },\n        mmap: function(stream, length, position, prot, flags) {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr\n          var allocated\n          var contents = stream.node.contents\n          if (!(flags & 2) && contents.buffer === buffer) {\n            allocated = false\n            ptr = contents.byteOffset\n          } else {\n            if (position > 0 || position + length < contents.length) {\n              if (contents.subarray) {\n                contents = contents.subarray(position, position + length)\n              } else {\n                contents = Array.prototype.slice.call(\n                  contents,\n                  position,\n                  position + length\n                )\n              }\n            }\n            allocated = true\n            ptr = mmapAlloc(length)\n            if (!ptr) {\n              throw new FS.ErrnoError(48)\n            }\n            HEAP8.set(contents, ptr)\n          }\n          return { ptr: ptr, allocated: allocated }\n        },\n        msync: function(stream, buffer, offset, length, mmapFlags) {\n          MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    function asyncLoad(url, onload, onerror, noRunDep) {\n      var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''\n      readAsync(\n        url,\n        arrayBuffer => {\n          assert(\n            arrayBuffer,\n            'Loading data file \"' + url + '\" failed (no arrayBuffer).'\n          )\n          onload(new Uint8Array(arrayBuffer))\n          if (dep) removeRunDependency(dep)\n        },\n        event => {\n          if (onerror) {\n            onerror()\n          } else {\n            throw 'Loading data file \"' + url + '\" failed.'\n          }\n        }\n      )\n      if (dep) addRunDependency(dep)\n    }\n    var ERRNO_CODES = {}\n    var NODEFS = {\n      isWindows: false,\n      staticInit: () => {\n        NODEFS.isWindows = !!process.platform.match(/^win/)\n        var flags = process['binding']('constants')\n        if (flags['fs']) {\n          flags = flags['fs']\n        }\n        NODEFS.flagsForNodeMap = {\n          1024: flags['O_APPEND'],\n          64: flags['O_CREAT'],\n          128: flags['O_EXCL'],\n          256: flags['O_NOCTTY'],\n          0: flags['O_RDONLY'],\n          2: flags['O_RDWR'],\n          4096: flags['O_SYNC'],\n          512: flags['O_TRUNC'],\n          1: flags['O_WRONLY'],\n          131072: flags['O_NOFOLLOW'],\n        }\n      },\n      convertNodeCode: e => {\n        var code = e.code\n        return ERRNO_CODES[code]\n      },\n      mount: mount => {\n        return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0)\n      },\n      createNode: (parent, name, mode, dev) => {\n        if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = FS.createNode(parent, name, mode)\n        node.node_ops = NODEFS.node_ops\n        node.stream_ops = NODEFS.stream_ops\n        return node\n      },\n      getMode: path => {\n        var stat\n        try {\n          stat = fs.lstatSync(path)\n          if (NODEFS.isWindows) {\n            stat.mode = stat.mode | ((stat.mode & 292) >> 2)\n          }\n        } catch (e) {\n          if (!e.code) throw e\n          throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n        }\n        return stat.mode\n      },\n      realPath: node => {\n        var parts = []\n        while (node.parent !== node) {\n          parts.push(node.name)\n          node = node.parent\n        }\n        parts.push(node.mount.opts.root)\n        parts.reverse()\n        return PATH.join.apply(null, parts)\n      },\n      flagsForNode: flags => {\n        flags &= ~2097152\n        flags &= ~2048\n        flags &= ~32768\n        flags &= ~524288\n        flags &= ~65536\n        var newFlags = 0\n        for (var k in NODEFS.flagsForNodeMap) {\n          if (flags & k) {\n            newFlags |= NODEFS.flagsForNodeMap[k]\n            flags ^= k\n          }\n        }\n        if (flags) {\n          throw new FS.ErrnoError(28)\n        }\n        return newFlags\n      },\n      node_ops: {\n        getattr: node => {\n          var path = NODEFS.realPath(node)\n          var stat\n          try {\n            stat = fs.lstatSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          if (NODEFS.isWindows && !stat.blksize) {\n            stat.blksize = 4096\n          }\n          if (NODEFS.isWindows && !stat.blocks) {\n            stat.blocks = ((stat.size + stat.blksize - 1) / stat.blksize) | 0\n          }\n          return {\n            dev: stat.dev,\n            ino: stat.ino,\n            mode: stat.mode,\n            nlink: stat.nlink,\n            uid: stat.uid,\n            gid: stat.gid,\n            rdev: stat.rdev,\n            size: stat.size,\n            atime: stat.atime,\n            mtime: stat.mtime,\n            ctime: stat.ctime,\n            blksize: stat.blksize,\n            blocks: stat.blocks,\n          }\n        },\n        setattr: (node, attr) => {\n          var path = NODEFS.realPath(node)\n          try {\n            if (attr.mode !== undefined) {\n              fs.chmodSync(path, attr.mode)\n              node.mode = attr.mode\n            }\n            if (attr.timestamp !== undefined) {\n              var date = new Date(attr.timestamp)\n              fs.utimesSync(path, date, date)\n            }\n            if (attr.size !== undefined) {\n              fs.truncateSync(path, attr.size)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        lookup: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          var mode = NODEFS.getMode(path)\n          return NODEFS.createNode(parent, name, mode)\n        },\n        mknod: (parent, name, mode, dev) => {\n          var node = NODEFS.createNode(parent, name, mode, dev)\n          var path = NODEFS.realPath(node)\n          try {\n            if (FS.isDir(node.mode)) {\n              fs.mkdirSync(path, node.mode)\n            } else {\n              fs.writeFileSync(path, '', { mode: node.mode })\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          return node\n        },\n        rename: (oldNode, newDir, newName) => {\n          var oldPath = NODEFS.realPath(oldNode)\n          var newPath = PATH.join2(NODEFS.realPath(newDir), newName)\n          try {\n            fs.renameSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n          oldNode.name = newName\n        },\n        unlink: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.unlinkSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        rmdir: (parent, name) => {\n          var path = PATH.join2(NODEFS.realPath(parent), name)\n          try {\n            fs.rmdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readdir: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            return fs.readdirSync(path)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        symlink: (parent, newName, oldPath) => {\n          var newPath = PATH.join2(NODEFS.realPath(parent), newName)\n          try {\n            fs.symlinkSync(oldPath, newPath)\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        readlink: node => {\n          var path = NODEFS.realPath(node)\n          try {\n            path = fs.readlinkSync(path)\n            path = nodePath.relative(\n              nodePath.resolve(node.mount.opts.root),\n              path\n            )\n            return path\n          } catch (e) {\n            if (!e.code) throw e\n            if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28)\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n      },\n      stream_ops: {\n        open: stream => {\n          var path = NODEFS.realPath(stream.node)\n          try {\n            if (FS.isFile(stream.node.mode)) {\n              stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags))\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        close: stream => {\n          try {\n            if (FS.isFile(stream.node.mode) && stream.nfd) {\n              fs.closeSync(stream.nfd)\n            }\n          } catch (e) {\n            if (!e.code) throw e\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        read: (stream, buffer, offset, length, position) => {\n          if (length === 0) return 0\n          try {\n            return fs.readSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        write: (stream, buffer, offset, length, position) => {\n          try {\n            return fs.writeSync(\n              stream.nfd,\n              Buffer.from(buffer.buffer),\n              offset,\n              length,\n              position\n            )\n          } catch (e) {\n            throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n          }\n        },\n        llseek: (stream, offset, whence) => {\n          var position = offset\n          if (whence === 1) {\n            position += stream.position\n          } else if (whence === 2) {\n            if (FS.isFile(stream.node.mode)) {\n              try {\n                var stat = fs.fstatSync(stream.nfd)\n                position += stat.size\n              } catch (e) {\n                throw new FS.ErrnoError(NODEFS.convertNodeCode(e))\n              }\n            }\n          }\n          if (position < 0) {\n            throw new FS.ErrnoError(28)\n          }\n          return position\n        },\n        mmap: (stream, length, position, prot, flags) => {\n          if (!FS.isFile(stream.node.mode)) {\n            throw new FS.ErrnoError(43)\n          }\n          var ptr = mmapAlloc(length)\n          NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        },\n        msync: (stream, buffer, offset, length, mmapFlags) => {\n          NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false)\n          return 0\n        },\n      },\n    }\n    var FS = {\n      root: null,\n      mounts: [],\n      devices: {},\n      streams: [],\n      nextInode: 1,\n      nameTable: null,\n      currentPath: '/',\n      initialized: false,\n      ignorePermissions: true,\n      ErrnoError: null,\n      genericErrors: {},\n      filesystems: null,\n      syncFSRequests: 0,\n      lookupPath: (path, opts = {}) => {\n        path = PATH_FS.resolve(path)\n        if (!path) return { path: '', node: null }\n        var defaults = { follow_mount: true, recurse_count: 0 }\n        opts = Object.assign(defaults, opts)\n        if (opts.recurse_count > 8) {\n          throw new FS.ErrnoError(32)\n        }\n        var parts = path.split('/').filter(p => !!p)\n        var current = FS.root\n        var current_path = '/'\n        for (var i = 0; i < parts.length; i++) {\n          var islast = i === parts.length - 1\n          if (islast && opts.parent) {\n            break\n          }\n          current = FS.lookupNode(current, parts[i])\n          current_path = PATH.join2(current_path, parts[i])\n          if (FS.isMountpoint(current)) {\n            if (!islast || (islast && opts.follow_mount)) {\n              current = current.mounted.root\n            }\n          }\n          if (!islast || opts.follow) {\n            var count = 0\n            while (FS.isLink(current.mode)) {\n              var link = FS.readlink(current_path)\n              current_path = PATH_FS.resolve(PATH.dirname(current_path), link)\n              var lookup = FS.lookupPath(current_path, {\n                recurse_count: opts.recurse_count + 1,\n              })\n              current = lookup.node\n              if (count++ > 40) {\n                throw new FS.ErrnoError(32)\n              }\n            }\n          }\n        }\n        return { path: current_path, node: current }\n      },\n      getPath: node => {\n        var path\n        while (true) {\n          if (FS.isRoot(node)) {\n            var mount = node.mount.mountpoint\n            if (!path) return mount\n            return mount[mount.length - 1] !== '/'\n              ? mount + '/' + path\n              : mount + path\n          }\n          path = path ? node.name + '/' + path : node.name\n          node = node.parent\n        }\n      },\n      hashName: (parentid, name) => {\n        var hash = 0\n        for (var i = 0; i < name.length; i++) {\n          hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0\n        }\n        return ((parentid + hash) >>> 0) % FS.nameTable.length\n      },\n      hashAddNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        node.name_next = FS.nameTable[hash]\n        FS.nameTable[hash] = node\n      },\n      hashRemoveNode: node => {\n        var hash = FS.hashName(node.parent.id, node.name)\n        if (FS.nameTable[hash] === node) {\n          FS.nameTable[hash] = node.name_next\n        } else {\n          var current = FS.nameTable[hash]\n          while (current) {\n            if (current.name_next === node) {\n              current.name_next = node.name_next\n              break\n            }\n            current = current.name_next\n          }\n        }\n      },\n      lookupNode: (parent, name) => {\n        var errCode = FS.mayLookup(parent)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode, parent)\n        }\n        var hash = FS.hashName(parent.id, name)\n        for (var node = FS.nameTable[hash]; node; node = node.name_next) {\n          var nodeName = node.name\n          if (node.parent.id === parent.id && nodeName === name) {\n            return node\n          }\n        }\n        return FS.lookup(parent, name)\n      },\n      createNode: (parent, name, mode, rdev) => {\n        var node = new FS.FSNode(parent, name, mode, rdev)\n        FS.hashAddNode(node)\n        return node\n      },\n      destroyNode: node => {\n        FS.hashRemoveNode(node)\n      },\n      isRoot: node => {\n        return node === node.parent\n      },\n      isMountpoint: node => {\n        return !!node.mounted\n      },\n      isFile: mode => {\n        return (mode & 61440) === 32768\n      },\n      isDir: mode => {\n        return (mode & 61440) === 16384\n      },\n      isLink: mode => {\n        return (mode & 61440) === 40960\n      },\n      isChrdev: mode => {\n        return (mode & 61440) === 8192\n      },\n      isBlkdev: mode => {\n        return (mode & 61440) === 24576\n      },\n      isFIFO: mode => {\n        return (mode & 61440) === 4096\n      },\n      isSocket: mode => {\n        return (mode & 49152) === 49152\n      },\n      flagModes: { r: 0, 'r+': 2, w: 577, 'w+': 578, a: 1089, 'a+': 1090 },\n      modeStringToFlags: str => {\n        var flags = FS.flagModes[str]\n        if (typeof flags == 'undefined') {\n          throw new Error('Unknown file open mode: ' + str)\n        }\n        return flags\n      },\n      flagsToPermissionString: flag => {\n        var perms = ['r', 'w', 'rw'][flag & 3]\n        if (flag & 512) {\n          perms += 'w'\n        }\n        return perms\n      },\n      nodePermissions: (node, perms) => {\n        if (FS.ignorePermissions) {\n          return 0\n        }\n        if (perms.includes('r') && !(node.mode & 292)) {\n          return 2\n        } else if (perms.includes('w') && !(node.mode & 146)) {\n          return 2\n        } else if (perms.includes('x') && !(node.mode & 73)) {\n          return 2\n        }\n        return 0\n      },\n      mayLookup: dir => {\n        var errCode = FS.nodePermissions(dir, 'x')\n        if (errCode) return errCode\n        if (!dir.node_ops.lookup) return 2\n        return 0\n      },\n      mayCreate: (dir, name) => {\n        try {\n          var node = FS.lookupNode(dir, name)\n          return 20\n        } catch (e) {}\n        return FS.nodePermissions(dir, 'wx')\n      },\n      mayDelete: (dir, name, isdir) => {\n        var node\n        try {\n          node = FS.lookupNode(dir, name)\n        } catch (e) {\n          return e.errno\n        }\n        var errCode = FS.nodePermissions(dir, 'wx')\n        if (errCode) {\n          return errCode\n        }\n        if (isdir) {\n          if (!FS.isDir(node.mode)) {\n            return 54\n          }\n          if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) {\n            return 10\n          }\n        } else {\n          if (FS.isDir(node.mode)) {\n            return 31\n          }\n        }\n        return 0\n      },\n      mayOpen: (node, flags) => {\n        if (!node) {\n          return 44\n        }\n        if (FS.isLink(node.mode)) {\n          return 32\n        } else if (FS.isDir(node.mode)) {\n          if (FS.flagsToPermissionString(flags) !== 'r' || flags & 512) {\n            return 31\n          }\n        }\n        return FS.nodePermissions(node, FS.flagsToPermissionString(flags))\n      },\n      MAX_OPEN_FDS: 4096,\n      nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => {\n        for (var fd = fd_start; fd <= fd_end; fd++) {\n          if (!FS.streams[fd]) {\n            return fd\n          }\n        }\n        throw new FS.ErrnoError(33)\n      },\n      getStream: fd => FS.streams[fd],\n      createStream: (stream, fd_start, fd_end) => {\n        if (!FS.FSStream) {\n          FS.FSStream = function() {\n            this.shared = {}\n          }\n          FS.FSStream.prototype = {}\n          Object.defineProperties(FS.FSStream.prototype, {\n            object: {\n              get: function() {\n                return this.node\n              },\n              set: function(val) {\n                this.node = val\n              },\n            },\n            isRead: {\n              get: function() {\n                return (this.flags & 2097155) !== 1\n              },\n            },\n            isWrite: {\n              get: function() {\n                return (this.flags & 2097155) !== 0\n              },\n            },\n            isAppend: {\n              get: function() {\n                return this.flags & 1024\n              },\n            },\n            flags: {\n              get: function() {\n                return this.shared.flags\n              },\n              set: function(val) {\n                this.shared.flags = val\n              },\n            },\n            position: {\n              get: function() {\n                return this.shared.position\n              },\n              set: function(val) {\n                this.shared.position = val\n              },\n            },\n          })\n        }\n        stream = Object.assign(new FS.FSStream(), stream)\n        var fd = FS.nextfd(fd_start, fd_end)\n        stream.fd = fd\n        FS.streams[fd] = stream\n        return stream\n      },\n      closeStream: fd => {\n        FS.streams[fd] = null\n      },\n      chrdev_stream_ops: {\n        open: stream => {\n          var device = FS.getDevice(stream.node.rdev)\n          stream.stream_ops = device.stream_ops\n          if (stream.stream_ops.open) {\n            stream.stream_ops.open(stream)\n          }\n        },\n        llseek: () => {\n          throw new FS.ErrnoError(70)\n        },\n      },\n      major: dev => dev >> 8,\n      minor: dev => dev & 255,\n      makedev: (ma, mi) => (ma << 8) | mi,\n      registerDevice: (dev, ops) => {\n        FS.devices[dev] = { stream_ops: ops }\n      },\n      getDevice: dev => FS.devices[dev],\n      getMounts: mount => {\n        var mounts = []\n        var check = [mount]\n        while (check.length) {\n          var m = check.pop()\n          mounts.push(m)\n          check.push.apply(check, m.mounts)\n        }\n        return mounts\n      },\n      syncfs: (populate, callback) => {\n        if (typeof populate == 'function') {\n          callback = populate\n          populate = false\n        }\n        FS.syncFSRequests++\n        if (FS.syncFSRequests > 1) {\n          err(\n            'warning: ' +\n              FS.syncFSRequests +\n              ' FS.syncfs operations in flight at once, probably just doing extra work'\n          )\n        }\n        var mounts = FS.getMounts(FS.root.mount)\n        var completed = 0\n        function doCallback(errCode) {\n          FS.syncFSRequests--\n          return callback(errCode)\n        }\n        function done(errCode) {\n          if (errCode) {\n            if (!done.errored) {\n              done.errored = true\n              return doCallback(errCode)\n            }\n            return\n          }\n          if (++completed >= mounts.length) {\n            doCallback(null)\n          }\n        }\n        mounts.forEach(mount => {\n          if (!mount.type.syncfs) {\n            return done(null)\n          }\n          mount.type.syncfs(mount, populate, done)\n        })\n      },\n      mount: (type, opts, mountpoint) => {\n        var root = mountpoint === '/'\n        var pseudo = !mountpoint\n        var node\n        if (root && FS.root) {\n          throw new FS.ErrnoError(10)\n        } else if (!root && !pseudo) {\n          var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n          mountpoint = lookup.path\n          node = lookup.node\n          if (FS.isMountpoint(node)) {\n            throw new FS.ErrnoError(10)\n          }\n          if (!FS.isDir(node.mode)) {\n            throw new FS.ErrnoError(54)\n          }\n        }\n        var mount = {\n          type: type,\n          opts: opts,\n          mountpoint: mountpoint,\n          mounts: [],\n        }\n        var mountRoot = type.mount(mount)\n        mountRoot.mount = mount\n        mount.root = mountRoot\n        if (root) {\n          FS.root = mountRoot\n        } else if (node) {\n          node.mounted = mount\n          if (node.mount) {\n            node.mount.mounts.push(mount)\n          }\n        }\n        return mountRoot\n      },\n      unmount: mountpoint => {\n        var lookup = FS.lookupPath(mountpoint, { follow_mount: false })\n        if (!FS.isMountpoint(lookup.node)) {\n          throw new FS.ErrnoError(28)\n        }\n        var node = lookup.node\n        var mount = node.mounted\n        var mounts = FS.getMounts(mount)\n        Object.keys(FS.nameTable).forEach(hash => {\n          var current = FS.nameTable[hash]\n          while (current) {\n            var next = current.name_next\n            if (mounts.includes(current.mount)) {\n              FS.destroyNode(current)\n            }\n            current = next\n          }\n        })\n        node.mounted = null\n        var idx = node.mount.mounts.indexOf(mount)\n        node.mount.mounts.splice(idx, 1)\n      },\n      lookup: (parent, name) => {\n        return parent.node_ops.lookup(parent, name)\n      },\n      mknod: (path, mode, dev) => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        if (!name || name === '.' || name === '..') {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.mayCreate(parent, name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.mknod) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.mknod(parent, name, mode, dev)\n      },\n      create: (path, mode) => {\n        mode = mode !== undefined ? mode : 438\n        mode &= 4095\n        mode |= 32768\n        return FS.mknod(path, mode, 0)\n      },\n      mkdir: (path, mode) => {\n        mode = mode !== undefined ? mode : 511\n        mode &= 511 | 512\n        mode |= 16384\n        return FS.mknod(path, mode, 0)\n      },\n      mkdirTree: (path, mode) => {\n        var dirs = path.split('/')\n        var d = ''\n        for (var i = 0; i < dirs.length; ++i) {\n          if (!dirs[i]) continue\n          d += '/' + dirs[i]\n          try {\n            FS.mkdir(d, mode)\n          } catch (e) {\n            if (e.errno != 20) throw e\n          }\n        }\n      },\n      mkdev: (path, mode, dev) => {\n        if (typeof dev == 'undefined') {\n          dev = mode\n          mode = 438\n        }\n        mode |= 8192\n        return FS.mknod(path, mode, dev)\n      },\n      symlink: (oldpath, newpath) => {\n        if (!PATH_FS.resolve(oldpath)) {\n          throw new FS.ErrnoError(44)\n        }\n        var lookup = FS.lookupPath(newpath, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var newname = PATH.basename(newpath)\n        var errCode = FS.mayCreate(parent, newname)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.symlink) {\n          throw new FS.ErrnoError(63)\n        }\n        return parent.node_ops.symlink(parent, newname, oldpath)\n      },\n      rename: (old_path, new_path) => {\n        var old_dirname = PATH.dirname(old_path)\n        var new_dirname = PATH.dirname(new_path)\n        var old_name = PATH.basename(old_path)\n        var new_name = PATH.basename(new_path)\n        var lookup, old_dir, new_dir\n        lookup = FS.lookupPath(old_path, { parent: true })\n        old_dir = lookup.node\n        lookup = FS.lookupPath(new_path, { parent: true })\n        new_dir = lookup.node\n        if (!old_dir || !new_dir) throw new FS.ErrnoError(44)\n        if (old_dir.mount !== new_dir.mount) {\n          throw new FS.ErrnoError(75)\n        }\n        var old_node = FS.lookupNode(old_dir, old_name)\n        var relative = PATH_FS.relative(old_path, new_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(28)\n        }\n        relative = PATH_FS.relative(new_path, old_dirname)\n        if (relative.charAt(0) !== '.') {\n          throw new FS.ErrnoError(55)\n        }\n        var new_node\n        try {\n          new_node = FS.lookupNode(new_dir, new_name)\n        } catch (e) {}\n        if (old_node === new_node) {\n          return\n        }\n        var isdir = FS.isDir(old_node.mode)\n        var errCode = FS.mayDelete(old_dir, old_name, isdir)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        errCode = new_node\n          ? FS.mayDelete(new_dir, new_name, isdir)\n          : FS.mayCreate(new_dir, new_name)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!old_dir.node_ops.rename) {\n          throw new FS.ErrnoError(63)\n        }\n        if (\n          FS.isMountpoint(old_node) ||\n          (new_node && FS.isMountpoint(new_node))\n        ) {\n          throw new FS.ErrnoError(10)\n        }\n        if (new_dir !== old_dir) {\n          errCode = FS.nodePermissions(old_dir, 'w')\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        FS.hashRemoveNode(old_node)\n        try {\n          old_dir.node_ops.rename(old_node, new_dir, new_name)\n        } catch (e) {\n          throw e\n        } finally {\n          FS.hashAddNode(old_node)\n        }\n      },\n      rmdir: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, true)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.rmdir) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.rmdir(parent, name)\n        FS.destroyNode(node)\n      },\n      readdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        if (!node.node_ops.readdir) {\n          throw new FS.ErrnoError(54)\n        }\n        return node.node_ops.readdir(node)\n      },\n      unlink: path => {\n        var lookup = FS.lookupPath(path, { parent: true })\n        var parent = lookup.node\n        if (!parent) {\n          throw new FS.ErrnoError(44)\n        }\n        var name = PATH.basename(path)\n        var node = FS.lookupNode(parent, name)\n        var errCode = FS.mayDelete(parent, name, false)\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        if (!parent.node_ops.unlink) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isMountpoint(node)) {\n          throw new FS.ErrnoError(10)\n        }\n        parent.node_ops.unlink(parent, name)\n        FS.destroyNode(node)\n      },\n      readlink: path => {\n        var lookup = FS.lookupPath(path)\n        var link = lookup.node\n        if (!link) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!link.node_ops.readlink) {\n          throw new FS.ErrnoError(28)\n        }\n        return PATH_FS.resolve(\n          FS.getPath(link.parent),\n          link.node_ops.readlink(link)\n        )\n      },\n      stat: (path, dontFollow) => {\n        var lookup = FS.lookupPath(path, { follow: !dontFollow })\n        var node = lookup.node\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!node.node_ops.getattr) {\n          throw new FS.ErrnoError(63)\n        }\n        return node.node_ops.getattr(node)\n      },\n      lstat: path => {\n        return FS.stat(path, true)\n      },\n      chmod: (path, mode, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, {\n          mode: (mode & 4095) | (node.mode & ~4095),\n          timestamp: Date.now(),\n        })\n      },\n      lchmod: (path, mode) => {\n        FS.chmod(path, mode, true)\n      },\n      fchmod: (fd, mode) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chmod(stream.node, mode)\n      },\n      chown: (path, uid, gid, dontFollow) => {\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: !dontFollow })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        node.node_ops.setattr(node, { timestamp: Date.now() })\n      },\n      lchown: (path, uid, gid) => {\n        FS.chown(path, uid, gid, true)\n      },\n      fchown: (fd, uid, gid) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        FS.chown(stream.node, uid, gid)\n      },\n      truncate: (path, len) => {\n        if (len < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        var node\n        if (typeof path == 'string') {\n          var lookup = FS.lookupPath(path, { follow: true })\n          node = lookup.node\n        } else {\n          node = path\n        }\n        if (!node.node_ops.setattr) {\n          throw new FS.ErrnoError(63)\n        }\n        if (FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!FS.isFile(node.mode)) {\n          throw new FS.ErrnoError(28)\n        }\n        var errCode = FS.nodePermissions(node, 'w')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        node.node_ops.setattr(node, { size: len, timestamp: Date.now() })\n      },\n      ftruncate: (fd, len) => {\n        var stream = FS.getStream(fd)\n        if (!stream) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(28)\n        }\n        FS.truncate(stream.node, len)\n      },\n      utime: (path, atime, mtime) => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        var node = lookup.node\n        node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) })\n      },\n      open: (path, flags, mode) => {\n        if (path === '') {\n          throw new FS.ErrnoError(44)\n        }\n        flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags\n        mode = typeof mode == 'undefined' ? 438 : mode\n        if (flags & 64) {\n          mode = (mode & 4095) | 32768\n        } else {\n          mode = 0\n        }\n        var node\n        if (typeof path == 'object') {\n          node = path\n        } else {\n          path = PATH.normalize(path)\n          try {\n            var lookup = FS.lookupPath(path, { follow: !(flags & 131072) })\n            node = lookup.node\n          } catch (e) {}\n        }\n        var created = false\n        if (flags & 64) {\n          if (node) {\n            if (flags & 128) {\n              throw new FS.ErrnoError(20)\n            }\n          } else {\n            node = FS.mknod(path, mode, 0)\n            created = true\n          }\n        }\n        if (!node) {\n          throw new FS.ErrnoError(44)\n        }\n        if (FS.isChrdev(node.mode)) {\n          flags &= ~512\n        }\n        if (flags & 65536 && !FS.isDir(node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        if (!created) {\n          var errCode = FS.mayOpen(node, flags)\n          if (errCode) {\n            throw new FS.ErrnoError(errCode)\n          }\n        }\n        if (flags & 512 && !created) {\n          FS.truncate(node, 0)\n        }\n        flags &= ~(128 | 512 | 131072)\n        var stream = FS.createStream({\n          node: node,\n          path: FS.getPath(node),\n          flags: flags,\n          seekable: true,\n          position: 0,\n          stream_ops: node.stream_ops,\n          ungotten: [],\n          error: false,\n        })\n        if (stream.stream_ops.open) {\n          stream.stream_ops.open(stream)\n        }\n        if (Module['logReadFiles'] && !(flags & 1)) {\n          if (!FS.readFiles) FS.readFiles = {}\n          if (!(path in FS.readFiles)) {\n            FS.readFiles[path] = 1\n          }\n        }\n        return stream\n      },\n      close: stream => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (stream.getdents) stream.getdents = null\n        try {\n          if (stream.stream_ops.close) {\n            stream.stream_ops.close(stream)\n          }\n        } catch (e) {\n          throw e\n        } finally {\n          FS.closeStream(stream.fd)\n        }\n        stream.fd = null\n      },\n      isClosed: stream => {\n        return stream.fd === null\n      },\n      llseek: (stream, offset, whence) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!stream.seekable || !stream.stream_ops.llseek) {\n          throw new FS.ErrnoError(70)\n        }\n        if (whence != 0 && whence != 1 && whence != 2) {\n          throw new FS.ErrnoError(28)\n        }\n        stream.position = stream.stream_ops.llseek(stream, offset, whence)\n        stream.ungotten = []\n        return stream.position\n      },\n      read: (stream, buffer, offset, length, position) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.read) {\n          throw new FS.ErrnoError(28)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesRead = stream.stream_ops.read(\n          stream,\n          buffer,\n          offset,\n          length,\n          position\n        )\n        if (!seeking) stream.position += bytesRead\n        return bytesRead\n      },\n      write: (stream, buffer, offset, length, position, canOwn) => {\n        if (length < 0 || position < 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(31)\n        }\n        if (!stream.stream_ops.write) {\n          throw new FS.ErrnoError(28)\n        }\n        if (stream.seekable && stream.flags & 1024) {\n          FS.llseek(stream, 0, 2)\n        }\n        var seeking = typeof position != 'undefined'\n        if (!seeking) {\n          position = stream.position\n        } else if (!stream.seekable) {\n          throw new FS.ErrnoError(70)\n        }\n        var bytesWritten = stream.stream_ops.write(\n          stream,\n          buffer,\n          offset,\n          length,\n          position,\n          canOwn\n        )\n        if (!seeking) stream.position += bytesWritten\n        return bytesWritten\n      },\n      allocate: (stream, offset, length) => {\n        if (FS.isClosed(stream)) {\n          throw new FS.ErrnoError(8)\n        }\n        if (offset < 0 || length <= 0) {\n          throw new FS.ErrnoError(28)\n        }\n        if ((stream.flags & 2097155) === 0) {\n          throw new FS.ErrnoError(8)\n        }\n        if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (!stream.stream_ops.allocate) {\n          throw new FS.ErrnoError(138)\n        }\n        stream.stream_ops.allocate(stream, offset, length)\n      },\n      mmap: (stream, length, position, prot, flags) => {\n        if (\n          (prot & 2) !== 0 &&\n          (flags & 2) === 0 &&\n          (stream.flags & 2097155) !== 2\n        ) {\n          throw new FS.ErrnoError(2)\n        }\n        if ((stream.flags & 2097155) === 1) {\n          throw new FS.ErrnoError(2)\n        }\n        if (!stream.stream_ops.mmap) {\n          throw new FS.ErrnoError(43)\n        }\n        return stream.stream_ops.mmap(stream, length, position, prot, flags)\n      },\n      msync: (stream, buffer, offset, length, mmapFlags) => {\n        if (!stream.stream_ops.msync) {\n          return 0\n        }\n        return stream.stream_ops.msync(\n          stream,\n          buffer,\n          offset,\n          length,\n          mmapFlags\n        )\n      },\n      munmap: stream => 0,\n      ioctl: (stream, cmd, arg) => {\n        if (!stream.stream_ops.ioctl) {\n          throw new FS.ErrnoError(59)\n        }\n        return stream.stream_ops.ioctl(stream, cmd, arg)\n      },\n      readFile: (path, opts = {}) => {\n        opts.flags = opts.flags || 0\n        opts.encoding = opts.encoding || 'binary'\n        if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') {\n          throw new Error('Invalid encoding type \"' + opts.encoding + '\"')\n        }\n        var ret\n        var stream = FS.open(path, opts.flags)\n        var stat = FS.stat(path)\n        var length = stat.size\n        var buf = new Uint8Array(length)\n        FS.read(stream, buf, 0, length, 0)\n        if (opts.encoding === 'utf8') {\n          ret = UTF8ArrayToString(buf, 0)\n        } else if (opts.encoding === 'binary') {\n          ret = buf\n        }\n        FS.close(stream)\n        return ret\n      },\n      writeFile: (path, data, opts = {}) => {\n        opts.flags = opts.flags || 577\n        var stream = FS.open(path, opts.flags, opts.mode)\n        if (typeof data == 'string') {\n          var buf = new Uint8Array(lengthBytesUTF8(data) + 1)\n          var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length)\n          FS.write(stream, buf, 0, actualNumBytes, undefined, opts.canOwn)\n        } else if (ArrayBuffer.isView(data)) {\n          FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn)\n        } else {\n          throw new Error('Unsupported data type')\n        }\n        FS.close(stream)\n      },\n      cwd: () => FS.currentPath,\n      chdir: path => {\n        var lookup = FS.lookupPath(path, { follow: true })\n        if (lookup.node === null) {\n          throw new FS.ErrnoError(44)\n        }\n        if (!FS.isDir(lookup.node.mode)) {\n          throw new FS.ErrnoError(54)\n        }\n        var errCode = FS.nodePermissions(lookup.node, 'x')\n        if (errCode) {\n          throw new FS.ErrnoError(errCode)\n        }\n        FS.currentPath = lookup.path\n      },\n      createDefaultDirectories: () => {\n        FS.mkdir('/tmp')\n        FS.mkdir('/home')\n        FS.mkdir('/home/web_user')\n      },\n      createDefaultDevices: () => {\n        FS.mkdir('/dev')\n        FS.registerDevice(FS.makedev(1, 3), {\n          read: () => 0,\n          write: (stream, buffer, offset, length, pos) => length,\n        })\n        FS.mkdev('/dev/null', FS.makedev(1, 3))\n        TTY.register(FS.makedev(5, 0), TTY.default_tty_ops)\n        TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops)\n        FS.mkdev('/dev/tty', FS.makedev(5, 0))\n        FS.mkdev('/dev/tty1', FS.makedev(6, 0))\n        var random_device = getRandomDevice()\n        FS.createDevice('/dev', 'random', random_device)\n        FS.createDevice('/dev', 'urandom', random_device)\n        FS.mkdir('/dev/shm')\n        FS.mkdir('/dev/shm/tmp')\n      },\n      createSpecialDirectories: () => {\n        FS.mkdir('/proc')\n        var proc_self = FS.mkdir('/proc/self')\n        FS.mkdir('/proc/self/fd')\n        FS.mount(\n          {\n            mount: () => {\n              var node = FS.createNode(proc_self, 'fd', 16384 | 511, 73)\n              node.node_ops = {\n                lookup: (parent, name) => {\n                  var fd = +name\n                  var stream = FS.getStream(fd)\n                  if (!stream) throw new FS.ErrnoError(8)\n                  var ret = {\n                    parent: null,\n                    mount: { mountpoint: 'fake' },\n                    node_ops: { readlink: () => stream.path },\n                  }\n                  ret.parent = ret\n                  return ret\n                },\n              }\n              return node\n            },\n          },\n          {},\n          '/proc/self/fd'\n        )\n      },\n      createStandardStreams: () => {\n        if (Module['stdin']) {\n          FS.createDevice('/dev', 'stdin', Module['stdin'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdin')\n        }\n        if (Module['stdout']) {\n          FS.createDevice('/dev', 'stdout', null, Module['stdout'])\n        } else {\n          FS.symlink('/dev/tty', '/dev/stdout')\n        }\n        if (Module['stderr']) {\n          FS.createDevice('/dev', 'stderr', null, Module['stderr'])\n        } else {\n          FS.symlink('/dev/tty1', '/dev/stderr')\n        }\n        var stdin = FS.open('/dev/stdin', 0)\n        var stdout = FS.open('/dev/stdout', 1)\n        var stderr = FS.open('/dev/stderr', 1)\n      },\n      ensureErrnoError: () => {\n        if (FS.ErrnoError) return\n        FS.ErrnoError = function ErrnoError(errno, node) {\n          this.node = node\n          this.setErrno = function(errno) {\n            this.errno = errno\n          }\n          this.setErrno(errno)\n          this.message = 'FS error'\n        }\n        FS.ErrnoError.prototype = new Error()\n        FS.ErrnoError.prototype.constructor = FS.ErrnoError\n        ;[44].forEach(code => {\n          FS.genericErrors[code] = new FS.ErrnoError(code)\n          FS.genericErrors[code].stack = '<generic error, no stack>'\n        })\n      },\n      staticInit: () => {\n        FS.ensureErrnoError()\n        FS.nameTable = new Array(4096)\n        FS.mount(MEMFS, {}, '/')\n        FS.createDefaultDirectories()\n        FS.createDefaultDevices()\n        FS.createSpecialDirectories()\n        FS.filesystems = { MEMFS: MEMFS, NODEFS: NODEFS }\n      },\n      init: (input, output, error) => {\n        FS.init.initialized = true\n        FS.ensureErrnoError()\n        Module['stdin'] = input || Module['stdin']\n        Module['stdout'] = output || Module['stdout']\n        Module['stderr'] = error || Module['stderr']\n        FS.createStandardStreams()\n      },\n      quit: () => {\n        FS.init.initialized = false\n        for (var i = 0; i < FS.streams.length; i++) {\n          var stream = FS.streams[i]\n          if (!stream) {\n            continue\n          }\n          FS.close(stream)\n        }\n      },\n      getMode: (canRead, canWrite) => {\n        var mode = 0\n        if (canRead) mode |= 292 | 73\n        if (canWrite) mode |= 146\n        return mode\n      },\n      findObject: (path, dontResolveLastLink) => {\n        var ret = FS.analyzePath(path, dontResolveLastLink)\n        if (!ret.exists) {\n          return null\n        }\n        return ret.object\n      },\n      analyzePath: (path, dontResolveLastLink) => {\n        try {\n          var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          path = lookup.path\n        } catch (e) {}\n        var ret = {\n          isRoot: false,\n          exists: false,\n          error: 0,\n          name: null,\n          path: null,\n          object: null,\n          parentExists: false,\n          parentPath: null,\n          parentObject: null,\n        }\n        try {\n          var lookup = FS.lookupPath(path, { parent: true })\n          ret.parentExists = true\n          ret.parentPath = lookup.path\n          ret.parentObject = lookup.node\n          ret.name = PATH.basename(path)\n          lookup = FS.lookupPath(path, { follow: !dontResolveLastLink })\n          ret.exists = true\n          ret.path = lookup.path\n          ret.object = lookup.node\n          ret.name = lookup.node.name\n          ret.isRoot = lookup.path === '/'\n        } catch (e) {\n          ret.error = e.errno\n        }\n        return ret\n      },\n      createPath: (parent, path, canRead, canWrite) => {\n        parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n        var parts = path.split('/').reverse()\n        while (parts.length) {\n          var part = parts.pop()\n          if (!part) continue\n          var current = PATH.join2(parent, part)\n          try {\n            FS.mkdir(current)\n          } catch (e) {}\n          parent = current\n        }\n        return current\n      },\n      createFile: (parent, name, properties, canRead, canWrite) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(canRead, canWrite)\n        return FS.create(path, mode)\n      },\n      createDataFile: (parent, name, data, canRead, canWrite, canOwn) => {\n        var path = name\n        if (parent) {\n          parent = typeof parent == 'string' ? parent : FS.getPath(parent)\n          path = name ? PATH.join2(parent, name) : parent\n        }\n        var mode = FS.getMode(canRead, canWrite)\n        var node = FS.create(path, mode)\n        if (data) {\n          if (typeof data == 'string') {\n            var arr = new Array(data.length)\n            for (var i = 0, len = data.length; i < len; ++i)\n              arr[i] = data.charCodeAt(i)\n            data = arr\n          }\n          FS.chmod(node, mode | 146)\n          var stream = FS.open(node, 577)\n          FS.write(stream, data, 0, data.length, 0, canOwn)\n          FS.close(stream)\n          FS.chmod(node, mode)\n        }\n        return node\n      },\n      createDevice: (parent, name, input, output) => {\n        var path = PATH.join2(\n          typeof parent == 'string' ? parent : FS.getPath(parent),\n          name\n        )\n        var mode = FS.getMode(!!input, !!output)\n        if (!FS.createDevice.major) FS.createDevice.major = 64\n        var dev = FS.makedev(FS.createDevice.major++, 0)\n        FS.registerDevice(dev, {\n          open: stream => {\n            stream.seekable = false\n          },\n          close: stream => {\n            if (output && output.buffer && output.buffer.length) {\n              output(10)\n            }\n          },\n          read: (stream, buffer, offset, length, pos) => {\n            var bytesRead = 0\n            for (var i = 0; i < length; i++) {\n              var result\n              try {\n                result = input()\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n              if (result === undefined && bytesRead === 0) {\n                throw new FS.ErrnoError(6)\n              }\n              if (result === null || result === undefined) break\n              bytesRead++\n              buffer[offset + i] = result\n            }\n            if (bytesRead) {\n              stream.node.timestamp = Date.now()\n            }\n            return bytesRead\n          },\n          write: (stream, buffer, offset, length, pos) => {\n            for (var i = 0; i < length; i++) {\n              try {\n                output(buffer[offset + i])\n              } catch (e) {\n                throw new FS.ErrnoError(29)\n              }\n            }\n            if (length) {\n              stream.node.timestamp = Date.now()\n            }\n            return i\n          },\n        })\n        return FS.mkdev(path, mode, dev)\n      },\n      forceLoadFile: obj => {\n        if (obj.isDevice || obj.isFolder || obj.link || obj.contents)\n          return true\n        if (typeof XMLHttpRequest != 'undefined') {\n          throw new Error(\n            'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.'\n          )\n        } else if (read_) {\n          try {\n            obj.contents = intArrayFromString(read_(obj.url), true)\n            obj.usedBytes = obj.contents.length\n          } catch (e) {\n            throw new FS.ErrnoError(29)\n          }\n        } else {\n          throw new Error('Cannot load without read() or XMLHttpRequest.')\n        }\n      },\n      createLazyFile: (parent, name, url, canRead, canWrite) => {\n        function LazyUint8Array() {\n          this.lengthKnown = false\n          this.chunks = []\n        }\n        LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) {\n          if (idx > this.length - 1 || idx < 0) {\n            return undefined\n          }\n          var chunkOffset = idx % this.chunkSize\n          var chunkNum = (idx / this.chunkSize) | 0\n          return this.getter(chunkNum)[chunkOffset]\n        }\n        LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(\n          getter\n        ) {\n          this.getter = getter\n        }\n        LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() {\n          var xhr = new XMLHttpRequest()\n          xhr.open('HEAD', url, false)\n          xhr.send(null)\n          if (!((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304))\n            throw new Error(\"Couldn't load \" + url + '. Status: ' + xhr.status)\n          var datalength = Number(xhr.getResponseHeader('Content-length'))\n          var header\n          var hasByteServing =\n            (header = xhr.getResponseHeader('Accept-Ranges')) &&\n            header === 'bytes'\n          var usesGzip =\n            (header = xhr.getResponseHeader('Content-Encoding')) &&\n            header === 'gzip'\n          var chunkSize = 1024 * 1024\n          if (!hasByteServing) chunkSize = datalength\n          var doXHR = (from, to) => {\n            if (from > to)\n              throw new Error(\n                'invalid range (' +\n                  from +\n                  ', ' +\n                  to +\n                  ') or no bytes requested!'\n              )\n            if (to > datalength - 1)\n              throw new Error(\n                'only ' + datalength + ' bytes available! programmer error!'\n              )\n            var xhr = new XMLHttpRequest()\n            xhr.open('GET', url, false)\n            if (datalength !== chunkSize)\n              xhr.setRequestHeader('Range', 'bytes=' + from + '-' + to)\n            xhr.responseType = 'arraybuffer'\n            if (xhr.overrideMimeType) {\n              xhr.overrideMimeType('text/plain; charset=x-user-defined')\n            }\n            xhr.send(null)\n            if (\n              !((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)\n            )\n              throw new Error(\n                \"Couldn't load \" + url + '. Status: ' + xhr.status\n              )\n            if (xhr.response !== undefined) {\n              return new Uint8Array(xhr.response || [])\n            }\n            return intArrayFromString(xhr.responseText || '', true)\n          }\n          var lazyArray = this\n          lazyArray.setDataGetter(chunkNum => {\n            var start = chunkNum * chunkSize\n            var end = (chunkNum + 1) * chunkSize - 1\n            end = Math.min(end, datalength - 1)\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined') {\n              lazyArray.chunks[chunkNum] = doXHR(start, end)\n            }\n            if (typeof lazyArray.chunks[chunkNum] == 'undefined')\n              throw new Error('doXHR failed!')\n            return lazyArray.chunks[chunkNum]\n          })\n          if (usesGzip || !datalength) {\n            chunkSize = datalength = 1\n            datalength = this.getter(0).length\n            chunkSize = datalength\n            out(\n              'LazyFiles on gzip forces download of the whole file when length is accessed'\n            )\n          }\n          this._length = datalength\n          this._chunkSize = chunkSize\n          this.lengthKnown = true\n        }\n        if (typeof XMLHttpRequest != 'undefined') {\n          if (!ENVIRONMENT_IS_WORKER)\n            throw 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'\n          var lazyArray = new LazyUint8Array()\n          Object.defineProperties(lazyArray, {\n            length: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._length\n              },\n            },\n            chunkSize: {\n              get: function() {\n                if (!this.lengthKnown) {\n                  this.cacheLength()\n                }\n                return this._chunkSize\n              },\n            },\n          })\n          var properties = { isDevice: false, contents: lazyArray }\n        } else {\n          var properties = { isDevice: false, url: url }\n        }\n        var node = FS.createFile(parent, name, properties, canRead, canWrite)\n        if (properties.contents) {\n          node.contents = properties.contents\n        } else if (properties.url) {\n          node.contents = null\n          node.url = properties.url\n        }\n        Object.defineProperties(node, {\n          usedBytes: {\n            get: function() {\n              return this.contents.length\n            },\n          },\n        })\n        var stream_ops = {}\n        var keys = Object.keys(node.stream_ops)\n        keys.forEach(key => {\n          var fn = node.stream_ops[key]\n          stream_ops[key] = function forceLoadLazyFile() {\n            FS.forceLoadFile(node)\n            return fn.apply(null, arguments)\n          }\n        })\n        function writeChunks(stream, buffer, offset, length, position) {\n          var contents = stream.node.contents\n          if (position >= contents.length) return 0\n          var size = Math.min(contents.length - position, length)\n          if (contents.slice) {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents[position + i]\n            }\n          } else {\n            for (var i = 0; i < size; i++) {\n              buffer[offset + i] = contents.get(position + i)\n            }\n          }\n          return size\n        }\n        stream_ops.read = (stream, buffer, offset, length, position) => {\n          FS.forceLoadFile(node)\n          return writeChunks(stream, buffer, offset, length, position)\n        }\n        stream_ops.mmap = (stream, length, position, prot, flags) => {\n          FS.forceLoadFile(node)\n          var ptr = mmapAlloc(length)\n          if (!ptr) {\n            throw new FS.ErrnoError(48)\n          }\n          writeChunks(stream, HEAP8, ptr, length, position)\n          return { ptr: ptr, allocated: true }\n        }\n        node.stream_ops = stream_ops\n        return node\n      },\n      createPreloadedFile: (\n        parent,\n        name,\n        url,\n        canRead,\n        canWrite,\n        onload,\n        onerror,\n        dontCreateFile,\n        canOwn,\n        preFinish\n      ) => {\n        var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent\n        var dep = getUniqueRunDependency('cp ' + fullname)\n        function processData(byteArray) {\n          function finish(byteArray) {\n            if (preFinish) preFinish()\n            if (!dontCreateFile) {\n              FS.createDataFile(\n                parent,\n                name,\n                byteArray,\n                canRead,\n                canWrite,\n                canOwn\n              )\n            }\n            if (onload) onload()\n            removeRunDependency(dep)\n          }\n          if (\n            Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => {\n              if (onerror) onerror()\n              removeRunDependency(dep)\n            })\n          ) {\n            return\n          }\n          finish(byteArray)\n        }\n        addRunDependency(dep)\n        if (typeof url == 'string') {\n          asyncLoad(url, byteArray => processData(byteArray), onerror)\n        } else {\n          processData(url)\n        }\n      },\n      indexedDB: () => {\n        return (\n          window.indexedDB ||\n          window.mozIndexedDB ||\n          window.webkitIndexedDB ||\n          window.msIndexedDB\n        )\n      },\n      DB_NAME: () => {\n        return 'EM_FS_' + window.location.pathname\n      },\n      DB_VERSION: 20,\n      DB_STORE_NAME: 'FILE_DATA',\n      saveFilesToDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = () => {\n          out('creating db')\n          var db = openRequest.result\n          db.createObjectStore(FS.DB_STORE_NAME)\n        }\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite')\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var putRequest = files.put(\n              FS.analyzePath(path).object.contents,\n              path\n            )\n            putRequest.onsuccess = () => {\n              ok++\n              if (ok + fail == total) finish()\n            }\n            putRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n      loadFilesFromDB: (paths, onload, onerror) => {\n        onload = onload || (() => {})\n        onerror = onerror || (() => {})\n        var indexedDB = FS.indexedDB()\n        try {\n          var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION)\n        } catch (e) {\n          return onerror(e)\n        }\n        openRequest.onupgradeneeded = onerror\n        openRequest.onsuccess = () => {\n          var db = openRequest.result\n          try {\n            var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly')\n          } catch (e) {\n            onerror(e)\n            return\n          }\n          var files = transaction.objectStore(FS.DB_STORE_NAME)\n          var ok = 0,\n            fail = 0,\n            total = paths.length\n          function finish() {\n            if (fail == 0) onload()\n            else onerror()\n          }\n          paths.forEach(path => {\n            var getRequest = files.get(path)\n            getRequest.onsuccess = () => {\n              if (FS.analyzePath(path).exists) {\n                FS.unlink(path)\n              }\n              FS.createDataFile(\n                PATH.dirname(path),\n                PATH.basename(path),\n                getRequest.result,\n                true,\n                true,\n                true\n              )\n              ok++\n              if (ok + fail == total) finish()\n            }\n            getRequest.onerror = () => {\n              fail++\n              if (ok + fail == total) finish()\n            }\n          })\n          transaction.onerror = onerror\n        }\n        openRequest.onerror = onerror\n      },\n    }\n    var SYSCALLS = {\n      DEFAULT_POLLMASK: 5,\n      calculateAt: function(dirfd, path, allowEmpty) {\n        if (PATH.isAbs(path)) {\n          return path\n        }\n        var dir\n        if (dirfd === -100) {\n          dir = FS.cwd()\n        } else {\n          var dirstream = SYSCALLS.getStreamFromFD(dirfd)\n          dir = dirstream.path\n        }\n        if (path.length == 0) {\n          if (!allowEmpty) {\n            throw new FS.ErrnoError(44)\n          }\n          return dir\n        }\n        return PATH.join2(dir, path)\n      },\n      doStat: function(func, path, buf) {\n        try {\n          var stat = func(path)\n        } catch (e) {\n          if (\n            e &&\n            e.node &&\n            PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))\n          ) {\n            return -54\n          }\n          throw e\n        }\n        HEAP32[buf >> 2] = stat.dev\n        HEAP32[(buf + 8) >> 2] = stat.ino\n        HEAP32[(buf + 12) >> 2] = stat.mode\n        HEAPU32[(buf + 16) >> 2] = stat.nlink\n        HEAP32[(buf + 20) >> 2] = stat.uid\n        HEAP32[(buf + 24) >> 2] = stat.gid\n        HEAP32[(buf + 28) >> 2] = stat.rdev\n        ;(tempI64 = [\n          stat.size >>> 0,\n          ((tempDouble = stat.size),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 40) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 44) >> 2] = tempI64[1])\n        HEAP32[(buf + 48) >> 2] = 4096\n        HEAP32[(buf + 52) >> 2] = stat.blocks\n        var atime = stat.atime.getTime()\n        var mtime = stat.mtime.getTime()\n        var ctime = stat.ctime.getTime()\n        ;(tempI64 = [\n          Math.floor(atime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(atime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 56) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 60) >> 2] = tempI64[1])\n        HEAPU32[(buf + 64) >> 2] = (atime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(mtime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(mtime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 72) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 76) >> 2] = tempI64[1])\n        HEAPU32[(buf + 80) >> 2] = (mtime % 1e3) * 1e3\n        ;(tempI64 = [\n          Math.floor(ctime / 1e3) >>> 0,\n          ((tempDouble = Math.floor(ctime / 1e3)),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 88) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 92) >> 2] = tempI64[1])\n        HEAPU32[(buf + 96) >> 2] = (ctime % 1e3) * 1e3\n        ;(tempI64 = [\n          stat.ino >>> 0,\n          ((tempDouble = stat.ino),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[(buf + 104) >> 2] = tempI64[0]),\n          (HEAP32[(buf + 108) >> 2] = tempI64[1])\n        return 0\n      },\n      doMsync: function(addr, stream, len, flags, offset) {\n        if (!FS.isFile(stream.node.mode)) {\n          throw new FS.ErrnoError(43)\n        }\n        if (flags & 2) {\n          return 0\n        }\n        var buffer = HEAPU8.slice(addr, addr + len)\n        FS.msync(stream, buffer, offset, len, flags)\n      },\n      varargs: undefined,\n      get: function() {\n        SYSCALLS.varargs += 4\n        var ret = HEAP32[(SYSCALLS.varargs - 4) >> 2]\n        return ret\n      },\n      getStr: function(ptr) {\n        var ret = UTF8ToString(ptr)\n        return ret\n      },\n      getStreamFromFD: function(fd) {\n        var stream = FS.getStream(fd)\n        if (!stream) throw new FS.ErrnoError(8)\n        return stream\n      },\n    }\n    function ___syscall_fcntl64(fd, cmd, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (cmd) {\n          case 0: {\n            var arg = SYSCALLS.get()\n            if (arg < 0) {\n              return -28\n            }\n            var newStream\n            newStream = FS.createStream(stream, arg)\n            return newStream.fd\n          }\n          case 1:\n          case 2:\n            return 0\n          case 3:\n            return stream.flags\n          case 4: {\n            var arg = SYSCALLS.get()\n            stream.flags |= arg\n            return 0\n          }\n          case 5: {\n            var arg = SYSCALLS.get()\n            var offset = 0\n            HEAP16[(arg + offset) >> 1] = 2\n            return 0\n          }\n          case 6:\n          case 7:\n            return 0\n          case 16:\n          case 8:\n            return -28\n          case 9:\n            setErrNo(28)\n            return -1\n          default: {\n            return -28\n          }\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_getcwd(buf, size) {\n      try {\n        if (size === 0) return -28\n        var cwd = FS.cwd()\n        var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1\n        if (size < cwdLengthInBytes) return -68\n        stringToUTF8(cwd, buf, size)\n        return cwdLengthInBytes\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_ioctl(fd, op, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        switch (op) {\n          case 21509:\n          case 21505: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21510:\n          case 21511:\n          case 21512:\n          case 21506:\n          case 21507:\n          case 21508: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21519: {\n            if (!stream.tty) return -59\n            var argp = SYSCALLS.get()\n            HEAP32[argp >> 2] = 0\n            return 0\n          }\n          case 21520: {\n            if (!stream.tty) return -59\n            return -28\n          }\n          case 21531: {\n            var argp = SYSCALLS.get()\n            return FS.ioctl(stream, op, argp)\n          }\n          case 21523: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          case 21524: {\n            if (!stream.tty) return -59\n            return 0\n          }\n          default:\n            return -28\n        }\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_openat(dirfd, path, flags, varargs) {\n      SYSCALLS.varargs = varargs\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        var mode = varargs ? SYSCALLS.get() : 0\n        return FS.open(path, flags, mode).fd\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_readlinkat(dirfd, path, buf, bufsize) {\n      try {\n        path = SYSCALLS.getStr(path)\n        path = SYSCALLS.calculateAt(dirfd, path)\n        if (bufsize <= 0) return -28\n        var ret = FS.readlink(path)\n        var len = Math.min(bufsize, lengthBytesUTF8(ret))\n        var endChar = HEAP8[buf + len]\n        stringToUTF8(ret, buf, bufsize + 1)\n        HEAP8[buf + len] = endChar\n        return len\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function ___syscall_stat64(path, buf) {\n      try {\n        path = SYSCALLS.getStr(path)\n        return SYSCALLS.doStat(FS.stat, path, buf)\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return -e.errno\n      }\n    }\n    function _abort() {\n      abort('')\n    }\n    function _emscripten_memcpy_big(dest, src, num) {\n      HEAPU8.copyWithin(dest, src, src + num)\n    }\n    function getHeapMax() {\n      return 2147483648\n    }\n    function emscripten_realloc_buffer(size) {\n      try {\n        wasmMemory.grow((size - buffer.byteLength + 65535) >>> 16)\n        updateGlobalBufferAndViews(wasmMemory.buffer)\n        return 1\n      } catch (e) {}\n    }\n    function _emscripten_resize_heap(requestedSize) {\n      var oldSize = HEAPU8.length\n      requestedSize = requestedSize >>> 0\n      var maxHeapSize = getHeapMax()\n      if (requestedSize > maxHeapSize) {\n        return false\n      }\n      let alignUp = (x, multiple) =>\n        x + ((multiple - (x % multiple)) % multiple)\n      for (var cutDown = 1; cutDown <= 4; cutDown *= 2) {\n        var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown)\n        overGrownHeapSize = Math.min(\n          overGrownHeapSize,\n          requestedSize + 100663296\n        )\n        var newSize = Math.min(\n          maxHeapSize,\n          alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)\n        )\n        var replacement = emscripten_realloc_buffer(newSize)\n        if (replacement) {\n          return true\n        }\n      }\n      return false\n    }\n    var ENV = {}\n    function getExecutableName() {\n      return thisProgram || './this.program'\n    }\n    function getEnvStrings() {\n      if (!getEnvStrings.strings) {\n        var lang =\n          (\n            (typeof navigator == 'object' &&\n              navigator.languages &&\n              navigator.languages[0]) ||\n            'C'\n          ).replace('-', '_') + '.UTF-8'\n        var env = {\n          USER: 'web_user',\n          LOGNAME: 'web_user',\n          PATH: '/',\n          PWD: '/',\n          HOME: '/home/web_user',\n          LANG: lang,\n          _: getExecutableName(),\n        }\n        for (var x in ENV) {\n          if (ENV[x] === undefined) delete env[x]\n          else env[x] = ENV[x]\n        }\n        var strings = []\n        for (var x in env) {\n          strings.push(x + '=' + env[x])\n        }\n        getEnvStrings.strings = strings\n      }\n      return getEnvStrings.strings\n    }\n    function writeAsciiToMemory(str, buffer, dontAddNull) {\n      for (var i = 0; i < str.length; ++i) {\n        HEAP8[buffer++ >> 0] = str.charCodeAt(i)\n      }\n      if (!dontAddNull) HEAP8[buffer >> 0] = 0\n    }\n    function _environ_get(__environ, environ_buf) {\n      var bufSize = 0\n      getEnvStrings().forEach(function(string, i) {\n        var ptr = environ_buf + bufSize\n        HEAPU32[(__environ + i * 4) >> 2] = ptr\n        writeAsciiToMemory(string, ptr)\n        bufSize += string.length + 1\n      })\n      return 0\n    }\n    function _environ_sizes_get(penviron_count, penviron_buf_size) {\n      var strings = getEnvStrings()\n      HEAPU32[penviron_count >> 2] = strings.length\n      var bufSize = 0\n      strings.forEach(function(string) {\n        bufSize += string.length + 1\n      })\n      HEAPU32[penviron_buf_size >> 2] = bufSize\n      return 0\n    }\n    function _proc_exit(code) {\n      EXITSTATUS = code\n      if (!keepRuntimeAlive()) {\n        if (Module['onExit']) Module['onExit'](code)\n        ABORT = true\n      }\n      quit_(code, new ExitStatus(code))\n    }\n    function exitJS(status, implicit) {\n      EXITSTATUS = status\n      _proc_exit(status)\n    }\n    var _exit = exitJS\n    function _fd_close(fd) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.close(stream)\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doReadv(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.read(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n        if (curr < len) break\n      }\n      return ret\n    }\n    function _fd_read(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doReadv(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function convertI32PairToI53Checked(lo, hi) {\n      return (hi + 2097152) >>> 0 < 4194305 - !!lo\n        ? (lo >>> 0) + hi * 4294967296\n        : NaN\n    }\n    function _fd_seek(fd, offset_low, offset_high, whence, newOffset) {\n      try {\n        var offset = convertI32PairToI53Checked(offset_low, offset_high)\n        if (isNaN(offset)) return 61\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        FS.llseek(stream, offset, whence)\n        ;(tempI64 = [\n          stream.position >>> 0,\n          ((tempDouble = stream.position),\n          +Math.abs(tempDouble) >= 1\n            ? tempDouble > 0\n              ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) |\n                  0) >>>\n                0\n              : ~~+Math.ceil(\n                  (tempDouble - +(~~tempDouble >>> 0)) / 4294967296\n                ) >>> 0\n            : 0),\n        ]),\n          (HEAP32[newOffset >> 2] = tempI64[0]),\n          (HEAP32[(newOffset + 4) >> 2] = tempI64[1])\n        if (stream.getdents && offset === 0 && whence === 0)\n          stream.getdents = null\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function doWritev(stream, iov, iovcnt, offset) {\n      var ret = 0\n      for (var i = 0; i < iovcnt; i++) {\n        var ptr = HEAPU32[iov >> 2]\n        var len = HEAPU32[(iov + 4) >> 2]\n        iov += 8\n        var curr = FS.write(stream, HEAP8, ptr, len, offset)\n        if (curr < 0) return -1\n        ret += curr\n      }\n      return ret\n    }\n    function _fd_write(fd, iov, iovcnt, pnum) {\n      try {\n        var stream = SYSCALLS.getStreamFromFD(fd)\n        var num = doWritev(stream, iov, iovcnt)\n        HEAPU32[pnum >> 2] = num\n        return 0\n      } catch (e) {\n        if (typeof FS == 'undefined' || !(e instanceof FS.ErrnoError)) throw e\n        return e.errno\n      }\n    }\n    function __isLeapYear(year) {\n      return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)\n    }\n    function __arraySum(array, index) {\n      var sum = 0\n      for (var i = 0; i <= index; sum += array[i++]) {}\n      return sum\n    }\n    var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n    function __addDays(date, days) {\n      var newDate = new Date(date.getTime())\n      while (days > 0) {\n        var leap = __isLeapYear(newDate.getFullYear())\n        var currentMonth = newDate.getMonth()\n        var daysInCurrentMonth = (leap\n          ? __MONTH_DAYS_LEAP\n          : __MONTH_DAYS_REGULAR)[currentMonth]\n        if (days > daysInCurrentMonth - newDate.getDate()) {\n          days -= daysInCurrentMonth - newDate.getDate() + 1\n          newDate.setDate(1)\n          if (currentMonth < 11) {\n            newDate.setMonth(currentMonth + 1)\n          } else {\n            newDate.setMonth(0)\n            newDate.setFullYear(newDate.getFullYear() + 1)\n          }\n        } else {\n          newDate.setDate(newDate.getDate() + days)\n          return newDate\n        }\n      }\n      return newDate\n    }\n    function writeArrayToMemory(array, buffer) {\n      HEAP8.set(array, buffer)\n    }\n    function _strftime(s, maxsize, format, tm) {\n      var tm_zone = HEAP32[(tm + 40) >> 2]\n      var date = {\n        tm_sec: HEAP32[tm >> 2],\n        tm_min: HEAP32[(tm + 4) >> 2],\n        tm_hour: HEAP32[(tm + 8) >> 2],\n        tm_mday: HEAP32[(tm + 12) >> 2],\n        tm_mon: HEAP32[(tm + 16) >> 2],\n        tm_year: HEAP32[(tm + 20) >> 2],\n        tm_wday: HEAP32[(tm + 24) >> 2],\n        tm_yday: HEAP32[(tm + 28) >> 2],\n        tm_isdst: HEAP32[(tm + 32) >> 2],\n        tm_gmtoff: HEAP32[(tm + 36) >> 2],\n        tm_zone: tm_zone ? UTF8ToString(tm_zone) : '',\n      }\n      var pattern = UTF8ToString(format)\n      var EXPANSION_RULES_1 = {\n        '%c': '%a %b %d %H:%M:%S %Y',\n        '%D': '%m/%d/%y',\n        '%F': '%Y-%m-%d',\n        '%h': '%b',\n        '%r': '%I:%M:%S %p',\n        '%R': '%H:%M',\n        '%T': '%H:%M:%S',\n        '%x': '%m/%d/%y',\n        '%X': '%H:%M:%S',\n        '%Ec': '%c',\n        '%EC': '%C',\n        '%Ex': '%m/%d/%y',\n        '%EX': '%H:%M:%S',\n        '%Ey': '%y',\n        '%EY': '%Y',\n        '%Od': '%d',\n        '%Oe': '%e',\n        '%OH': '%H',\n        '%OI': '%I',\n        '%Om': '%m',\n        '%OM': '%M',\n        '%OS': '%S',\n        '%Ou': '%u',\n        '%OU': '%U',\n        '%OV': '%V',\n        '%Ow': '%w',\n        '%OW': '%W',\n        '%Oy': '%y',\n      }\n      for (var rule in EXPANSION_RULES_1) {\n        pattern = pattern.replace(\n          new RegExp(rule, 'g'),\n          EXPANSION_RULES_1[rule]\n        )\n      }\n      var WEEKDAYS = [\n        'Sunday',\n        'Monday',\n        'Tuesday',\n        'Wednesday',\n        'Thursday',\n        'Friday',\n        'Saturday',\n      ]\n      var MONTHS = [\n        'January',\n        'February',\n        'March',\n        'April',\n        'May',\n        'June',\n        'July',\n        'August',\n        'September',\n        'October',\n        'November',\n        'December',\n      ]\n      function leadingSomething(value, digits, character) {\n        var str = typeof value == 'number' ? value.toString() : value || ''\n        while (str.length < digits) {\n          str = character[0] + str\n        }\n        return str\n      }\n      function leadingNulls(value, digits) {\n        return leadingSomething(value, digits, '0')\n      }\n      function compareByDay(date1, date2) {\n        function sgn(value) {\n          return value < 0 ? -1 : value > 0 ? 1 : 0\n        }\n        var compare\n        if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) {\n          if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) {\n            compare = sgn(date1.getDate() - date2.getDate())\n          }\n        }\n        return compare\n      }\n      function getFirstWeekStartDate(janFourth) {\n        switch (janFourth.getDay()) {\n          case 0:\n            return new Date(janFourth.getFullYear() - 1, 11, 29)\n          case 1:\n            return janFourth\n          case 2:\n            return new Date(janFourth.getFullYear(), 0, 3)\n          case 3:\n            return new Date(janFourth.getFullYear(), 0, 2)\n          case 4:\n            return new Date(janFourth.getFullYear(), 0, 1)\n          case 5:\n            return new Date(janFourth.getFullYear() - 1, 11, 31)\n          case 6:\n            return new Date(janFourth.getFullYear() - 1, 11, 30)\n        }\n      }\n      function getWeekBasedYear(date) {\n        var thisDate = __addDays(\n          new Date(date.tm_year + 1900, 0, 1),\n          date.tm_yday\n        )\n        var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4)\n        var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4)\n        var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear)\n        var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear)\n        if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) {\n          if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) {\n            return thisDate.getFullYear() + 1\n          }\n          return thisDate.getFullYear()\n        }\n        return thisDate.getFullYear() - 1\n      }\n      var EXPANSION_RULES_2 = {\n        '%a': function(date) {\n          return WEEKDAYS[date.tm_wday].substring(0, 3)\n        },\n        '%A': function(date) {\n          return WEEKDAYS[date.tm_wday]\n        },\n        '%b': function(date) {\n          return MONTHS[date.tm_mon].substring(0, 3)\n        },\n        '%B': function(date) {\n          return MONTHS[date.tm_mon]\n        },\n        '%C': function(date) {\n          var year = date.tm_year + 1900\n          return leadingNulls((year / 100) | 0, 2)\n        },\n        '%d': function(date) {\n          return leadingNulls(date.tm_mday, 2)\n        },\n        '%e': function(date) {\n          return leadingSomething(date.tm_mday, 2, ' ')\n        },\n        '%g': function(date) {\n          return getWeekBasedYear(date)\n            .toString()\n            .substring(2)\n        },\n        '%G': function(date) {\n          return getWeekBasedYear(date)\n        },\n        '%H': function(date) {\n          return leadingNulls(date.tm_hour, 2)\n        },\n        '%I': function(date) {\n          var twelveHour = date.tm_hour\n          if (twelveHour == 0) twelveHour = 12\n          else if (twelveHour > 12) twelveHour -= 12\n          return leadingNulls(twelveHour, 2)\n        },\n        '%j': function(date) {\n          return leadingNulls(\n            date.tm_mday +\n              __arraySum(\n                __isLeapYear(date.tm_year + 1900)\n                  ? __MONTH_DAYS_LEAP\n                  : __MONTH_DAYS_REGULAR,\n                date.tm_mon - 1\n              ),\n            3\n          )\n        },\n        '%m': function(date) {\n          return leadingNulls(date.tm_mon + 1, 2)\n        },\n        '%M': function(date) {\n          return leadingNulls(date.tm_min, 2)\n        },\n        '%n': function() {\n          return '\\n'\n        },\n        '%p': function(date) {\n          if (date.tm_hour >= 0 && date.tm_hour < 12) {\n            return 'AM'\n          }\n          return 'PM'\n        },\n        '%S': function(date) {\n          return leadingNulls(date.tm_sec, 2)\n        },\n        '%t': function() {\n          return '\\t'\n        },\n        '%u': function(date) {\n          return date.tm_wday || 7\n        },\n        '%U': function(date) {\n          var days = date.tm_yday + 7 - date.tm_wday\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%V': function(date) {\n          var val = Math.floor(\n            (date.tm_yday + 7 - ((date.tm_wday + 6) % 7)) / 7\n          )\n          if ((date.tm_wday + 371 - date.tm_yday - 2) % 7 <= 2) {\n            val++\n          }\n          if (!val) {\n            val = 52\n            var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7\n            if (\n              dec31 == 4 ||\n              (dec31 == 5 && __isLeapYear((date.tm_year % 400) - 1))\n            ) {\n              val++\n            }\n          } else if (val == 53) {\n            var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7\n            if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) val = 1\n          }\n          return leadingNulls(val, 2)\n        },\n        '%w': function(date) {\n          return date.tm_wday\n        },\n        '%W': function(date) {\n          var days = date.tm_yday + 7 - ((date.tm_wday + 6) % 7)\n          return leadingNulls(Math.floor(days / 7), 2)\n        },\n        '%y': function(date) {\n          return (date.tm_year + 1900).toString().substring(2)\n        },\n        '%Y': function(date) {\n          return date.tm_year + 1900\n        },\n        '%z': function(date) {\n          var off = date.tm_gmtoff\n          var ahead = off >= 0\n          off = Math.abs(off) / 60\n          off = (off / 60) * 100 + (off % 60)\n          return (ahead ? '+' : '-') + String('0000' + off).slice(-4)\n        },\n        '%Z': function(date) {\n          return date.tm_zone\n        },\n        '%%': function() {\n          return '%'\n        },\n      }\n      pattern = pattern.replace(/%%/g, '\\0\\0')\n      for (var rule in EXPANSION_RULES_2) {\n        if (pattern.includes(rule)) {\n          pattern = pattern.replace(\n            new RegExp(rule, 'g'),\n            EXPANSION_RULES_2[rule](date)\n          )\n        }\n      }\n      pattern = pattern.replace(/\\0\\0/g, '%')\n      var bytes = intArrayFromString(pattern, false)\n      if (bytes.length > maxsize) {\n        return 0\n      }\n      writeArrayToMemory(bytes, s)\n      return bytes.length - 1\n    }\n    function _strftime_l(s, maxsize, format, tm, loc) {\n      return _strftime(s, maxsize, format, tm)\n    }\n    function handleException(e) {\n      if (e instanceof ExitStatus || e == 'unwind') {\n        return EXITSTATUS\n      }\n      quit_(1, e)\n    }\n    function allocateUTF8OnStack(str) {\n      var size = lengthBytesUTF8(str) + 1\n      var ret = stackAlloc(size)\n      stringToUTF8Array(str, HEAP8, ret, size)\n      return ret\n    }\n    function getCFunc(ident) {\n      var func = Module['_' + ident]\n      return func\n    }\n    function ccall(ident, returnType, argTypes, args, opts) {\n      var toC = {\n        string: str => {\n          var ret = 0\n          if (str !== null && str !== undefined && str !== 0) {\n            var len = (str.length << 2) + 1\n            ret = stackAlloc(len)\n            stringToUTF8(str, ret, len)\n          }\n          return ret\n        },\n        array: arr => {\n          var ret = stackAlloc(arr.length)\n          writeArrayToMemory(arr, ret)\n          return ret\n        },\n      }\n      function convertReturnValue(ret) {\n        if (returnType === 'string') {\n          return UTF8ToString(ret)\n        }\n        if (returnType === 'boolean') return Boolean(ret)\n        return ret\n      }\n      var func = getCFunc(ident)\n      var cArgs = []\n      var stack = 0\n      if (args) {\n        for (var i = 0; i < args.length; i++) {\n          var converter = toC[argTypes[i]]\n          if (converter) {\n            if (stack === 0) stack = stackSave()\n            cArgs[i] = converter(args[i])\n          } else {\n            cArgs[i] = args[i]\n          }\n        }\n      }\n      var ret = func.apply(null, cArgs)\n      function onDone(ret) {\n        if (stack !== 0) stackRestore(stack)\n        return convertReturnValue(ret)\n      }\n      ret = onDone(ret)\n      return ret\n    }\n    function cwrap(ident, returnType, argTypes, opts) {\n      argTypes = argTypes || []\n      var numericArgs = argTypes.every(\n        type => type === 'number' || type === 'boolean'\n      )\n      var numericRet = returnType !== 'string'\n      if (numericRet && numericArgs && !opts) {\n        return getCFunc(ident)\n      }\n      return function() {\n        return ccall(ident, returnType, argTypes, arguments, opts)\n      }\n    }\n    function AsciiToString(ptr) {\n      var str = ''\n      while (1) {\n        var ch = HEAPU8[ptr++ >> 0]\n        if (!ch) return str\n        str += String.fromCharCode(ch)\n      }\n    }\n    var FSNode = function(parent, name, mode, rdev) {\n      if (!parent) {\n        parent = this\n      }\n      this.parent = parent\n      this.mount = parent.mount\n      this.mounted = null\n      this.id = FS.nextInode++\n      this.name = name\n      this.mode = mode\n      this.node_ops = {}\n      this.stream_ops = {}\n      this.rdev = rdev\n    }\n    var readMode = 292 | 73\n    var writeMode = 146\n    Object.defineProperties(FSNode.prototype, {\n      read: {\n        get: function() {\n          return (this.mode & readMode) === readMode\n        },\n        set: function(val) {\n          val ? (this.mode |= readMode) : (this.mode &= ~readMode)\n        },\n      },\n      write: {\n        get: function() {\n          return (this.mode & writeMode) === writeMode\n        },\n        set: function(val) {\n          val ? (this.mode |= writeMode) : (this.mode &= ~writeMode)\n        },\n      },\n      isFolder: {\n        get: function() {\n          return FS.isDir(this.mode)\n        },\n      },\n      isDevice: {\n        get: function() {\n          return FS.isChrdev(this.mode)\n        },\n      },\n    })\n    FS.FSNode = FSNode\n    FS.staticInit()\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_unlink'] = FS.unlink\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    if (ENVIRONMENT_IS_NODE) {\n      NODEFS.staticInit()\n    }\n    ERRNO_CODES = {\n      EPERM: 63,\n      ENOENT: 44,\n      ESRCH: 71,\n      EINTR: 27,\n      EIO: 29,\n      ENXIO: 60,\n      E2BIG: 1,\n      ENOEXEC: 45,\n      EBADF: 8,\n      ECHILD: 12,\n      EAGAIN: 6,\n      EWOULDBLOCK: 6,\n      ENOMEM: 48,\n      EACCES: 2,\n      EFAULT: 21,\n      ENOTBLK: 105,\n      EBUSY: 10,\n      EEXIST: 20,\n      EXDEV: 75,\n      ENODEV: 43,\n      ENOTDIR: 54,\n      EISDIR: 31,\n      EINVAL: 28,\n      ENFILE: 41,\n      EMFILE: 33,\n      ENOTTY: 59,\n      ETXTBSY: 74,\n      EFBIG: 22,\n      ENOSPC: 51,\n      ESPIPE: 70,\n      EROFS: 69,\n      EMLINK: 34,\n      EPIPE: 64,\n      EDOM: 18,\n      ERANGE: 68,\n      ENOMSG: 49,\n      EIDRM: 24,\n      ECHRNG: 106,\n      EL2NSYNC: 156,\n      EL3HLT: 107,\n      EL3RST: 108,\n      ELNRNG: 109,\n      EUNATCH: 110,\n      ENOCSI: 111,\n      EL2HLT: 112,\n      EDEADLK: 16,\n      ENOLCK: 46,\n      EBADE: 113,\n      EBADR: 114,\n      EXFULL: 115,\n      ENOANO: 104,\n      EBADRQC: 103,\n      EBADSLT: 102,\n      EDEADLOCK: 16,\n      EBFONT: 101,\n      ENOSTR: 100,\n      ENODATA: 116,\n      ETIME: 117,\n      ENOSR: 118,\n      ENONET: 119,\n      ENOPKG: 120,\n      EREMOTE: 121,\n      ENOLINK: 47,\n      EADV: 122,\n      ESRMNT: 123,\n      ECOMM: 124,\n      EPROTO: 65,\n      EMULTIHOP: 36,\n      EDOTDOT: 125,\n      EBADMSG: 9,\n      ENOTUNIQ: 126,\n      EBADFD: 127,\n      EREMCHG: 128,\n      ELIBACC: 129,\n      ELIBBAD: 130,\n      ELIBSCN: 131,\n      ELIBMAX: 132,\n      ELIBEXEC: 133,\n      ENOSYS: 52,\n      ENOTEMPTY: 55,\n      ENAMETOOLONG: 37,\n      ELOOP: 32,\n      EOPNOTSUPP: 138,\n      EPFNOSUPPORT: 139,\n      ECONNRESET: 15,\n      ENOBUFS: 42,\n      EAFNOSUPPORT: 5,\n      EPROTOTYPE: 67,\n      ENOTSOCK: 57,\n      ENOPROTOOPT: 50,\n      ESHUTDOWN: 140,\n      ECONNREFUSED: 14,\n      EADDRINUSE: 3,\n      ECONNABORTED: 13,\n      ENETUNREACH: 40,\n      ENETDOWN: 38,\n      ETIMEDOUT: 73,\n      EHOSTDOWN: 142,\n      EHOSTUNREACH: 23,\n      EINPROGRESS: 26,\n      EALREADY: 7,\n      EDESTADDRREQ: 17,\n      EMSGSIZE: 35,\n      EPROTONOSUPPORT: 66,\n      ESOCKTNOSUPPORT: 137,\n      EADDRNOTAVAIL: 4,\n      ENETRESET: 39,\n      EISCONN: 30,\n      ENOTCONN: 53,\n      ETOOMANYREFS: 141,\n      EUSERS: 136,\n      EDQUOT: 19,\n      ESTALE: 72,\n      ENOTSUP: 138,\n      ENOMEDIUM: 148,\n      EILSEQ: 25,\n      EOVERFLOW: 61,\n      ECANCELED: 11,\n      ENOTRECOVERABLE: 56,\n      EOWNERDEAD: 62,\n      ESTRPIPE: 135,\n    }\n    var asmLibraryArg = {\n      a: ___cxa_throw,\n      d: ___syscall_fcntl64,\n      r: ___syscall_getcwd,\n      i: ___syscall_ioctl,\n      j: ___syscall_openat,\n      n: ___syscall_readlinkat,\n      o: ___syscall_stat64,\n      b: _abort,\n      f: _emscripten_memcpy_big,\n      m: _emscripten_resize_heap,\n      p: _environ_get,\n      q: _environ_sizes_get,\n      c: _exit,\n      e: _fd_close,\n      h: _fd_read,\n      k: _fd_seek,\n      g: _fd_write,\n      l: _strftime_l,\n    }\n    var asm = createWasm()\n    var ___wasm_call_ctors = (Module['___wasm_call_ctors'] = function() {\n      return (___wasm_call_ctors = Module['___wasm_call_ctors'] =\n        Module['asm']['t']).apply(null, arguments)\n    })\n    var _main = (Module['_main'] = function() {\n      return (_main = Module['_main'] = Module['asm']['u']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___errno_location = (Module['___errno_location'] = function() {\n      return (___errno_location = Module['___errno_location'] =\n        Module['asm']['v']).apply(null, arguments)\n    })\n    var _itk_wasm_input_array_alloc = (Module[\n      '_itk_wasm_input_array_alloc'\n    ] = function() {\n      return (_itk_wasm_input_array_alloc = Module[\n        '_itk_wasm_input_array_alloc'\n      ] = Module['asm']['w']).apply(null, arguments)\n    })\n    var _itk_wasm_input_json_alloc = (Module[\n      '_itk_wasm_input_json_alloc'\n    ] = function() {\n      return (_itk_wasm_input_json_alloc = Module[\n        '_itk_wasm_input_json_alloc'\n      ] = Module['asm']['x']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_address = (Module[\n      '_itk_wasm_output_json_address'\n    ] = function() {\n      return (_itk_wasm_output_json_address = Module[\n        '_itk_wasm_output_json_address'\n      ] = Module['asm']['y']).apply(null, arguments)\n    })\n    var _itk_wasm_output_json_size = (Module[\n      '_itk_wasm_output_json_size'\n    ] = function() {\n      return (_itk_wasm_output_json_size = Module[\n        '_itk_wasm_output_json_size'\n      ] = Module['asm']['z']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_address = (Module[\n      '_itk_wasm_output_array_address'\n    ] = function() {\n      return (_itk_wasm_output_array_address = Module[\n        '_itk_wasm_output_array_address'\n      ] = Module['asm']['A']).apply(null, arguments)\n    })\n    var _itk_wasm_output_array_size = (Module[\n      '_itk_wasm_output_array_size'\n    ] = function() {\n      return (_itk_wasm_output_array_size = Module[\n        '_itk_wasm_output_array_size'\n      ] = Module['asm']['B']).apply(null, arguments)\n    })\n    var _itk_wasm_free_all = (Module['_itk_wasm_free_all'] = function() {\n      return (_itk_wasm_free_all = Module['_itk_wasm_free_all'] =\n        Module['asm']['C']).apply(null, arguments)\n    })\n    var stackSave = (Module['stackSave'] = function() {\n      return (stackSave = Module['stackSave'] = Module['asm']['E']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackRestore = (Module['stackRestore'] = function() {\n      return (stackRestore = Module['stackRestore'] = Module['asm']['F']).apply(\n        null,\n        arguments\n      )\n    })\n    var stackAlloc = (Module['stackAlloc'] = function() {\n      return (stackAlloc = Module['stackAlloc'] = Module['asm']['G']).apply(\n        null,\n        arguments\n      )\n    })\n    var ___cxa_is_pointer_type = (Module[\n      '___cxa_is_pointer_type'\n    ] = function() {\n      return (___cxa_is_pointer_type = Module['___cxa_is_pointer_type'] =\n        Module['asm']['H']).apply(null, arguments)\n    })\n    Module['addRunDependency'] = addRunDependency\n    Module['removeRunDependency'] = removeRunDependency\n    Module['FS_createPath'] = FS.createPath\n    Module['FS_createDataFile'] = FS.createDataFile\n    Module['FS_createPreloadedFile'] = FS.createPreloadedFile\n    Module['FS_createLazyFile'] = FS.createLazyFile\n    Module['FS_createDevice'] = FS.createDevice\n    Module['FS_unlink'] = FS.unlink\n    Module['callMain'] = callMain\n    Module['ccall'] = ccall\n    Module['cwrap'] = cwrap\n    Module['AsciiToString'] = AsciiToString\n    Module['writeArrayToMemory'] = writeArrayToMemory\n    Module['writeAsciiToMemory'] = writeAsciiToMemory\n    var calledRun\n    dependenciesFulfilled = function runCaller() {\n      if (!calledRun) run()\n      if (!calledRun) dependenciesFulfilled = runCaller\n    }\n    function callMain(args) {\n      var entryFunction = Module['_main']\n      args = args || []\n      args.unshift(thisProgram)\n      var argc = args.length\n      var argv = stackAlloc((argc + 1) * 4)\n      var argv_ptr = argv >> 2\n      args.forEach(arg => {\n        HEAP32[argv_ptr++] = allocateUTF8OnStack(arg)\n      })\n      HEAP32[argv_ptr] = 0\n      try {\n        var ret = entryFunction(argc, argv)\n        exitJS(ret, true)\n        return ret\n      } catch (e) {\n        return handleException(e)\n      }\n    }\n    function run(args) {\n      args = args || arguments_\n      if (runDependencies > 0) {\n        return\n      }\n      preRun()\n      if (runDependencies > 0) {\n        return\n      }\n      function doRun() {\n        if (calledRun) return\n        calledRun = true\n        Module['calledRun'] = true\n        if (ABORT) return\n        initRuntime()\n        preMain()\n        readyPromiseResolve(Module)\n        if (Module['onRuntimeInitialized']) Module['onRuntimeInitialized']()\n        if (shouldRunNow) callMain(args)\n        postRun()\n      }\n      if (Module['setStatus']) {\n        Module['setStatus']('Running...')\n        setTimeout(function() {\n          setTimeout(function() {\n            Module['setStatus']('')\n          }, 1)\n          doRun()\n        }, 1)\n      } else {\n        doRun()\n      }\n    }\n    if (Module['preInit']) {\n      if (typeof Module['preInit'] == 'function')\n        Module['preInit'] = [Module['preInit']]\n      while (Module['preInit'].length > 0) {\n        Module['preInit'].pop()()\n      }\n    }\n    var shouldRunNow = false\n    if (Module['noInitialRun']) shouldRunNow = false\n    run()\n    Module.mountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      if (FS.isDir(containingDir) || containingDir === '/') {\n        return\n      }\n      var currentDir = '/'\n      var splitContainingDir = containingDir.split(path.sep)\n      for (var ii = 1; ii < splitContainingDir.length; ii++) {\n        currentDir += splitContainingDir[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n      FS.mount(NODEFS, { root: containingDir }, currentDir)\n      return currentDir + path.basename(filePath)\n    }\n    Module.unmountContainingDir = function(filePath) {\n      if (!ENVIRONMENT_IS_NODE) {\n        return\n      }\n      var path = require('path')\n      var containingDir = path.dirname(filePath)\n      FS.unmount(containingDir)\n    }\n    Module.fs_mkdirs = function(dirs) {\n      var currentDir = '/'\n      var splitDirs = dirs.split('/')\n      for (var ii = 1; ii < splitDirs.length; ++ii) {\n        currentDir += splitDirs[ii]\n        if (!FS.analyzePath(currentDir).exists) {\n          FS.mkdir(currentDir)\n        }\n        currentDir += '/'\n      }\n    }\n    Module.fs_readFile = function(path, opts) {\n      return FS.readFile(path, opts)\n    }\n    Module.fs_writeFile = function(path, data, opts) {\n      return FS.writeFile(path, data, opts)\n    }\n    Module.fs_unlink = function(path) {\n      return FS.unlink(path)\n    }\n    Module.fs_open = function(path, flags, mode) {\n      return FS.open(path, flags, mode)\n    }\n    Module.fs_stat = function(path) {\n      return FS.stat(path)\n    }\n    Module.fs_read = function(stream, buffer, offset, length, position) {\n      return FS.read(stream, buffer, offset, length, position)\n    }\n    Module.fs_close = function(stream) {\n      return FS.close(stream)\n    }\n\n    return ResampleLabelImage.ready\n  }\n})()\nif (typeof exports === 'object' && typeof module === 'object')\n  module.exports = ResampleLabelImage\nelse if (typeof define === 'function' && define['amd'])\n  define([], function() {\n    return ResampleLabelImage\n  })\nelse if (typeof exports === 'object')\n  exports['ResampleLabelImage'] = ResampleLabelImage\n"
  },
  {
    "path": "src/IO/ResampleLabelImage/index.mjs",
    "content": "#!/usr/bin/env node\n/* eslint-env node */\n\nimport { Command } from 'commander/esm.mjs'\nimport path from 'path'\n\nconst program = new Command()\n\nimport {\n  readLocalFile,\n  writeLocalFile,\n  runPipelineNode,\n  InterfaceTypes,\n} from 'itk-wasm'\n\nprogram\n  .description('Resample an image')\n  .option('-l, --label-image', 'Label image as opposed to an intensity image')\n  .arguments('<inputFile> <outputFile>')\n  .parse(process.argv)\n\nif (program.args.length < 2) {\n  console.error('Please pass in both the input and output file paths.')\n  process.exit(1)\n}\n\nconst inputFile = program.args[0]\nconst outputFile = program.args[1]\nconst pipelinePath = path.resolve('./emscripten-build/ResampleLabelImage')\n\ntry {\n  const inputImage = await readLocalFile(inputFile)\n\n  const inputs = [\n    {\n      type: InterfaceTypes.Image,\n      data: inputImage,\n    },\n  ]\n  const desiredOutputs = [\n    { type: InterfaceTypes.Image },\n    // { type: InterfaceTypes.TextStream },\n  ]\n  const size = [100, 100]\n  const spacing = [2, 2]\n  const origin = [1, 3]\n  const direction = [0, 1, 1, 0]\n  const args = [\n    '0',\n    '0',\n    '--size',\n    size.join(','),\n    '--spacing',\n    spacing.join(','),\n    '--origin',\n    origin.join(','),\n    '--direction',\n    direction.join(','),\n    // '--max-total-splits',\n    // '10',\n    // '--split',\n    // '5',\n    '--memory-io',\n  ]\n  const { outputs } = await runPipelineNode(\n    pipelinePath,\n    args,\n    desiredOutputs,\n    inputs\n  )\n\n  const outputImage = outputs[0].data\n\n  await writeLocalFile(outputImage, outputFile)\n} catch (error) {\n  console.error('Error during processing:\\n')\n  console.error(error)\n}\n"
  },
  {
    "path": "src/IO/ResampleLabelImage/package.json",
    "content": "{\n  \"name\": \"resample\",\n  \"version\": \"1.0.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"type\": \"module\",\n  \"scripts\": {\n    \"build\": \"itk-wasm build\",\n    \"build:debug\": \"itk-wasm build -- -DCMAKE_BUILD_TYPE=Debug\",\n    \"test\": \"node index.mjs ../Downsample/cthead1-bin.png resample.png\"\n  },\n  \"author\": \"\",\n  \"license\": \"Apache-2.0\",\n  \"dependencies\": {\n    \"itk-image-io\": \"^1.0.0-b.84\",\n    \"itk-wasm\": \"^1.0.0-b.84\"\n  }\n}\n"
  },
  {
    "path": "src/IO/ResampleLabelImage/resampleLabelImage.js",
    "content": "import { arraysEqual } from '../../internalUtils.js'\nimport { runWasm } from '../itkWasmUtils.js'\n\nexport async function resampleLabelImage(image, labelImage) {\n  const { size, spacing, origin, direction } = image\n  const args = [\n    '--size',\n    size.join(','),\n    '--spacing',\n    spacing.join(','),\n    '--origin',\n    origin.join(','),\n    '--direction',\n    direction.join(','),\n  ]\n\n  return runWasm({ pipeline: 'ResampleLabelImage', args, images: [labelImage] })\n}\n\nexport function compareImageSpaces(imageA, imageB) {\n  const equalKeys = ['size', 'direction', 'origin', 'spacing'].map(key =>\n    arraysEqual(imageA[key], imageB[key])\n  )\n  return equalKeys.every(b => b)\n}\n"
  },
  {
    "path": "src/IO/ZarrMultiscaleSpatialImage.js",
    "content": "import { PixelTypes } from 'itk-wasm'\nimport PQueue from 'p-queue'\n\nimport MultiscaleSpatialImage from './MultiscaleSpatialImage'\nimport bloscZarrDecompress from '../Compression/bloscZarrDecompress'\nimport ZarrStoreParser from './ZarrStoreParser'\nimport HttpStore from './HttpStore'\nimport { CXYZT, toDimensionMap } from './dimensionUtils'\nimport { getComponentType } from './dtypeUtils'\nimport { MAX_CONCURRENCY } from '../Context/ViewerMachineContext'\n\n// ends with zarr and optional nested image name like foo.zarr/image1\nexport const isZarr = url => /\\w[./]zarr\\b/.test(url)\n\nconst TCZYX = Object.freeze(['t', 'c', 'z', 'y', 'x'])\n\nconst composeTransforms = (transforms = [], dimCount) =>\n  transforms.reduce(\n    ({ scale, translation }, transform) => {\n      if (transform.type === 'scale') {\n        const { scale: transformScale } = transform\n        return {\n          scale: scale.map((s, i) => s * transformScale[i]),\n          translation: translation.map((t, i) => t * transformScale[i]),\n        }\n      } else if (transform.type === 'translation') {\n        const { translation: transformTranslation } = transform\n        return {\n          scale,\n          translation: translation.map((t, i) => t + transformTranslation[i]),\n        }\n      }\n    },\n    { scale: Array(dimCount).fill(1), translation: Array(dimCount).fill(0) }\n  )\n\nexport const computeTransform = (imageMetadata, datasetMetadata, dimCount) => {\n  const global = composeTransforms(\n    imageMetadata.coordinateTransformations,\n    dimCount\n  )\n  const dataset = composeTransforms(\n    datasetMetadata.coordinateTransformations,\n    dimCount\n  )\n\n  return composeTransforms(\n    [\n      { type: 'scale', scale: dataset.scale },\n      { type: 'translation', translation: dataset.translation },\n      { type: 'scale', scale: global.scale },\n      { type: 'translation', translation: global.translation },\n    ],\n    dimCount\n  )\n}\n\n// if missing coordinateTransformations, make all scales same size as finest scale\nconst ensureScaleTransforms = datasetsWithArrayMetadata => {\n  const hasDatasetCoordinateTransform = datasetsWithArrayMetadata.some(\n    ({ dataset }) => dataset.coordinateTransformations\n  )\n  if (hasDatasetCoordinateTransform) return datasetsWithArrayMetadata\n\n  const targetSize = datasetsWithArrayMetadata[0].pixelArrayMetadata.shape\n\n  return datasetsWithArrayMetadata.map(({ dataset, pixelArrayMetadata }) => {\n    const { shape } = pixelArrayMetadata\n    const scale = targetSize.map((target, idx) => target / shape[idx])\n    return {\n      dataset: {\n        ...dataset,\n        coordinateTransformations: [{ scale, type: 'scale' }],\n      },\n      pixelArrayMetadata,\n    }\n  })\n}\n\n// lazy creation of voxel/pixel/dimension coordinates array\nconst makeCoords = ({ shape, multiscaleImage, dataset }) => {\n  const axes = multiscaleImage.axes?.map(({ name }) => name) ?? TCZYX\n  const coords = new Map(axes.map(dim => [dim, null]))\n\n  const {\n    scale: spacingDataset,\n    translation: originDataset,\n  } = computeTransform(multiscaleImage, dataset, axes.length)\n\n  return {\n    get(dim) {\n      if (coords.get(dim) === null) {\n        // make array\n        const dimIdx = axes.indexOf(dim)\n        const spacing = spacingDataset[dimIdx]\n        const origin = originDataset[dimIdx]\n        const coordsPerElement = new Float32Array(shape[dimIdx])\n        for (let i = 0; i < coordsPerElement.length; i++) {\n          coordsPerElement[i] = i * spacing + origin\n        }\n        coords.set(dim, coordsPerElement)\n      }\n      return coords.get(dim)\n    },\n    has(dim) {\n      return axes.includes(dim)\n    },\n  }\n}\n\nconst findAxesLongNames = async ({ dataset, dataSource, dims }) => {\n  const upOneLevel = dataset.path\n    .split('/')\n    .slice(0, -1)\n    .join('')\n  return new Map(\n    await Promise.all(\n      dims.map(dim => dataSource.getItem(`${upOneLevel}/${dim}/.zattrs`))\n    ).then(dimensionsZattrs =>\n      dimensionsZattrs.map(({ long_name }, i) => [dims[i], long_name])\n    )\n  )\n}\n\nconst createScaledImageInfo = async ({\n  multiscaleImage,\n  dataset,\n  pixelArrayMetadata,\n  dataSource,\n  multiscaleSpatialImageVersion,\n}) => {\n  const scaleZattrs = multiscaleSpatialImageVersion\n    ? await dataSource.getItem(`${dataset.path}/.zattrs`)\n    : {}\n\n  const dims =\n    scaleZattrs._ARRAY_DIMENSIONS ??\n    multiscaleImage.axes?.map(axis => axis.name ?? axis) ??\n    TCZYX // default to TCZYX for NGFF v0.1\n\n  const { shape, chunks } = pixelArrayMetadata\n\n  const chunkSize = toDimensionMap(dims, chunks)\n  const arrayShape = toDimensionMap(dims, shape)\n\n  const axesNames = multiscaleSpatialImageVersion\n    ? await findAxesLongNames({ dataset, dataSource, dims })\n    : undefined\n\n  return {\n    dims,\n    pixelArrayMetadata,\n    name: multiscaleImage.name,\n    pixelArrayPath: dataset.path,\n    coords: makeCoords({ shape, multiscaleImage, dataset }),\n    ranges: scaleZattrs.ranges ?? multiscaleImage.ranges,\n    direction: scaleZattrs.direction ?? multiscaleImage.direction,\n    axesNames,\n    chunkCount: toDimensionMap(\n      dims,\n      dims.map(dim => Math.ceil(arrayShape.get(dim) / chunkSize.get(dim)))\n    ),\n    chunkSize,\n    arrayShape,\n  }\n}\n\nconst extractScaleSpacing = async dataSource => {\n  const zattrs = await dataSource.getItem('.zattrs')\n\n  const { multiscales, multiscaleSpatialImageVersion } = zattrs\n  const multiscaleImage = Array.isArray(multiscales)\n    ? multiscales[0] // if multiple images (multiscales), just grab first one\n    : multiscales\n\n  const datasetsWithArrayMetadataRaw = await Promise.all(\n    multiscaleImage.datasets.map(async dataset => ({\n      dataset,\n      pixelArrayMetadata: await dataSource.getItem(`${dataset.path}/.zarray`),\n    }))\n  )\n\n  const datasetsWithArrayMetadata = ensureScaleTransforms(\n    datasetsWithArrayMetadataRaw\n  )\n\n  const scaleInfo = await Promise.all(\n    datasetsWithArrayMetadata.map(async ({ dataset, pixelArrayMetadata }) => {\n      return createScaledImageInfo({\n        multiscaleImage,\n        dataset,\n        pixelArrayMetadata,\n        dataSource,\n        multiscaleSpatialImageVersion,\n      })\n    })\n  )\n\n  const info = scaleInfo[0]\n\n  const components = info.arrayShape.get('c') ?? 1\n\n  const imageType = {\n    // How many spatial dimensions?  Count greater than 1, X Y Z elements because \"axis\" metadata not defined in ngff V0.1\n    dimension: ['x', 'y', 'z'].filter(dim => info.arrayShape.get(dim) > 1)\n      .length,\n    pixelType:\n      components === 1 ? PixelTypes.Scalar : PixelTypes.VariableLengthVector,\n    componentType: getComponentType(info.pixelArrayMetadata.dtype),\n    components,\n  }\n\n  return { scaleInfo, imageType }\n}\n\nclass ZarrMultiscaleSpatialImage extends MultiscaleSpatialImage {\n  // Store parameter is object with getItem (but not a ZarrStoreParser)\n  static async fromStore(store, maxConcurrency) {\n    const zarrStoreParser = new ZarrStoreParser(store)\n    const { scaleInfo, imageType } = await extractScaleSpacing(zarrStoreParser)\n    return new ZarrMultiscaleSpatialImage(\n      zarrStoreParser,\n      scaleInfo,\n      imageType,\n      maxConcurrency\n    )\n  }\n\n  static async fromUrl(url, maxConcurrency) {\n    return ZarrMultiscaleSpatialImage.fromStore(\n      new HttpStore(url),\n      maxConcurrency\n    )\n  }\n\n  // Use static factory functions to construct\n  constructor(zarrStoreParser, scaleInfo, imageType, maxConcurrency) {\n    super(scaleInfo, imageType)\n    this.dataSource = zarrStoreParser\n\n    const concurrency = Math.min(\n      window.navigator.hardwareConcurrency,\n      maxConcurrency ?? MAX_CONCURRENCY\n    )\n    this.rpcQueue = new PQueue({ concurrency })\n  }\n\n  async getChunksImpl(scale, cxyztArray) {\n    const info = this.scaleInfo[scale]\n    const chunkPathBase = info.pixelArrayPath\n    const chunkPaths = []\n    const chunkPromises = []\n\n    const { dimension_separator: dimSeparator = '.' } = info.pixelArrayMetadata\n\n    for (let index = 0; index < cxyztArray.length; index++) {\n      let chunkPath = `${chunkPathBase}/`\n      for (let dd = 0; dd < info.dims.length; dd++) {\n        const dim = info.dims[dd]\n        chunkPath = `${chunkPath}${\n          cxyztArray[index][CXYZT.indexOf(dim)]\n        }${dimSeparator}`\n      }\n      chunkPath = chunkPath.slice(0, -1)\n      chunkPaths.push(chunkPath)\n      chunkPromises.push(() => this.dataSource.getItem(chunkPath))\n    }\n    const compressedChunks = await this.rpcQueue.addAll(chunkPromises)\n\n    const toDecompress = []\n    for (let index = 0; index < compressedChunks.length; index++) {\n      toDecompress.push({\n        data: compressedChunks[index],\n        metadata: info.pixelArrayMetadata,\n      })\n    }\n\n    return bloscZarrDecompress(toDecompress)\n  }\n}\n\nexport default ZarrMultiscaleSpatialImage\n"
  },
  {
    "path": "src/IO/ZarrStoreParser.js",
    "content": "const isMetadata = item =>\n  ['.zattrs', '.zgroup', '.zarray'].some(knownMetadataFile =>\n    item.endsWith(knownMetadataFile)\n  )\n\nclass ZarrStore {\n  constructor(store) {\n    this.store = store\n    this.decoder = new TextDecoder()\n  }\n\n  toJson(data) {\n    return JSON.parse(this.decoder.decode(data))\n  }\n\n  async getItem(item) {\n    const data = await this.store.getItem(item)\n    return isMetadata(item) ? this.toJson(data) : data\n  }\n}\n\nexport default ZarrStore\n"
  },
  {
    "path": "src/IO/componentTypeToTypedArray.js",
    "content": "import { IntTypes, FloatTypes } from 'itk-wasm'\n\nconst componentTypeToTypedArray = new Map([\n  [IntTypes.Int8, Int8Array],\n  [IntTypes.UInt8, Uint8Array],\n  [IntTypes.Int16, Int16Array],\n  [IntTypes.UInt16, Uint16Array],\n  [IntTypes.Int32, Int32Array],\n  [IntTypes.UInt32, Uint32Array],\n\n  [FloatTypes.Float32, Float32Array],\n  [FloatTypes.Float64, Float64Array],\n])\n\nexport default componentTypeToTypedArray\n"
  },
  {
    "path": "src/IO/composeComponents.js",
    "content": "const sum = (a, b) => a + b\n\nconst countElements = componentInfo =>\n  componentInfo\n    .map(({ data, srcComponentCount }) => data.length / srcComponentCount)\n    .reduce(sum)\n\nconst getLargestTypeByBytes = componentInfo =>\n  componentInfo\n    .map(({ data }) => data)\n    .reduce((lastType, typedArray) =>\n      lastType.BYTES_PER_ELEMENT >= typedArray.BYTES_PER_ELEMENT\n        ? lastType\n        : typedArray\n    )\n\nconst fuseComponents = ({ componentInfo, arrayToFill }) => {\n  const elementCount = countElements(componentInfo)\n  const fusedImageData =\n    arrayToFill ??\n    new (getLargestTypeByBytes(componentInfo).constructor)(elementCount)\n\n  const componentCount = componentInfo.length\n  const tupleCount = elementCount / componentCount\n  for (let cIdx = 0; cIdx < componentCount; cIdx++) {\n    const { data, srcComponentCount, fromComponent } = componentInfo[cIdx]\n    for (let tuple = 0; tuple < tupleCount; tuple++) {\n      fusedImageData[tuple * componentCount + cIdx] =\n        data[tuple * srcComponentCount + fromComponent]\n    }\n  }\n  return fusedImageData\n}\n\n// returns \"component infos\"\nexport const parseByComponent = scaleImage => {\n  if (!scaleImage) return []\n\n  // lift ITK image into array if not already (like from InMemoryMultiscaleSpatialImage)\n  const scaleImages = Array.isArray(scaleImage) ? scaleImage : [scaleImage]\n  return scaleImages.flatMap(image => {\n    const srcComponentCount = image.imageType.components\n    // pull each component from image\n    return [...Array(srcComponentCount).keys()].map(fromComponent => ({\n      fromComponent,\n      srcComponentCount,\n      image,\n      data: image.data,\n    }))\n  })\n}\n\nexport const pickAndFuseComponents = async ({\n  image,\n  labelImage,\n  components,\n}) => {\n  // not Conglomerate, no label image, and all components needed: just return image\n  if (\n    !Array.isArray(image) &&\n    !labelImage &&\n    image.imageType.components === components.length\n  )\n    return image\n\n  const [imageByComponent, labelByComponent] = [image, labelImage].map(image =>\n    parseByComponent(image)\n  )\n  const componentInfo = components.map(\n    comp =>\n      comp >= 0 ? imageByComponent[comp] : labelByComponent[comp * -1 - 1] // label component index starts at -1\n  )\n\n  componentInfo.forEach((compInfo, idx) => {\n    if (!compInfo) {\n      throw new Error(\n        'pickAndFuseComponents: Missing component for requested component: ' +\n          idx\n      )\n    }\n  })\n\n  const imageArray = fuseComponents({\n    componentInfo,\n  })\n\n  const ranges = componentInfo.map(\n    ({ image: { ranges }, fromComponent }) => ranges && ranges[fromComponent]\n  )\n\n  // picks out one from ConglomerateImage\n  const singleImage = Array.isArray(image) ? image[0] : image\n\n  const itkImage = {\n    ...singleImage,\n    data: imageArray,\n    imageType: {\n      ...singleImage.imageType,\n      components: components.length,\n    },\n    ranges,\n  }\n  return itkImage\n}\n\nexport const composeComponents = images => {\n  const componentCount = images.map(i => i.imageType.components).reduce(sum)\n  // include all components\n  const components = [...Array(componentCount).keys()]\n  // compose Conglomerate images\n  return pickAndFuseComponents({\n    image: images,\n    components,\n  })\n}\n"
  },
  {
    "path": "src/IO/dimensionUtils.js",
    "content": "export const CXYZT = Object.freeze(['c', 'x', 'y', 'z', 't']) // viewer indexing\n\nexport const ensuredDims = (defaultValue, ensuredDims, dimMap) =>\n  ensuredDims.reduce(\n    (map, dim) => map.set(dim, map.get(dim) ?? defaultValue),\n    new Map(dimMap)\n  )\n\nexport const toDimensionMap = (dims, array) =>\n  new Map(dims.map((dim, i) => [dim, array[i]]))\n\n// example: orderBy(['y', 'x'])(new Map([['x', 1], ['y', 2], ['z', 3]])) -> Map([['y', 2], ['x', 1]])\n// drops dimensions that are not in dims!\nexport const orderBy = dims => map =>\n  new Map(dims.map(dim => [dim, map.get(dim)]))\n\nexport const chunkArray = (chunkSize, array) => {\n  const chunks = []\n  for (let i = 0; i < array.length; i += chunkSize) {\n    chunks.push(array.slice(i, i + chunkSize))\n  }\n  return chunks\n}\n"
  },
  {
    "path": "src/IO/dtypeUtils.js",
    "content": "import { IntTypes, FloatTypes } from 'itk-wasm'\n\n// Currently missing on Safari\nconst bigIntArrayType =\n  typeof globalThis.BigInt64Array === 'function'\n    ? globalThis.BigInt64Array\n    : Int32Array\nconst bigUintArrayType =\n  typeof globalThis.BigUint64Array === 'function'\n    ? globalThis.BigUint64Array\n    : Uint32Array\n\n// key is sans endian\nconst dtypeUtils = Array.from(\n  new Map([\n    ['b', [Int8Array, 'getInt8', IntTypes.Int8]],\n    ['B', [Uint8Array, 'getUint8', IntTypes.UInt8]],\n    ['u1', [Uint8Array, 'getUint8', IntTypes.UInt8]],\n    ['i1', [Int8Array, 'getInt8', IntTypes.Int8]],\n    ['u2', [Uint16Array, 'getUint16', IntTypes.UInt16]],\n    ['i2', [Int16Array, 'getInt16', IntTypes.Int16]],\n    ['u4', [Uint32Array, 'getUint32', IntTypes.UInt32]],\n    ['i4', [Int32Array, 'getInt32', IntTypes.Int32]],\n    ['u8', [bigUintArrayType, 'getBigUint64', IntTypes.UInt64]],\n    ['i8', [bigIntArrayType, 'getBigInt64', IntTypes.Int64]],\n\n    ['f4', [Float32Array, 'getFloat32', FloatTypes.Float32]],\n    ['f8', [Float64Array, 'getFloat64', FloatTypes.Float64]],\n  ])\n).reduce(\n  (map, [dtype, [TypedArray, dataViewGetter, itkComponent]]) =>\n    map.set(dtype, { TypedArray, dataViewGetter, itkComponent }),\n  new Map()\n)\n\nconst getType = dtype => dtype.replace(/^(<|>|=|\\|)/, '') // remove starting < > = | endianness\n\nexport const getSize = dtype => {\n  const type = getType(dtype)\n  return type.length < 2 ? 1 : Number(type.slice(-1))\n}\n\nexport const getComponentType = dtype =>\n  dtypeUtils.get(getType(dtype)).itkComponent\n\nexport const getTypedArray = dtype => dtypeUtils.get(getType(dtype)).TypedArray\n\nexport const testLittleEndian = dtype => dtype.charAt(0) === '<'\n\nexport const ElementGetter = (dtype, buffer) => {\n  const view = new DataView(buffer)\n  const size = getSize(dtype)\n  const isLittleEndian = testLittleEndian(dtype)\n  const { dataViewGetter } = dtypeUtils.get(getType(dtype))\n\n  return index => view[dataViewGetter](index * size, isLittleEndian)\n}\n\nexport const getDtype = (typedArrayConstructor, endianness = '<') => {\n  const typedArrayToDtype = new Map(\n    Array.from(dtypeUtils).map(([key, { TypedArray }]) => [TypedArray, key])\n  )\n  return `${endianness}${typedArrayToDtype.get(typedArrayConstructor)}`\n}\n"
  },
  {
    "path": "src/IO/fetchBinaryContent.js",
    "content": "import axios from 'axios'\nimport any from 'promise.any'\n\nasync function fetchBinaryContent(urlObj, progressCallback) {\n  if (urlObj.protocol === 'ipfs:') {\n    const splitPathname = urlObj.href.split('/')\n    const cid = splitPathname[2]\n    const path = splitPathname.slice(3).join('/')\n    const httpUrls = [`http://${cid}.ipfs.localhost:8080/${path}`]\n    const externalGateways = ['cf-ipfs.com', 'dweb.link']\n    externalGateways.forEach(g => {\n      const target = `https://${cid}.ipfs.${g}/${path}`\n      httpUrls.push(target)\n    })\n    try {\n      const responses = httpUrls.map((target, index) => {\n        const callback = index === 2 ? progressCallback : null\n        return axios.get(target, {\n          onDownloadProgress: callback,\n          responseType: 'arraybuffer',\n        })\n      })\n      const response = await any(responses)\n      return response.data\n    } catch (error) {\n      // Possibly no local node or network connection\n    }\n  } else {\n    const response = await axios.get(urlObj.href, {\n      onDownloadProgress: progressCallback,\n      responseType: 'arraybuffer',\n    })\n    return response.data\n  }\n}\n\nexport default fetchBinaryContent\n"
  },
  {
    "path": "src/IO/fetchJsonContent.js",
    "content": "import vtkHttpDataAccessHelper from 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper'\n\nconst fetchJsonContent = (url, progressCallback) =>\n  vtkHttpDataAccessHelper.fetchJSON({}, url, { progressCallback })\n\nexport default fetchJsonContent\n"
  },
  {
    "path": "src/IO/itkWasmUtils.js",
    "content": "import {\n  runPipeline,\n  InterfaceTypes,\n  imageSharedBufferOrCopy,\n  WorkerPool,\n  stackImages,\n} from 'itk-wasm'\n\nexport async function runWasm({\n  pipeline,\n  args,\n  images,\n  outputs = [{ type: InterfaceTypes.Image }],\n  maxSplits = 4, // avoid out of memory errors with larger images\n}) {\n  const numberOfWorkers = navigator.hardwareConcurrency || 6\n\n  const aImage = images[0]\n  const splits = Math.min(\n    parseInt(numberOfWorkers / 2),\n    Math.max(aImage.size[aImage.size.length - 1], 1),\n    maxSplits\n  )\n\n  const tasks = [...Array(splits).keys()].map(split => {\n    const taskArgs = [\n      ...[...Array(images.length).keys()].map(num => num.toString()),\n      '0',\n      ...args.map(o => o.toString()),\n      '--max-total-splits',\n      '' + splits,\n      '--split',\n      '' + split,\n      '--number-of-splits',\n      '' + splits,\n      '--memory-io',\n    ]\n\n    const inputs = images.map(image => ({\n      type: InterfaceTypes.Image,\n      data: imageSharedBufferOrCopy(image),\n    }))\n\n    return [pipeline, taskArgs, outputs, inputs]\n  })\n\n  const workerPool = new WorkerPool(numberOfWorkers, runPipeline)\n  const results = await workerPool.runTasks(tasks).promise\n  workerPool.terminateWorkers()\n  const validResults = results.filter(r => r.returnValue === 0)\n  const imageSplits = validResults.map(({ outputs }) => outputs[0].data)\n\n  return stackImages(imageSplits)\n}\n"
  },
  {
    "path": "src/IO/ndarrayToItkImage.js",
    "content": "import { PixelTypes, IntTypes, FloatTypes } from 'itk-wasm'\n\nconst numpy2itkType = {\n  int8: {\n    componentType: IntTypes.Int8,\n    arrayType: Int8Array,\n  },\n  uint8: {\n    componentType: IntTypes.UInt8,\n    arrayType: Uint8Array,\n  },\n  int16: {\n    componentType: IntTypes.Int16,\n    arrayType: Int16Array,\n  },\n  uint16: {\n    componentType: IntTypes.UInt16,\n    arrayType: Uint16Array,\n  },\n  int32: {\n    componentType: IntTypes.Int32,\n    arrayType: Int32Array,\n  },\n  uint32: {\n    componentType: IntTypes.UInt32,\n    arrayType: Uint32Array,\n  },\n  int64: {\n    componentType: IntTypes.Int64,\n    arrayType: BigInt64Array,\n  },\n  uint64: {\n    componentType: IntTypes.UInt64,\n    arrayType: BigUint64Array,\n  },\n  float32: {\n    componentType: FloatTypes.Float32,\n    arrayType: Float32Array,\n  },\n  float64: {\n    componentType: FloatTypes.Float64,\n    arrayType: Float64Array,\n  },\n  bool: {\n    componentType: IntTypes.UInt8,\n    arrayType: Uint8Array,\n  },\n}\n\nfunction ndarrayToItkImage(array) {\n  if (array._rtype !== 'ndarray') {\n    throw new Error('Invalid ndarray type: ' + array._rtype)\n  }\n  const { componentType, arrayType } = numpy2itkType[array._rdtype]\n  if (\n    array._rshape.length === 2 ||\n    (array._rshape.length == 3 && array._rshape[2] <= 4)\n  ) {\n    const channels = array._rshape.length === 3 ? array._rshape[2] : 1\n    const pixelType =\n      channels === 1 ? PixelTypes.Scalar : PixelTypes.VariableLengthVector\n    return {\n      imageType: {\n        dimension: 2,\n        pixelType,\n        componentType,\n        components: channels,\n      },\n      name: 'Image',\n      origin: [0.0, 0.0],\n      spacing: [1.0, 1.0],\n      direction: new Float64Array([1.0, 0.0, 0.0, 1.0]),\n      size: [array._rshape[1], array._rshape[0]],\n      data: new arrayType(array._rvalue),\n    }\n  } else if (array._rshape.length === 3) {\n    return {\n      imageType: {\n        dimension: 3,\n        pixelType: PixelTypes.Scalar,\n        componentType,\n        components: 1,\n      },\n      name: 'Image',\n      origin: [0.0, 0.0, 0.0],\n      spacing: [1.0, 1.0, 1.0],\n      direction: new Float64Array([\n        1.0,\n        0.0,\n        0.0,\n        0.0,\n        1.0,\n        0.0,\n        0.0,\n        0.0,\n        1.0,\n      ]),\n      size: [array._rshape[2], array._rshape[1], array._rshape[0]],\n      data: new arrayType(array._rvalue),\n    }\n  } else if (array._rshape.length === 4) {\n    return {\n      imageType: {\n        dimension: 3,\n        pixelType: PixelTypes.Scalar,\n        componentType,\n        components: array._rshape[3],\n      },\n      name: 'Image',\n      origin: [0.0, 0.0, 0.0],\n      spacing: [1.0, 1.0, 1.0],\n      direction: new Float64Array([\n        1.0,\n        0.0,\n        0.0,\n        0.0,\n        1.0,\n        0.0,\n        0.0,\n        0.0,\n        1.0,\n      ]),\n      size: [array._rshape[2], array._rshape[1], array._rshape[0]],\n      data: new arrayType(array._rvalue),\n    }\n  } else {\n    throw new Error(`Unsupported shape: ${array._rshape}`)\n  }\n}\n\nexport default ndarrayToItkImage\n"
  },
  {
    "path": "src/IO/ndarrayToPointSet.js",
    "content": "import vtk from 'vtk.js/Sources/vtk'\n\nconst numpy2TypedArray = {\n  int8: Int8Array,\n  uint8: Uint8Array,\n  int16: Int16Array,\n  uint16: Uint16Array,\n  int32: Int32Array,\n  uint32: Uint32Array,\n  float32: Float32Array,\n  float64: Float64Array,\n}\n\nfunction ndarrayToPointSet(array) {\n  if (array._rtype !== 'ndarray') {\n    throw new Error('Invalid ndarray type: ' + array._rtype)\n  }\n  let arrayType = numpy2TypedArray[array._rdtype]\n  if (array._rshape.length !== 2) {\n    throw new Error(`Unsupported dimension: ${array._rshape.length}`)\n  }\n  if (array._rshape[1] === 2) {\n    // convert to 3d point sets\n    const originalPoints = new arrayType(array._rvalue)\n    const newPoints = new Float32Array(\n      new ArrayBuffer(array._rshape[0] * 3 * 4)\n    )\n    for (let i = 0; i < array._rshape[0]; i++) {\n      newPoints[i * 3] = originalPoints[i * 2]\n      newPoints[i * 3 + 1] = originalPoints[i * 2 + 1]\n      newPoints[i * 3 + 2] = -5.0e-6\n    }\n    arrayType = Float32Array\n    array = {\n      _rtype: 'ndarray',\n      _rdtype: 'float32',\n      _rshape: [array._rshape[0], 3],\n      _rvalue: newPoints.buffer,\n    }\n  } else if (array._rshape[1] !== 3) {\n    throw new Error(`Unsupported shape: ${array._rshape}`)\n  }\n  const verts = new Uint32Array(new ArrayBuffer(array._rshape[0] * 2 * 4))\n  for (let i = 0; i < array._rshape[0] * 2; i += 2) {\n    verts[i] = 1\n    verts[i + 1] = i / 2\n  }\n  const size = array._rshape.reduce((a, b) => a * b, 1)\n  return vtk({\n    vtkClass: 'vtkPolyData',\n    points: {\n      vtkClass: 'vtkPoints',\n      name: '_points',\n      numberOfComponents: 3,\n      dataType: arrayType.name,\n      size,\n      values: new arrayType(array._rvalue),\n    },\n    verts: {\n      vtkClass: 'vtkCellArray',\n      name: '_verts',\n      numberOfComponents: 1,\n      dataType: 'Uint32Array',\n      size: array._rshape[0] * 2,\n      values: verts,\n    },\n  })\n}\n\nexport default ndarrayToPointSet\n"
  },
  {
    "path": "src/IO/processFiles.js",
    "content": "import {\n  extensionToMeshIO,\n  readImageFile,\n  readImageDICOMFileSeries,\n  readMeshFile,\n  FloatTypes,\n  getFileExtension,\n  meshToPolyData,\n} from 'itk-wasm'\nimport vtk from 'vtk.js/Sources/vtk'\nimport vtkXMLPolyDataReader from 'vtk.js/Sources/IO/XML/XMLPolyDataReader'\nimport vtkXMLImageDataReader from 'vtk.js/Sources/IO/XML/XMLImageDataReader'\nimport PromiseFileReader from 'promise-file-reader'\n\nimport vtkITKHelper from 'vtk.js/Sources/Common/DataModel/ITKHelper'\n\nimport UserInterface from '../UserInterface'\nimport createViewer from '../createViewer'\n\nconst MAX_LABELS_IN_LABEL_IMAGE = 64\n\nconst readDataFromFiles = async files => {\n  const readers = Array.from(files).map(async file => {\n    const extension = getFileExtension(file.name)\n    if (extension === 'vti') {\n      return PromiseFileReader.readAsArrayBuffer(file).then(fileContents => {\n        const vtiReader = vtkXMLImageDataReader.newInstance()\n        vtiReader.parseAsArrayBuffer(fileContents)\n        const vtkImage = vtiReader.getOutputData(0)\n        const itkImage = vtkITKHelper.convertVtkToItkImage(vtkImage)\n        return Promise.resolve({\n          is3D: true,\n          data: itkImage,\n        })\n      })\n    } else if (extension === 'vtp') {\n      return PromiseFileReader.readAsArrayBuffer(file).then(fileContents => {\n        const vtpReader = vtkXMLPolyDataReader.newInstance()\n        vtpReader.parseAsArrayBuffer(fileContents)\n        const polyData = vtpReader.getOutputData(0)\n        return Promise.resolve({\n          is3D: true,\n          data: polyData,\n        })\n      })\n    } else if (extensionToMeshIO.has(extension)) {\n      let is3D = true\n      try {\n        const read0 = performance.now()\n        const { mesh: itkMesh, webWorker } = await readMeshFile(null, file)\n        const read1 = performance.now()\n        const duration = Number(read1 - read0)\n          .toFixed(1)\n          .toString()\n        const { polyData: itkPolyData } = await meshToPolyData(\n          webWorker,\n          itkMesh\n        )\n        console.log('Mesh reading took ' + duration + ' milliseconds.')\n        webWorker.terminate()\n        const polyData = vtkITKHelper.convertItkToVtkPolyData(itkPolyData)\n        return { is3D, data: vtk(polyData) }\n      } catch (error) {\n        return readImageFile(null, file)\n          .then(({ image: itkImage, webWorker }) => {\n            webWorker.terminate()\n            is3D = itkImage.imageType.dimension === 3\n            return Promise.resolve({ is3D, data: itkImage })\n          })\n          .catch(error => {\n            return Promise.reject(error)\n          })\n      }\n    }\n    const { image: itkImage, webWorker } = await readImageFile(null, file)\n    itkImage.name = file.name\n    webWorker.terminate()\n    const is3D = itkImage.imageType.dimension === 3\n    return { is3D, data: itkImage }\n  })\n  return await Promise.all(readers)\n}\n\nexport const processFiles = async (\n  container,\n  {\n    files,\n    image,\n    labelImage,\n    fixedImage,\n    config,\n    labelImageNames,\n    rotate,\n    use2D,\n    ...rest\n  }\n) => {\n  UserInterface.emptyContainer(container)\n  UserInterface.createLoadingProgress(container)\n  const viewerConfig = await readFiles({\n    files,\n    image,\n    labelImage,\n    labelImageNames,\n    use2D,\n  })\n  return createViewer(container, {\n    ...viewerConfig,\n    config,\n    rotate,\n    fixedImage,\n    ...rest,\n  })\n}\n\nexport const readFiles = async ({\n  files,\n  image,\n  labelImage,\n  labelImageNames,\n  use2D,\n}) => {\n  let readDICOMSeries = readImageDICOMFileSeries\n  if (files.length < 2 || !image) {\n    readDICOMSeries = function() {\n      return Promise.reject('Skip DICOM series read attempt')\n    }\n  }\n  try {\n    const { image: itkImage, webWorkerPool } = await readDICOMSeries(files)\n    webWorkerPool.terminateWorkers()\n    itkImage.name = files[0].name\n    const is3D = itkImage.imageType.dimension === 3 && !use2D\n    return {\n      image: itkImage,\n      labelImage,\n      use2D: !is3D,\n    }\n  } catch (error) {\n    const dataSets = await readDataFromFiles(files)\n    let imagesFromFiles = dataSets\n      .map(({ data }) => data)\n      .filter(data => !!data && data.imageType !== undefined)\n\n    // find labelImage\n    const labelImageResult =\n      labelImage ??\n      imagesFromFiles.find(image => {\n        // Only integer-based pixels considered for label maps\n        const { componentType } = image.imageType\n        if (\n          componentType !== FloatTypes.Float32 &&\n          componentType !== FloatTypes.Float64\n        ) {\n          // If there are more values than this, it will not be considered a\n          // label map\n          const uniqueLabels = new Set(image.data).size\n          if (uniqueLabels <= MAX_LABELS_IN_LABEL_IMAGE) return image\n        }\n      })\n\n    imagesFromFiles = imagesFromFiles.filter(\n      image => image !== labelImageResult\n    )\n\n    const labelImageNameData = labelImageNames ? new Map(labelImageNames) : null\n\n    const geometries = dataSets\n      .filter(({ data }) => {\n        return (\n          !!data &&\n          data.isA !== undefined &&\n          data.isA('vtkPolyData') &&\n          !!(\n            data.getPolys().getNumberOfValues() ||\n            data.getLines().getNumberOfValues() ||\n            data.getStrips().getNumberOfValues()\n          )\n        )\n      })\n      .map(({ data }) => data)\n\n    const pointSets = dataSets\n      .filter(({ data }) => {\n        return (\n          !!data &&\n          data.isA !== undefined &&\n          data.isA('vtkPolyData') &&\n          !(\n            data.getPolys().getNumberOfValues() ||\n            data.getLines().getNumberOfValues() ||\n            data.getStrips().getNumberOfValues()\n          )\n        )\n      })\n      .map(({ data }) => data)\n\n    const outImage = image ?? imagesFromFiles[0]\n\n    const any3D = [\n      ...dataSets.map(({ is3D }) => is3D),\n      ...[outImage, labelImageResult].map(\n        image => image?.imageType.dimension === 3\n      ),\n    ].some(is3D => is3D)\n\n    return {\n      image: outImage,\n      labelImage: labelImageResult,\n      labelImageNames: labelImageNameData,\n      geometries,\n      pointSets,\n      use2D: use2D || !any3D,\n    }\n  }\n}\n"
  },
  {
    "path": "src/IO/toMultiscaleSpatialImage.js",
    "content": "import { readImageArrayBuffer } from 'itk-wasm'\n\nimport MultiscaleSpatialImage from './MultiscaleSpatialImage'\nimport InMemoryMultiscaleSpatialImage from './InMemoryMultiscaleSpatialImage'\nimport ZarrMultiscaleSpatialImage, {\n  isZarr,\n} from './ZarrMultiscaleSpatialImage'\nimport ndarrayToItkImage from './ndarrayToItkImage'\nimport fetchBinaryContent from './fetchBinaryContent'\n\nasync function itkImageToInMemoryMultiscaleSpatialImage(image, isLabelImage) {\n  let chunkSize = [64, 64, 64]\n  if (image.data.length < 2e6) {\n    // Keep a single chunk\n    chunkSize = image.size\n  } else if (image.imageType.dimension === 2) {\n    chunkSize = [256, 256]\n  }\n\n  const {\n    scaleInfo,\n    imageType,\n    pyramid,\n  } = await InMemoryMultiscaleSpatialImage.buildPyramid(\n    image,\n    chunkSize,\n    isLabelImage\n  )\n  const multiscaleImage = new InMemoryMultiscaleSpatialImage(\n    pyramid,\n    scaleInfo,\n    imageType,\n    image.name\n  )\n\n  return multiscaleImage\n}\n\nasync function toMultiscaleSpatialImage(\n  image,\n  isLabelImage = false,\n  maxConcurrency\n) {\n  let multiscaleImage = null\n  if (image instanceof MultiscaleSpatialImage) {\n    // Already a multi-scale, chunked image\n    multiscaleImage = image\n  } else if (image.imageType !== undefined) {\n    // itk-wasm Image\n    multiscaleImage = await itkImageToInMemoryMultiscaleSpatialImage(\n      image,\n      isLabelImage\n    )\n  } else if (typeof image.getItem === 'function') {\n    // key value store\n    multiscaleImage = ZarrMultiscaleSpatialImage.fromStore(\n      image,\n      maxConcurrency\n    )\n  } else if (image._rtype !== undefined && image._rtype === 'ndarray') {\n    // ndarray\n    const itkImage = ndarrayToItkImage(image)\n    multiscaleImage = await itkImageToInMemoryMultiscaleSpatialImage(\n      itkImage,\n      isLabelImage\n    )\n  } else if (image.href !== undefined) {\n    if (isZarr(image.href)) {\n      multiscaleImage = ZarrMultiscaleSpatialImage.fromUrl(\n        image,\n        maxConcurrency\n      )\n    } else {\n      const dataBuffer = await fetchBinaryContent(image)\n      const { image: itkImage, webWorker } = await readImageArrayBuffer(\n        null,\n        dataBuffer,\n        image.pathname.split('/').pop()\n      )\n      webWorker.terminate()\n      multiscaleImage = await itkImageToInMemoryMultiscaleSpatialImage(\n        itkImage,\n        isLabelImage\n      )\n    }\n  } else {\n    throw new Error('Unexpected image')\n  }\n\n  return multiscaleImage\n}\n\nexport default toMultiscaleSpatialImage\n"
  },
  {
    "path": "src/IO/uploadFileHandler.js",
    "content": "import curry from 'curry'\n\nimport preventDefaults from './UserInterface/preventDefaults'\nimport processFiles from './processFiles'\n\n/* Example usage:\n\nimport uploadIcon from 'itk-vtk-viewer/src/UserInterface/icons/upload.svg';\nimport getContrastSensitiveStyle from 'itk-vtk-viewer/src/UserInterface/getContrastSensitiveStyle';\n\nconst isBackgroundDark = false;\n\nconst contrastSensitiveStyle = getContrastSensitiveStyle(\n  ['uploadButton'],\n  isBackgroundDark\n);\n\nconst uploadButton = document.createElement('div');\nuploadButton.innerHTML = `<div class=\"${\n  contrastSensitiveStyle.uploadButton\n}\">${uploadIcon}</div><input type=\"file\" class=\"file\" style=\"display: none;\" multiple/>`;\nconst fileInput = uploadButton.querySelector('input');\n\nfileInput.addEventListener('change', uploadFileHandler);\nuploadButton.addEventListener('drop', uploadFileHandler);\nuploadButton.addEventListener('click', (e) => fileInput.click());\nuploadButton.addEventListener('dragover', preventDefaults);\nmainUIRow.appendChild(uploadButton);\n\n*/\nconst uploadFileHandler = curry(async function(container, event) {\n  preventDefaults(event)\n  const dataTransfer = event.dataTransfer\n  const files = event.target.files || dataTransfer.files\n  await processFiles(container, { files })\n})\nexport default uploadFileHandler\n"
  },
  {
    "path": "src/ImJoyPluginAPI.js",
    "content": "class ImJoyPluginAPI {\n  async setup() {\n    this.viewer = null\n    itkVtkViewer.createViewerFromLocalFiles(container).then(viewer => {\n      this.viewer = viewer\n    })\n  }\n\n  async run(ctx) {\n    if (!ctx.data) return\n\n    let pointSets = null\n    if (ctx.data.pointSets) {\n      pointSets = ctx.data.pointSets\n\n      if (!Array.isArray(pointSets)) pointSets = [pointSets]\n\n      pointSets = pointSets.map(points =>\n        itkVtkViewer.utils.ndarrayToPointSet(points)\n      )\n    }\n\n    if (ctx.config) {\n      this.viewer = await itkVtkViewer.createViewer(container, {\n        image: ctx.data.image,\n        labelImage: ctx.data.labelImage,\n        fixedImage: ctx.data?.fixedImage,\n        compare: ctx.data?.compare,\n        pointSets,\n        geometries: null,\n        rotate: false,\n        config: ctx.config,\n      })\n    } else {\n      if (pointSets) {\n        await this.setPointSets(ctx.data.pointSets)\n      }\n    }\n  }\n\n  async setPointSets(pointSets) {\n    if (!Array.isArray(pointSets)) pointSets = [pointSets]\n    pointSets = pointSets.map(points =>\n      itkVtkViewer.utils.ndarrayToPointSet(points)\n    )\n    if (this.viewer === null) {\n      this.viewer = await itkVtkViewer.createViewer(container, {\n        image: null,\n        pointSets,\n        geometries: null,\n        rotate: false,\n      })\n    } else {\n      await this.viewer.setPointSets(pointSets)\n    }\n  }\n\n  addPointSet(pointSet) {\n    let points = itkVtkViewer.utils.ndarrayToPointSet(pointSet)\n    this.viewer.addPointSet(points)\n  }\n\n  async captureImage() {\n    return await this.viewer.captureImage()\n  }\n\n  async setImage(image, name) {\n    if (this.viewer === null) {\n      this.viewer = await itkVtkViewer.createViewer(container, {\n        image,\n        imageName: name,\n        rotate: false,\n      })\n    } else {\n      await this.viewer.setImage(image, name)\n    }\n  }\n\n  getImage(name) {\n    return this.viewer.getImage(name)\n  }\n\n  async setLabelImage(labelImage) {\n    if (this.viewer === null) {\n      this.viewer = await itkVtkViewer.createViewer(container, {\n        labelImage: labelImage,\n        rotate: false,\n      })\n    } else {\n      await this.viewer.setLabelImage(labelImage)\n    }\n  }\n\n  getLabelImage() {\n    return this.viewer.getLabelImage()\n  }\n\n  registerEventListener(event, callback) {\n    this.viewer.on(event, callback)\n  }\n\n  getConfig() {\n    return this.viewer.getConfig()\n  }\n\n  setRenderingViewContainerStyle(containerStyle) {\n    this.viewer.setRenderingViewContainerStyle(containerStyle)\n  }\n  getRenderingViewStyle() {\n    return this.viewer.getRenderingViewContainerStyle()\n  }\n\n  setBackgroundColor(bgColor) {\n    this.viewer.setBackgroundColor(bgColor)\n  }\n  getBackgroundColor() {\n    return this.viewer.getBackgroundColor()\n  }\n\n  setUnits(units) {\n    this.viewer.setUnits(units)\n  }\n  getUnits() {\n    return this.viewer.getUnits()\n  }\n\n  setUICollapsed(collapsed) {\n    this.viewer.setUICollapsed(collapsed)\n  }\n  getUICollapsed() {\n    return this.viewer.getUICollapsed()\n  }\n\n  setRotateEnabled(enabled) {\n    this.viewer.setRotateEnabled(enabled)\n  }\n  getRotateEnabled() {\n    return this.viewer.getRotateEnabled()\n  }\n\n  setAnnotationsEnabled(enabled) {\n    this.viewer.setAnnotationsEnabled(enabled)\n  }\n  getAnnotationsEnabled() {\n    return this.viewer.getAnnotationsEnabled()\n  }\n\n  setAxesEnabled(enabled) {\n    this.viewer.setAxesEnabled(enabled)\n  }\n  getAxesEnabled() {\n    return this.viewer.getAxesEnabled()\n  }\n\n  setXSlice(position) {\n    this.viewer.setXSlice(position)\n  }\n\n  getXSlice() {\n    return this.viewer.getXSlice()\n  }\n\n  setYSlice(position) {\n    this.viewer.setYSlice(position)\n  }\n\n  getYSlice() {\n    return this.viewer.getYSlice()\n  }\n\n  setZSlice(position) {\n    this.viewer.setZSlice(position)\n  }\n  getZSlice() {\n    return this.viewer.getZSlice()\n  }\n\n  setViewMode(mode) {\n    this.viewer.setViewMode(mode)\n  }\n  getViewMode() {\n    return this.viewer.getViewMode()\n  }\n\n  getLayerNames() {\n    return this.viewer.getLayerNames()\n  }\n\n  setLayerVisibility(visible, name) {\n    this.viewer.setLayerVisibility(visible, name)\n  }\n\n  getLayerVisibility(name) {\n    return this.viewer.getLayerVisibility(name)\n  }\n\n  selectLayer(name) {\n    this.viewer.selectLayer(name)\n  }\n\n  setImageComponentVisibility(visibility, component, name) {\n    this.viewer.setImageComponentVisibility(visibility, component, name)\n  }\n\n  getImageComponentVisibility(component, name) {\n    return this.viewer.getImageComponentVisibility(component, name)\n  }\n\n  setImageInterpolationEnabled(enabled) {\n    this.viewer.setImageInterpolationEnabled(enabled)\n  }\n  getImageInterpolationEnabled() {\n    return this.viewer.getImageInterpolationEnabled()\n  }\n\n  setImageColorRange(range, component, name) {\n    this.viewer.setImageColorRange(range, component, name)\n  }\n\n  getImageColorRange(component, name) {\n    return this.viewer.getImageColorRange(component, name)\n  }\n\n  setImageColorRangeMin(min, component, name) {\n    this.viewer.setImageColorRangeMin(min, component, name)\n  }\n\n  setImageColorRangeMax(max, component, name) {\n    this.viewer.setImageColorRangeMax(max, component, name)\n  }\n\n  setImageColorRangeBounds(bounds, component, name) {\n    this.viewer.setImageColorRangeBounds(bounds, component, name)\n  }\n\n  getImageColorRangeBounds(component, name) {\n    return this.viewer.getImageColorRangeBounds(component, name)\n  }\n\n  setImageColorMap(colorMap, component, name) {\n    this.viewer.setImageColorMap(colorMap, component, name)\n  }\n\n  getImageColorMap(component, name) {\n    return this.viewer.getImageColorMap(component, name)\n  }\n\n  setImagePiecewiseFunctionPoints(points, component, name) {\n    this.viewer.setImagePiecewiseFunctionPoints(points, component, name)\n  }\n\n  getImagePiecewiseFunctionPoints(component, name) {\n    return this.viewer.getImagePiecewiseFunctionPoints(component, name)\n  }\n\n  setImageShadowEnabled(shadow, name) {\n    this.viewer.setImageShadowEnabled(shadow, name)\n  }\n\n  getImageShadowEnabled(name) {\n    return this.viewer.getImageShadowEnabled(name)\n  }\n\n  setImageGradientOpacity(opacity, name) {\n    this.viewer.setImageGradientOpacity(opacity, name)\n  }\n\n  getImageGradientOpacity(name) {\n    return this.viewer.getImageGradientOpacity(name)\n  }\n\n  setImageGradientOpacityScale(scale, name) {\n    this.viewer.setImageGradientOpacityScale(scale, name)\n  }\n\n  getImageGradientOpacityScale(name) {\n    return this.viewer.getImageGradientOpacityScale(name)\n  }\n\n  setImageVolumeSampleDistance(distance, name) {\n    this.viewer.setImageVolumeSampleDistance(distance, name)\n  }\n\n  getImageVolumeSampleDistance(name) {\n    return this.viewer.getImageVolumeSampleDistance(name)\n  }\n\n  setImageBlendMode(mode, name) {\n    this.viewer.setImageBlendMode(mode, name)\n  }\n\n  getImageBlendMode(name) {\n    return this.viewer.getImageBlendMode(name)\n  }\n\n  setLabelImageLookupTable(lookupTable, name) {\n    this.viewer.setLabelImageLookupTable(lookupTable, name)\n  }\n\n  getLabelImageLookupTable(name) {\n    return this.viewer.getLabelImageLookupTable(name)\n  }\n\n  setLabelImageBlend(blend, name) {\n    this.viewer.setLabelImageBlend(blend, name)\n  }\n\n  getLabelImageBlend(name) {\n    return this.viewer.getLabelImageBlend(name)\n  }\n\n  setLabelImageLabelNames(labelNames, name) {\n    this.viewer.setLabelImageLabelNames(labelNames, name)\n  }\n\n  getLabelImageLabelNames(name) {\n    return this.viewer.getLabelImageLabelNames(name)\n  }\n\n  setLabelImageWeights(weights, name) {\n    this.viewer.setLabelImageWeights(weights, name)\n  }\n\n  getLabelImageWeights(name) {\n    return this.viewer.getLabelImageWeights(name)\n  }\n\n  setCroppingPlanesEnabled(enabled) {\n    this.viewer.setCroppingPlanesEnabled(enabled)\n  }\n\n  getCroppingPlanesEnabled() {\n    return this.viewer.getCroppingPlanesEnabled()\n  }\n\n  setCroppingPlanes(croppingPlanes) {\n    this.viewer.setCroppingPlanes(croppingPlanes)\n  }\n\n  getCroppingPlanes() {\n    return this.viewer.getCroppingPlanes()\n  }\n\n  setImageVolumeScatteringBlend(scatteringBlend, name) {\n    this.viewer.setImageVolumeScatteringBlend(scatteringBlend, name)\n  }\n\n  getImageVolumeScatteringBlend(name) {\n    return this.viewer.getImageVolumeScatteringBlend(name)\n  }\n\n  setRpcMaxConcurrency(value) {\n    this.viewer.setMaxConcurrency(value)\n  }\n\n  getRpcMaxConcurrency() {\n    return this.viewer.getMaxConcurrency()\n  }\n\n  compareImages(fixedImageName, movingImageName, options) {\n    return this.viewer.setCompareImages(\n      fixedImageName,\n      movingImageName,\n      options\n    )\n  }\n\n  getCompareImages(name) {\n    return this.viewer.getCompareImages(name)\n  }\n\n  getLoadedScale(scale) {\n    return this.viewer.getLoadedScale(scale)\n  }\n\n  getCroppedImageWorldBounds() {\n    return this.viewer.getCroppedImageWorldBounds()\n  }\n\n  async getCroppedIndexBounds(scale) {\n    return await this.viewer.getCroppedIndexBounds(scale)\n  }\n}\n\nexport default ImJoyPluginAPI\n"
  },
  {
    "path": "src/Rendering/Images/createImageRenderingActor.js",
    "content": "import { assign, createMachine, forwardTo, send } from 'xstate'\nimport { defaultCompare } from '../../Context/ImageActorContext'\nimport { makeTransitions } from './makeTransitions'\n\nexport const getOutputIntensityComponentCount = actorContext => {\n  const {\n    image,\n    compare: { method },\n  } = actorContext\n  if (method && method !== 'disabled') return 2\n  return image.imageType.components\n}\n\nconst getLoadedImage = actorContext =>\n  actorContext.image ?? actorContext.labelImage\n\nconst assignColorRange = assign({\n  images: (\n    { images },\n    { data: { name, component, range, keepAutoAdjusting = false } }\n  ) => {\n    const {\n      colorRanges,\n      colorRangeMinAutoAdjust,\n      colorRangeMaxAutoAdjust,\n    } = images.actorContext.get(name)\n\n    colorRanges.set(component, range)\n\n    colorRangeMinAutoAdjust.set(\n      component,\n      colorRangeMinAutoAdjust.get(component) && keepAutoAdjusting\n    )\n    colorRangeMaxAutoAdjust.set(\n      component,\n      colorRangeMaxAutoAdjust.get(component) && keepAutoAdjusting\n    )\n\n    return images\n  },\n})\n\nconst assignColorRangeMin = assign({\n  images: ({ images }, { data: { name, component } }) => {\n    const { colorRangeMinAutoAdjust } = images.actorContext.get(name)\n    colorRangeMinAutoAdjust.set(component, false)\n    return images\n  },\n})\n\nconst updateColorRangeMin = (context, e) => {\n  const {\n    data: { name, component, value },\n  } = e\n  const { colorRanges } = context.images.actorContext.get(name)\n  const [, max] = colorRanges.get(component)\n  context.service.send({\n    type: 'IMAGE_COLOR_RANGE_CHANGED',\n    data: {\n      name,\n      component,\n      range: [value, max],\n      keepAutoAdjusting: true, // let max change\n    },\n  })\n}\n\nconst assignColorRangeMax = assign({\n  images: ({ images }, { data: { name, component } }) => {\n    const { colorRangeMaxAutoAdjust } = images.actorContext.get(name)\n    colorRangeMaxAutoAdjust.set(component, false)\n    return images\n  },\n})\n\nconst updateColorRangeMax = (context, e) => {\n  const {\n    data: { name, component, value },\n  } = e\n  const { colorRanges } = context.images.actorContext.get(name)\n  const [min] = colorRanges.get(component)\n  context.service.send({\n    type: 'IMAGE_COLOR_RANGE_CHANGED',\n    data: {\n      name,\n      component,\n      range: [min, value],\n      keepAutoAdjusting: true, // let min change\n    },\n  })\n}\n\nconst assignUpdateRenderedName = assign({\n  images: (context, event) => {\n    const images = context.images\n    images.updateRenderedName = event.data.name\n    return images\n  },\n})\n\nconst assignUpdateRenderedNameToSelectedName = assign({\n  images: context => {\n    const images = context.images\n    images.updateRenderedName = images.selectedName\n    return images\n  },\n})\n\nconst assignFinerScale = assign({\n  targetScale: ({ targetScale }) => {\n    return Math.max(0, targetScale - 1)\n  },\n})\n\nconst assignCoarserScale = assign({\n  targetScale: ({ images, targetScale }) => {\n    const actorContext = images.actorContext.get(images.updateRenderedName)\n    if (targetScale < getLoadedImage(actorContext).coarsestScale) {\n      return targetScale + 1\n    }\n    return targetScale\n  },\n  hasScaledCoarser: true,\n})\n\nconst assignLoadedScale = assign({\n  images: ({ images }, { data }) => {\n    const name = data.name ?? data\n    const actorContext = images.actorContext.get(name)\n    actorContext.loadedScale = data.loadedScale\n    return images\n  },\n})\n\nconst assignClearHistograms = assign({\n  images: ({ images }, { data }) => {\n    const name = data.name ?? data\n    const actorContext = images.actorContext.get(name)\n    actorContext.histograms = new Map()\n    return images\n  },\n})\n\nconst LOW_FPS = 10.0\nconst HIGH_FPS = 30.0\n\n// Return true if finest scale or already backed off coarser or FPS is in Goldilocks zone\nfunction finestScaleOrScaleJustRight(context) {\n  const { loadedScale } = context.images.actorContext.get(\n    context.images.updateRenderedName\n  )\n  return (\n    loadedScale === 0 ||\n    context.hasScaledCoarser ||\n    (LOW_FPS < context.main.fps && context.main.fps < HIGH_FPS)\n  )\n}\n\nfunction isFpsLow(context) {\n  return context.main.fps <= LOW_FPS\n}\n\nfunction isLoadedScaleMostCoarse(context) {\n  const actorContext = context.images.actorContext.get(\n    context.images.updateRenderedName\n  )\n  return getLoadedImage(actorContext).coarsestScale === actorContext.loadedScale\n}\n\nconst assignIsFramerateScalePickingOn = assign({\n  images: ({ images }, { type }) => {\n    const actorContext = images.actorContext.get(images.updateRenderedName)\n    actorContext.isFramerateScalePickingOn = type !== 'SET_IMAGE_SCALE'\n    return images\n  },\n})\n\nconst assignCinematic = assign({\n  images: ({ images }, { data: { params, name } }) => {\n    const actorContext = images.actorContext.get(name)\n    actorContext.cinematicParameters = {\n      ...actorContext.cinematicParameters,\n      ...params,\n    }\n    return images\n  },\n})\n\nconst sendCinematicChanged = context => {\n  const actorContext = context.images.actorContext.get(\n    context.images.selectedName\n  )\n  context.service.send({\n    type: 'CINEMATIC_CHANGED',\n    actorContext,\n  })\n}\n\nconst computeIsCinematicPossible = (context, { data: { itkImage, name } }) => {\n  const isCinematicPossible = itkImage.imageType.components === 1\n\n  context.service.send({\n    type: 'SET_CINEMATIC_PARAMETERS',\n    data: {\n      name,\n      params: { isCinematicPossible },\n    },\n  })\n}\n\n// force rebuilding image\nconst forceUpdate = c =>\n  c.service.send({\n    type: 'UPDATE_RENDERED_IMAGE',\n    data: { name: c.actorName },\n  })\n\nconst sendCompareUpdated = (c, { data: { name } }) => {\n  c.service.send({\n    type: 'COMPARE_UPDATED',\n    data: { name },\n  })\n}\n\nconst updateCompare = (\n  { service, use2D, images: { actorContext: actorMap } },\n  name\n) => {\n  const actorContext = actorMap.get(name)\n\n  const { method, imageMix } = actorContext.compare\n  const { method: lastMethod, imageMix: lastImageMix } =\n    actorContext.lastCompare ?? {}\n\n  if (lastMethod !== method) {\n    let colorMaps\n    if (method === 'green-magenta') {\n      colorMaps = ['BkGn', 'BkMa']\n    }\n    if (method === 'cyan-magenta') {\n      colorMaps = ['BkCy', 'BkMa']\n    }\n    if (method === 'cyan-red') {\n      colorMaps = ['BkCy', 'BkRd']\n    }\n    if (colorMaps) {\n      // besides setting the color maps, event adds another entry in colormap Map for the possibly new second component\n      const [firstColorMap, secondColorMap] = colorMaps\n      service.send({\n        type: 'IMAGE_COLOR_MAP_CHANGED',\n        data: { name, component: 0, colorMap: firstColorMap },\n      })\n      service.send({\n        type: 'IMAGE_COLOR_MAP_CHANGED',\n        data: { name, component: 1, colorMap: secondColorMap },\n      })\n    }\n\n    if (method === 'blend' || method === 'checkerboard') {\n      const colorForSecondComp = actorContext.colorMaps.get(0)\n      service.send({\n        type: 'IMAGE_COLOR_MAP_CHANGED',\n        data: { name, component: 1, colorMap: colorForSecondComp },\n      })\n    }\n  }\n\n  if (method !== 'disabled' && imageMix !== lastImageMix) {\n    const mix0 = 1 - imageMix\n    const mix1 = imageMix\n    for (let component = 0; component < 2; component++) {\n      const startPoints = actorContext.piecewiseFunctionPoints.get(component)\n      const firstX = (startPoints && startPoints[0][0]) ?? 0\n      const lastX = (startPoints && startPoints[startPoints.length - 1][0]) ?? 1\n      const onePoint = startPoints && startPoints.length === 1\n\n      const mix = component ? mix1 : mix0\n      const points = use2D\n        ? [...(onePoint ? [] : [[firstX, mix]]), [lastX, mix]]\n        : [...(onePoint ? [] : [[firstX, 0]]), [lastX, mix]]\n      service.send({\n        type: 'IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED',\n        data: { name, component, points },\n      })\n      // clamp points to color range to respect window and level\n      const range =\n        actorContext.colorRanges.get(component) ??\n        actorContext.colorRanges.get(0)\n      if (range) {\n        service.send({\n          type: 'IMAGE_COLOR_RANGE_CHANGED',\n          data: { name, component, range },\n        })\n      }\n    }\n  }\n}\n\nconst computeCheckerboard = (currentCompare, lastCompare) => {\n  if (\n    lastCompare.method !== 'checkerboard' &&\n    currentCompare.method === 'checkerboard'\n  )\n    return true\n  if (\n    lastCompare.method === 'checkerboard' &&\n    currentCompare.method !== 'checkerboard'\n  )\n    return false\n  return currentCompare.checkerboard\n}\n\nconst computeImageMix = (currentCompare, lastCompare) => {\n  if (currentCompare.method !== lastCompare.method) {\n    if (currentCompare.checkerboard)\n      return currentCompare.swapImageOrder ? 1 : 0\n    return 0.5\n  }\n\n  if (currentCompare.swapImageOrder !== lastCompare.swapImageOrder)\n    return currentCompare.swapImageOrder ? 1 : 0\n\n  return currentCompare.imageMix\n}\n\nconst assignCompare = assign({\n  images: (context, { data: { name, fixedImageName, options } }) => {\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.lastCompare = { ...actorContext.compare } // for diffing later by updateCompare, UI, etc.\n\n    const updatedCompare = {\n      ...defaultCompare,\n      ...actorContext.compare,\n      ...options,\n    }\n\n    const computedCheckerboard = {\n      ...updatedCompare,\n      checkerboard: computeCheckerboard(\n        updatedCompare,\n        actorContext.lastCompare\n      ),\n      // after computed values to let explicit set of values to take precedence\n      ...options,\n    }\n\n    const computedImageMix = {\n      ...computedCheckerboard,\n      imageMix: computeImageMix(computedCheckerboard, actorContext.lastCompare),\n    }\n\n    actorContext.compare = {\n      fixedImageName,\n      ...computedImageMix,\n      // after computed values to let explicit set of values to take precedence\n      ...options,\n    }\n    updateCompare(context, name)\n    return context.images\n  },\n})\n\nconst dirtyColorRanges = c => {\n  const actorContext = c.images.actorContext.get(c.actorName)\n  actorContext.dirtyColorRanges = true\n}\n\nconst cleanColorRanges = (c, { data: { name } }) => {\n  const actorContext = c.images.actorContext.get(name)\n  if (actorContext.dirtyColorRanges) {\n    // let applyRenderedImage update colorRanges and colorRangeBounds\n    actorContext.colorRanges = new Map()\n    const componentCount = getOutputIntensityComponentCount(actorContext)\n    actorContext.colorRangeBoundsAutoAdjust = new Map(\n      [...Array(componentCount).keys()].map(c => [c, true])\n    )\n    actorContext.colorRangeMinAutoAdjust = new Map(\n      [...Array(componentCount).keys()].map(c => [c, true])\n    )\n    actorContext.colorRangeMaxAutoAdjust = new Map(\n      [...Array(componentCount).keys()].map(c => [c, true])\n    )\n    actorContext.piecewiseFunctionPointsAutoAdjust = new Map(\n      [...Array(componentCount).keys()].map(c => [c, true])\n    )\n\n    actorContext.dirtyColorRanges = false\n  }\n}\n\nconst afterCompareMaybeForceUpdate = context => {\n  const {\n    actorName,\n    images: { actorContext: actorMap },\n  } = context\n  const actorContext = actorMap.get(actorName)\n\n  // eslint-disable-next-line no-unused-vars\n  const { imageMix, swapImageOrder, ...compare } = actorContext.compare\n  // eslint-disable-next-line no-unused-vars\n  const { imageMix: _, swapImageOrder: __, ...lastCompare } =\n    actorContext.lastCompare ?? {}\n\n  if (JSON.stringify(compare) === JSON.stringify(lastCompare)) return\n\n  dirtyColorRanges(context)\n  forceUpdate(context)\n}\n\nconst applyAnimateImageMix = (\n  { images: { actorContext: actorMap }, itkVtkView, service },\n  { data: { play, name } }\n) => {\n  const actorContext = actorMap.get(name)\n  if (play) {\n    if (!actorContext.imageMixAnimationDirection)\n      actorContext.imageMixAnimationDirection = 1\n\n    itkVtkView.getInteractor().requestAnimation('animateImageMix')\n    actorContext.imageMixAnimation = itkVtkView\n      .getInteractor()\n      .onAnimation(() => {\n        const { imageMix, fixedImageName } = actorContext.compare\n        let newMix = imageMix + 0.02 * actorContext.imageMixAnimationDirection\n        if (newMix > 1) {\n          newMix = 1\n          actorContext.imageMixAnimationDirection *= -1\n        }\n        if (newMix < 0) {\n          newMix = 0\n          actorContext.imageMixAnimationDirection *= -1\n        }\n        service.send({\n          type: 'COMPARE_IMAGES',\n          data: {\n            name,\n            fixedImageName: fixedImageName,\n            options: { imageMix: newMix },\n          },\n        })\n      })\n  } else if (actorContext.imageMixAnimation) {\n    actorContext.imageMixAnimation.unsubscribe()\n    actorContext.imageMixAnimation = null\n    itkVtkView.getInteractor().cancelAnimation('animateImageMix')\n  }\n}\n\nconst KNOWN_ERRORS = [\n  'Voxel count over max at scale',\n  'Image byte count over max at scale',\n  \"Failed to execute 'postMessage' on 'Worker': Data cannot be cloned, out of memory.\", // Chrome\n  \"Failed to execute 'postMessage' on 'DedicatedWorkerGlobalScope': Data cannot be cloned, out of memory.\", // Firefox\n  'Array buffer allocation failed',\n  'Aborted(). Build with -sASSERTIONS for more info',\n]\n\nconst checkIsKnownErrorOrThrow = (c, { data: error }) => {\n  if (\n    KNOWN_ERRORS.some(knownMessage => error.message?.startsWith(knownMessage))\n  ) {\n    console.warn('Could not update image', error.stack)\n  } else {\n    throw error\n  }\n}\n\nconst sendRenderedImageAssigned = (\n  context,\n  { data: { name, loadedScale } }\n) => {\n  context.service.send({\n    type: 'RENDERED_IMAGE_ASSIGNED',\n    data: name,\n    loadedScale,\n  })\n}\n\nconst sendStartDataUpdate = context => {\n  context.service.send({\n    type: 'START_DATA_UPDATE',\n    name: context.actorName,\n  })\n}\n\nconst sendFinishDataUpdate = context => {\n  context.service.send({\n    type: 'FINISH_DATA_UPDATE',\n    name: context.actorName,\n  })\n}\n\nconst assignHigherErrorCountIfMostCoarse = assign({\n  errorCountAtScale: ({\n    errorCountAtScale,\n    images: { actorContext: actorMap },\n    actorName,\n    targetScale,\n  }) => {\n    const actorContext = actorMap.get(actorName)\n    if (getLoadedImage(actorContext).coarsestScale !== targetScale)\n      return errorCountAtScale\n    return errorCountAtScale + 1\n  },\n})\n\nconst assignResetErrorCount = assign({\n  errorCountAtScale: 0,\n})\n\nconst eventResponses = {\n  IMAGE_ASSIGNED: {\n    target: 'updatingImage',\n    actions: [assignUpdateRenderedNameToSelectedName, assignLoadedScale],\n  },\n  LABEL_IMAGE_ASSIGNED: {\n    target: 'updatingImage',\n    actions: assignUpdateRenderedNameToSelectedName,\n  },\n  UPDATE_RENDERED_IMAGE: {\n    target: 'updatingImage',\n    actions: assignUpdateRenderedName,\n  },\n  TOGGLE_LAYER_VISIBILITY: {\n    actions: 'toggleLayerVisibility',\n  },\n  SET_GRADIENT_OPACITY: {\n    actions: 'applyGradientOpacity',\n  },\n  TOGGLE_IMAGE_INTERPOLATION: {\n    actions: 'toggleInterpolation',\n  },\n  IMAGE_COMPONENT_VISIBILITY_CHANGED: {\n    actions: 'applyComponentVisibility',\n  },\n  IMAGE_PIECEWISE_FUNCTION_CHANGED: {\n    actions: 'applyPiecewiseFunction',\n  },\n  IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED: {\n    actions: 'mapToPiecewiseFunctionNodes',\n  },\n  IMAGE_COLOR_RANGE_CHANGED: {\n    actions: [assignColorRange, 'applyColorRange'],\n  },\n  IMAGE_COLOR_RANGE_MIN_CHANGED: {\n    actions: [assignColorRangeMin, updateColorRangeMin],\n  },\n  IMAGE_COLOR_RANGE_MAX_CHANGED: {\n    actions: [assignColorRangeMax, updateColorRangeMax],\n  },\n  IMAGE_COLOR_RANGE_POINTS_CHANGED: {\n    actions: 'mapToColorFunctionRange',\n  },\n  IMAGE_COLOR_RANGE_BOUNDS_CHANGED: {\n    actions: ['applyColorRangeBounds'],\n  },\n  IMAGE_COLOR_MAP_CHANGED: {\n    actions: 'applyColorMap',\n  },\n  TOGGLE_IMAGE_SHADOW: {\n    actions: 'applyShadow',\n  },\n  IMAGE_GRADIENT_OPACITY_CHANGED: {\n    actions: 'applyGradientOpacity',\n  },\n  IMAGE_GRADIENT_OPACITY_SCALE_CHANGED: {\n    actions: 'applyGradientOpacity',\n  },\n  IMAGE_VOLUME_SAMPLE_DISTANCE_CHANGED: {\n    actions: 'applyVolumeSampleDistance',\n  },\n  IMAGE_BLEND_MODE_CHANGED: {\n    actions: 'applyBlendMode',\n  },\n  UPDATE_IMAGE_HISTOGRAM: {\n    target: 'updatingHistogram',\n  },\n  LABEL_IMAGE_LOOKUP_TABLE_CHANGED: {\n    actions: 'applyLookupTable',\n  },\n  LABEL_IMAGE_BLEND_CHANGED: {\n    actions: 'applyLabelImageBlend',\n  },\n  LABEL_IMAGE_WEIGHTS_CHANGED: {\n    actions: 'applyLabelImageWeights',\n  },\n  LABEL_IMAGE_LABEL_NAMES_CHANGED: {\n    actions: 'applyLabelNames',\n  },\n  LABEL_IMAGE_SELECTED_LABEL_CHANGED: {\n    actions: 'applySelectedLabel',\n  },\n  SET_IMAGE_SCALE: {\n    target: 'updatingImage',\n    actions: assignIsFramerateScalePickingOn,\n  },\n  ADJUST_SCALE_FOR_FRAMERATE: {\n    target: 'updatingImage',\n    actions: assignIsFramerateScalePickingOn,\n  },\n  RENDERED_BOUNDS_CHANGED: {\n    target: 'updatingImage',\n  },\n  SET_CINEMATIC_PARAMETERS: {\n    actions: [assignCinematic, sendCinematicChanged],\n  },\n  CINEMATIC_CHANGED: {\n    actions: 'applyCinematicChanged',\n  },\n  COMPARE_IMAGES: {\n    actions: [assignCompare, sendCompareUpdated, afterCompareMaybeForceUpdate],\n  },\n  ANIMATE_IMAGE_MIX: {\n    actions: applyAnimateImageMix,\n  },\n  TOGGLE_LAYER_BBOX: {\n    actions: 'toggleLayerBBox',\n  },\n}\n\nconst CHANGE_BOUNDS_EVENTS = [\n  'CROPPING_PLANES_CHANGED_BY_USER',\n  'CAMERA_MODIFIED',\n]\n\nconst createUpdatingImageMachine = options => {\n  return createMachine(\n    {\n      id: 'updatingImageMachine',\n      predictableActionArguments: true,\n      initial: 'checkingUpdateNeeded',\n      states: {\n        checkingUpdateNeeded: {\n          always: [\n            { cond: 'isImageUpdateNeeded', target: 'preLoadingImage' },\n            { target: '#updatingImageMachine.loadedImage' },\n          ],\n          exit: assign({ isUpdateForced: false }),\n        },\n\n        preLoadingImage: {\n          entry: sendStartDataUpdate,\n          invoke: {\n            id: 'preLoadingImage',\n            src: async () => {\n              // Give spinner chance to start. Waiting 2 frames works better in cached image case =|\n              await new Promise(requestAnimationFrame)\n              await new Promise(requestAnimationFrame)\n            },\n            onDone: {\n              target: 'loadingImage',\n            },\n          },\n        },\n\n        loadingImage: {\n          invoke: {\n            id: 'updateRenderedImage',\n            src: 'updateRenderedImage',\n            onDone: {\n              target: '#updatingImageMachine.loadedImage',\n              actions: [\n                'assignRenderedImage',\n                assignLoadedScale,\n                assignClearHistograms,\n                cleanColorRanges,\n                'applyRenderedImage',\n                sendRenderedImageAssigned,\n                computeIsCinematicPossible,\n                assignResetErrorCount,\n              ],\n            },\n            onError: {\n              actions: [\n                checkIsKnownErrorOrThrow,\n                assignHigherErrorCountIfMostCoarse,\n                assignCoarserScale,\n              ],\n              target: 'afterError',\n            },\n          },\n        },\n\n        afterError: {\n          entry: sendFinishDataUpdate,\n          always: [\n            {\n              cond: c => c.errorCountAtScale >= 2,\n              actions: () =>\n                console.warn('Too many errors building image. Giving up.'),\n              target: 'finished',\n            },\n            { target: 'checkingUpdateNeeded' },\n          ],\n        },\n\n        loadedImage: {\n          entry: sendFinishDataUpdate,\n          always: [\n            {\n              cond: 'isFramerateScalePickingOn',\n              target: 'checkingFramerate',\n            },\n            {\n              target: 'finished',\n            },\n          ],\n        },\n\n        checkingFramerate: {\n          entry: [c => c.service.send('UPDATE_FPS')],\n          on: {\n            FPS_UPDATED: [\n              {\n                cond: c =>\n                  [isFpsLow, isLoadedScaleMostCoarse].every(cond => cond(c)),\n                target: 'finished', // FPS too slow but nothing to do about it\n              },\n              {\n                cond: isFpsLow,\n                actions: assignCoarserScale, // back off\n                target: 'checkingUpdateNeeded',\n              },\n              {\n                cond: finestScaleOrScaleJustRight,\n                target: 'finished', // found good scale\n              },\n              {\n                actions: assignFinerScale, // try harder\n                target: 'checkingUpdateNeeded',\n              },\n            ],\n          },\n        },\n\n        finished: {\n          type: 'final',\n        },\n      },\n    },\n    options\n  )\n}\n\nconst createImageRenderingActor = (options, context, name) => {\n  const machineContext = { ...context, actorName: name }\n  return createMachine(\n    {\n      id: 'imageRendering',\n      predictableActionArguments: true,\n      context: machineContext,\n      type: 'parallel',\n      states: {\n        imageLoader: {\n          initial: 'idle',\n          states: {\n            idle: {\n              on: {\n                COMPARE_IMAGES: {\n                  actions: [assignCompare, sendCompareUpdated],\n                },\n              },\n              invoke: {\n                id: 'createImageRenderer',\n                src: 'createImageRenderer',\n                onDone: {\n                  target: 'updatingImage',\n                  actions: assignUpdateRenderedNameToSelectedName,\n                },\n              },\n            },\n\n            updatingImage: {\n              on: {\n                ...eventResponses,\n                FPS_UPDATED: {\n                  actions: forwardTo('updatingImageMachine'),\n                },\n                UPDATE_IMAGE_HISTOGRAM: {},\n                RENDERED_BOUNDS_CHANGED: {},\n              },\n              entry: 'assignVisualizedComponents',\n              invoke: {\n                id: 'updatingImageMachine',\n                src: createUpdatingImageMachine(options),\n                data: {\n                  ...machineContext,\n                  hasScaledCoarser: false,\n                  errorCountAtScale: 0,\n                  targetScale: ({ images }, event) => {\n                    if (event.type === 'SET_IMAGE_SCALE')\n                      return event.targetScale\n                    const actorContext = images.actorContext.get(\n                      images.updateRenderedName\n                    )\n                    if (\n                      actorContext.loadedScale ||\n                      actorContext.loadedScale === 0\n                    )\n                      return actorContext.loadedScale\n                    // nothing loaded, start at coarsest\n                    return getLoadedImage(actorContext).coarsestScale\n                  },\n                  isUpdateForced: (c, event) =>\n                    [\n                      'UPDATE_RENDERED_IMAGE',\n                      'IMAGE_ASSIGNED',\n                      'LABEL_IMAGE_ASSIGNED',\n                    ].some(forcedEvent => event.type === forcedEvent),\n                },\n                onDone: [\n                  {\n                    in:\n                      '#imageRendering.imageLoader.updatingImage.noUpdateNeeded',\n                    target: 'updatingHistogram',\n                  },\n                  { target: 'updatingImage' },\n                ],\n              },\n              initial: 'noUpdateNeeded',\n              states: {\n                noUpdateNeeded: { on: { RENDERED_BOUNDS_CHANGED: 'loopback' } },\n                loopback: {},\n              },\n            },\n\n            updatingHistogram: {\n              invoke: {\n                id: 'updateHistogram',\n                src: 'updateHistogram',\n                onDone: {\n                  target: 'active',\n                },\n              },\n              on: {\n                ...eventResponses,\n              },\n            },\n\n            active: {\n              entry: context =>\n                context.service.send({\n                  type: 'IMAGE_RENDERING_ACTIVE',\n                  data: { name: context.images.updateRenderedName },\n                }),\n              on: {\n                ...eventResponses,\n              },\n            },\n          },\n        },\n\n        debouncedImageUpdate: {\n          after: {\n            500: {\n              actions: send('RENDERED_BOUNDS_CHANGED'),\n            },\n          },\n          on: makeTransitions(CHANGE_BOUNDS_EVENTS, 'debouncedImageUpdate'),\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createImageRenderingActor\n"
  },
  {
    "path": "src/Rendering/Images/createImagesRenderingMachine.js",
    "content": "import { Machine, assign, spawn, send, actions } from 'xstate'\nimport { makeTransitions } from './makeTransitions'\n\nimport createImageRenderingActor from './createImageRenderingActor'\n\nfunction spawnImageRenderingActor(options) {\n  return assign({\n    images: (context, event) => {\n      const images = context.images\n      const name = event.data\n      if (!images.imageRenderingActors.has(name)) {\n        images.imageRenderingActors.set(\n          name,\n          spawn(\n            createImageRenderingActor(options, context, name),\n            `imageRenderingActor-${name}`\n          )\n        )\n      } else {\n        const actor = images.imageRenderingActors.get(name)\n        actor.send(event)\n      }\n      return images\n    },\n  })\n}\n\nconst forwardToNamedActor = send((_, e) => e, {\n  to: (c, e) => `imageRenderingActor-${e.name ?? e.data.name}`,\n})\n\nconst sendEventToAllActors = actions.pure(\n  ({ images: { imageRenderingActors } }, event) =>\n    Array.from(imageRenderingActors.values()).map(actor =>\n      send(event, {\n        to: actor,\n      })\n    )\n)\n\nfunction createImagesRenderingMachine(options, context) {\n  const { imageRenderingActor } = options\n\n  return Machine(\n    {\n      id: 'imagesRendering',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          on: {\n            IMAGE_ASSIGNED: {\n              target: 'active',\n              actions: [spawnImageRenderingActor(imageRenderingActor)],\n            },\n            LABEL_IMAGE_ASSIGNED: {\n              target: 'active',\n              actions: [spawnImageRenderingActor(imageRenderingActor)],\n            },\n          },\n        },\n        active: {\n          invoke: {\n            id: 'cameraModifiedWatcher',\n            src: context => send =>\n              context.itkVtkView\n                .getRenderer()\n                .getActiveCamera()\n                .onModified(() => send('CAMERA_MODIFIED')).unsubscribe, // return cleanup func\n          },\n          on: {\n            IMAGE_ASSIGNED: {\n              actions: spawnImageRenderingActor(imageRenderingActor),\n            },\n            LABEL_IMAGE_ASSIGNED: {\n              actions: spawnImageRenderingActor(imageRenderingActor),\n            },\n            SELECT_LAYER: {\n              actions: 'selectImageLayer',\n            },\n            UPDATE_RENDERED_IMAGE: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data.name}`,\n              }),\n            },\n            FPS_UPDATED: {\n              actions: send((_, e) => e, {\n                to: c => `imageRenderingActor-${c.images.updateRenderedName}`,\n              }),\n            },\n            SET_IMAGE_SCALE: {\n              actions: send((_, e) => e, {\n                to: c => `imageRenderingActor-${c.images.updateRenderedName}`,\n              }),\n            },\n            SET_CINEMATIC_PARAMETERS: {\n              actions: send((_, e) => e, {\n                to: c => `imageRenderingActor-${c.images.selectedName}`,\n              }),\n            },\n            CINEMATIC_CHANGED: {\n              actions: send((_, e) => e, {\n                to: c => `imageRenderingActor-${c.images.selectedName}`,\n              }),\n            },\n            TOGGLE_LAYER_VISIBILITY: {\n              actions: send((_, e) => e, {\n                to: c => `imageRenderingActor-${c.images.selectedName}`,\n              }),\n            },\n            TOGGLE_IMAGE_INTERPOLATION: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data}`,\n              }),\n            },\n            IMAGE_COMPONENT_VISIBILITY_CHANGED: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data.name}`,\n              }),\n            },\n            IMAGE_PIECEWISE_FUNCTION_CHANGED: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data.name}`,\n              }),\n            },\n            IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data.name}`,\n              }),\n            },\n            IMAGE_COLOR_RANGE_BOUNDS_CHANGED: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data.name}`,\n              }),\n            },\n            IMAGE_COLOR_RANGE_CHANGED: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data.name}`,\n              }),\n            },\n            IMAGE_COLOR_RANGE_POINTS_CHANGED: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data.name}`,\n              }),\n            },\n            IMAGE_COLOR_MAP_CHANGED: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data.name}`,\n              }),\n            },\n            TOGGLE_IMAGE_SHADOW: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `imageRenderingActor-${e.data}`,\n              }),\n            },\n            DOWNLOAD_IMAGE: {\n              actions: ['downloadImage'],\n            },\n            ...makeTransitions(\n              [\n                'IMAGE_GRADIENT_OPACITY_CHANGED',\n                'IMAGE_GRADIENT_OPACITY_SCALE_CHANGED',\n                'IMAGE_VOLUME_SAMPLE_DISTANCE_CHANGED',\n                'IMAGE_BLEND_MODE_CHANGED',\n                'UPDATE_IMAGE_HISTOGRAM',\n                'LABEL_IMAGE_LOOKUP_TABLE_CHANGED',\n                'LABEL_IMAGE_BLEND_CHANGED',\n                'LABEL_IMAGE_WEIGHTS_CHANGED',\n                'LABEL_IMAGE_SELECTED_LABEL_CHANGED',\n                'LABEL_IMAGE_LABEL_NAMES_CHANGED',\n                'COMPARE_IMAGES',\n                'WINDOW_LEVEL_TOGGLED',\n                'IMAGE_COLOR_RANGE_RESET',\n                'ANIMATE_IMAGE_MIX',\n                'TOGGLE_LAYER_BBOX',\n                'IMAGE_COLOR_RANGE_MIN_CHANGED',\n                'IMAGE_COLOR_RANGE_MAX_CHANGED',\n              ],\n              { actions: forwardToNamedActor }\n            ),\n            ...makeTransitions(\n              ['CROPPING_PLANES_CHANGED_BY_USER', 'CAMERA_MODIFIED'],\n              { actions: sendEventToAllActors }\n            ),\n          },\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createImagesRenderingMachine\n"
  },
  {
    "path": "src/Rendering/Images/makeTransitions.js",
    "content": "export const makeTransitions = (events, transition) =>\n  events.reduce(\n    (onEvents, e) => ({\n      ...onEvents,\n      [e]: transition,\n    }),\n    {}\n  )\n"
  },
  {
    "path": "src/Rendering/Layers/createLayersRenderingMachine.js",
    "content": "import { Machine } from 'xstate'\n\nfunction createLayersRenderingMachine(options, context) {\n  return Machine(\n    {\n      id: 'layersRendering',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          always: {\n            target: 'active',\n          },\n        },\n        active: {},\n      },\n    },\n    options\n  )\n}\n\nexport default createLayersRenderingMachine\n"
  },
  {
    "path": "src/Rendering/Main/backgroundIsDark.js",
    "content": "function backgroundIsDark(context) {\n  const backgroundColor = context.main.backgroundColor\n  const isDark =\n    backgroundColor[0] + backgroundColor[1] + backgroundColor[2] < 1.5\n  return isDark\n}\n\nexport default backgroundIsDark\n"
  },
  {
    "path": "src/Rendering/Main/backgroundIsLight.js",
    "content": "function backgroundIsLight(context, event) {\n  const backgroundColor = context.main.backgroundColor\n  const isLight =\n    backgroundColor[0] + backgroundColor[1] + backgroundColor[2] >= 1.5\n  return isLight\n}\n\nexport default backgroundIsLight\n"
  },
  {
    "path": "src/Rendering/Main/createMainRenderingMachine.js",
    "content": "import { Machine, assign, sendParent, send } from 'xstate'\n\nimport backgroundIsDark from './backgroundIsDark'\nimport backgroundIsLight from './backgroundIsLight'\n\nconst assignFps = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.fps = event.data\n    return main\n  },\n})\n\nconst eventToAxis = {\n  X_SLICE_CHANGED: 'x',\n  Y_SLICE_CHANGED: 'y',\n  Z_SLICE_CHANGED: 'z',\n}\n\nconst assignSlicePosition = assign({\n  main: ({ main }, { type, data: position }) => {\n    main.slicingPlanes[eventToAxis[type]].position = position\n    return main\n  },\n})\n\nfunction createMainRenderingMachine(options, context) {\n  let initialViewMode = 'volume'\n  switch (context.main.viewMode) {\n    case 'XPlane':\n      initialViewMode = 'xPlane'\n      break\n    case 'YPlane':\n      initialViewMode = 'yPlane'\n      break\n    case 'ZPlane':\n      initialViewMode = 'zPlane'\n      break\n    case 'Volume':\n      initialViewMode = 'volume'\n      break\n    default:\n      throw new Error(`Invalid initial view mode: ${context.main.viewMode}`)\n  }\n\n  return Machine(\n    {\n      id: 'main',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          always: {\n            target: 'active',\n          },\n        },\n        active: {\n          entry: ['setBackgroundColor', 'setUnits'],\n          type: 'parallel',\n          on: {\n            TAKE_SCREENSHOT: {\n              actions: 'takeScreenshot',\n            },\n            UPDATE_FPS: {\n              actions: 'updateFps',\n            },\n            FPS_UPDATED: {\n              actions: assignFps,\n            },\n            SET_BACKGROUND_COLOR: {\n              actions: [\n                'setBackgroundColor',\n                send('CHECK_BACKGROUND_CONTRAST'),\n              ],\n            },\n            TOGGLE_BACKGROUND_COLOR: {\n              actions: [\n                'setBackgroundColor',\n                send('CHECK_BACKGROUND_CONTRAST'),\n              ],\n            },\n            SET_UNITS: {\n              actions: 'setUnits',\n            },\n            RESET_CAMERA: {\n              actions: 'resetCamera',\n            },\n            RESET_CROPPING_PLANES: {\n              actions: 'resetCroppingPlanes',\n            },\n            CROPPING_PLANES_CHANGED: {\n              actions: ['applyCroppingPlanes', 'updateSlicingPlanes'],\n            },\n            SLICING_PLANES_CHANGED: {\n              actions: 'applySlicingPlanes',\n            },\n            X_SLICE_CHANGED: {\n              actions: [assignSlicePosition, 'applyXSlice'],\n            },\n            Y_SLICE_CHANGED: {\n              actions: [assignSlicePosition, 'applyYSlice'],\n            },\n            Z_SLICE_CHANGED: {\n              actions: [assignSlicePosition, 'applyZSlice'],\n            },\n          },\n          states: {\n            background: {\n              initial: backgroundIsLight(context) ? 'light' : 'dark',\n              states: {\n                dark: {\n                  entry: [\n                    context => (context.uiDarkMode = true),\n                    sendParent('BACKGROUND_TURNED_DARK'),\n                  ],\n                  on: {\n                    CHECK_BACKGROUND_CONTRAST: {\n                      target: ['light'],\n                      cond: backgroundIsLight,\n                    },\n                  },\n                },\n                light: {\n                  entry: [\n                    context => (context.uiDarkMode = false),\n                    sendParent('BACKGROUND_TURNED_LIGHT'),\n                  ],\n                  on: {\n                    CHECK_BACKGROUND_CONTRAST: {\n                      target: ['dark'],\n                      cond: backgroundIsDark,\n                    },\n                  },\n                },\n              },\n            },\n            annotations: {\n              initial: context.main.annotationsEnabled ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleAnnotations',\n                  on: {\n                    TOGGLE_ANNOTATIONS: 'disabled',\n                  },\n                },\n                disabled: {\n                  entry: 'toggleAnnotations',\n                  on: {\n                    TOGGLE_ANNOTATIONS: 'enabled',\n                  },\n                },\n              },\n            },\n            rotate: {\n              initial: context.main.rotateEnabled ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleRotate',\n                  on: {\n                    TOGGLE_ROTATE: 'disabled',\n                  },\n                },\n                disabled: {\n                  entry: 'toggleRotate',\n                  on: {\n                    TOGGLE_ROTATE: 'enabled',\n                  },\n                },\n              },\n            },\n            axes: {\n              initial: context.main.axesEnabled ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleAxes',\n                  on: {\n                    TOGGLE_AXES: 'disabled',\n                  },\n                },\n                disabled: {\n                  entry: 'toggleAxes',\n                  on: {\n                    TOGGLE_AXES: 'enabled',\n                  },\n                },\n              },\n            },\n            croppingPlanes: {\n              initial: context.main.croppingPlanesEnabled\n                ? 'enabled'\n                : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleCroppingPlanes',\n                  on: {\n                    TOGGLE_CROPPING_PLANES: 'disabled',\n                  },\n                },\n                disabled: {\n                  entry: 'toggleCroppingPlanes',\n                  on: {\n                    TOGGLE_CROPPING_PLANES: 'enabled',\n                  },\n                },\n              },\n            },\n            viewMode: {\n              initial: initialViewMode,\n              states: {\n                xPlane: {\n                  entry: 'viewModeXPlane',\n                },\n                yPlane: {\n                  entry: 'viewModeYPlane',\n                },\n                zPlane: {\n                  entry: 'viewModeZPlane',\n                },\n                volume: {\n                  entry: 'viewModeVolume',\n                },\n              },\n              on: {\n                VIEW_MODE_CHANGED: [\n                  { target: '.xPlane', cond: (c, e) => e.data === 'XPlane' },\n                  { target: '.yPlane', cond: (c, e) => e.data === 'YPlane' },\n                  { target: '.zPlane', cond: (c, e) => e.data === 'ZPlane' },\n                  {\n                    target: '.volume',\n                    cond: (c, e) => e.data === 'Volume',\n                  },\n                ],\n              },\n            },\n          },\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createMainRenderingMachine\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/ComposeImage.worker.js",
    "content": "import registerWebworker from 'webworker-promise/lib/register'\nimport vtkITKHelper from 'vtk.js/Sources/Common/DataModel/ITKHelper'\nimport vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox'\nimport { computeRanges } from '../../../IO/Analyze/computeRanges'\nimport { createRangeHelper } from '../../../IO/Analyze/createRangeHelper'\nimport { createCompareImage } from '../../../IO/Compare/createCompareImage'\nimport {\n  compareImageSpaces,\n  resampleLabelImage,\n} from '../../../IO/ResampleLabelImage/resampleLabelImage'\nimport {\n  composeComponents,\n  parseByComponent,\n  pickAndFuseComponents,\n} from '../../../IO/composeComponents'\n\nimport itkConfig from '../itkConfig.js'\n\nconst checkOverlap = (imageA, imageB) => {\n  const [vtkA, vtkB] = [imageA, imageB].map(vtkITKHelper.convertItkToVtkImage)\n  if (!vtkBoundingBox.intersects(vtkA.getBounds(), vtkB.getBounds())) {\n    console.warn(\n      'Trying to compare images but bounds do not intersect. Moving image will be empty.'\n    )\n  }\n}\n\nconst pickRanges = compInfos =>\n  compInfos\n    .map(({ image: { ranges }, fromComponent }) => ranges?.[fromComponent]) // no ranges in label\n    // if missing any range, return undefined\n    .reduce((ranges, range) => {\n      if (!ranges || !range) return undefined\n      return [...ranges, range]\n    }, [])\n    ?.map(([min, max]) => ({ min, max }))\n\nconst ensureRanges = async image => {\n  const componentInfo = parseByComponent(image)\n  const componentRanges =\n    pickRanges(componentInfo) ??\n    (await computeRanges(image.data, componentInfo.length))\n  image.ranges = componentRanges.map(({ min, max }) => [min, max])\n  return image\n}\n\nconst ensureSameImageSpace = async ({ targetImage, resampleImage }) => {\n  if (!resampleImage || !targetImage) return resampleImage\n\n  if (compareImageSpaces(targetImage, resampleImage)) return resampleImage\n\n  return resampleLabelImage(targetImage, resampleImage)\n}\n\nconst pickIntensityComponents = (image, components) => {\n  // 4+ component and ConglomerateImage processing\n  // fuseLabelImage assumes label is on the last component\n  const withoutLabel = components.filter(componentIndex => componentIndex >= 0)\n  return pickAndFuseComponents({\n    image,\n    components: withoutLabel,\n  })\n}\n\nconst fuseConglomerate = image => {\n  if (!Array.isArray(image)) return image\n  return composeComponents(image)\n}\n\nconst makeCompareImage = async ({ image, fixedImage, options }) => {\n  if (!options.method || options.method === 'disabled') return image\n\n  if (!fixedImage) {\n    console.error('No fixed image')\n    return\n  }\n  const itkImage = await fuseConglomerate(image)\n  const itkFixedImage = await fuseConglomerate(fixedImage)\n\n  // check if there is overlap in physical space.  If none, resample of image to fixedImage will be empty.\n  checkOverlap(itkImage, itkFixedImage)\n\n  const { ranges } = await ensureRanges(itkFixedImage)\n  const rangeHelper = createRangeHelper()\n  ranges.flat().forEach(v => rangeHelper.add(v))\n  const { min, max } = rangeHelper.getRange()\n\n  return createCompareImage(itkImage, itkFixedImage, {\n    minMax: [min, max],\n    ...options,\n  })\n}\n\nconst fuseLabelImage = async (image, labelImage) => {\n  const components = [...Array(image.imageType.components).keys(), -1]\n  const imageWithLabel = await pickAndFuseComponents({\n    image,\n    labelImage,\n    components,\n  })\n  return imageWithLabel\n}\n\nconst configureItkWasm = ({ pipelinesUrl, pipelineWorkerUrl }) => {\n  itkConfig.pipelinesUrl = pipelinesUrl\n  itkConfig.pipelineWorkerUrl = pipelineWorkerUrl\n}\n\nregisterWebworker(\n  async ({\n    image: inImage,\n    labelImage,\n    visualizedComponents,\n    fixedImage,\n    compare,\n    itkWasmConfig,\n  }) => {\n    configureItkWasm(itkWasmConfig)\n    let image = await makeCompareImage({\n      image: inImage,\n      fixedImage,\n      options: compare,\n    })\n    image = await pickIntensityComponents(image, visualizedComponents)\n\n    // Label processing\n    const labelResampled = await ensureSameImageSpace({\n      targetImage: image,\n      resampleImage: labelImage,\n    })\n    image = labelResampled ? await fuseLabelImage(image, labelResampled) : image\n    image = await ensureRanges(image)\n\n    return new registerWebworker.TransferableResponse({ image }, [\n      image.data.buffer,\n    ])\n  }\n)\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyBlendMode.js",
    "content": "function applyBlendMode(context, event) {\n  const name = event.data.name\n  const blendMode = event.data.blendMode\n\n  if (!!context.images.representationProxy) {\n    const volumeMapper = context.images.representationProxy.getMapper()\n    const blendModeLower = blendMode.toLowerCase()\n    switch (blendModeLower) {\n      case 'composite':\n        volumeMapper.setBlendMode(0)\n        break\n      case 'maximum':\n        volumeMapper.setBlendMode(1)\n        break\n      case 'minimum':\n        volumeMapper.setBlendMode(2)\n        break\n      case 'average':\n        volumeMapper.setBlendMode(3)\n        break\n      default:\n        throw new Error(`Invalid blend mode: ${blendMode}`)\n    }\n    context.service.send('RENDER')\n  }\n}\n\nexport default applyBlendMode\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyCinematicChanged.js",
    "content": "import vtkLight from 'vtk.js/Sources/Rendering/Core/Light'\nimport {\n  VOLUME_AMBIENT_DEFAULT,\n  VOLUME_DIFFUSE_DEFAULT,\n} from '../vtk/ItkVtkViewProxy'\n\nexport function applyCinematicChanged(context, { actorContext }) {\n  if (!context.images.representationProxy) return\n\n  const {\n    cinematicParameters: {\n      isCinematicPossible,\n      scatteringBlend,\n      diffuse,\n      ambient,\n    },\n  } = actorContext\n  const renderer = context.itkVtkView.getRenderer()\n  const mapper = context.images.representationProxy.getMapper()\n\n  renderer.removeAllLights()\n\n  const isCinematicOn = isCinematicPossible && scatteringBlend > 0\n\n  if (isCinematicOn) {\n    const light = vtkLight.newInstance()\n    light.setLightTypeToSceneLight()\n    light.setColor(1, 1, 1)\n    light.setIntensity(1)\n    light.setDirection([1, 1, 1])\n    renderer.addLight(light)\n  } else {\n    renderer.createLight() // headlight\n  }\n  renderer.setTwoSidedLighting(!isCinematicOn)\n\n  mapper.setVolumetricScatteringBlending(scatteringBlend)\n\n  const volumeProps = context.images.representationProxy.getVolumes()\n  volumeProps.forEach(volume => {\n    const vProperty = volume.getProperty()\n    if (isCinematicOn) {\n      vProperty.setDiffuse(diffuse)\n      vProperty.setAmbient(ambient)\n    } else {\n      vProperty.setDiffuse(VOLUME_DIFFUSE_DEFAULT)\n      vProperty.setAmbient(VOLUME_AMBIENT_DEFAULT)\n    }\n  })\n\n  context.service.send('RENDER')\n}\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyColorMap.js",
    "content": "import { getColorMap } from 'itk-viewer-color-maps'\n\n// We want an offset so there is contrast with label image colors\nconst COLOR_OFFSET = 146\n\nfunction applyColorMap(context, { data: { name, colorMap, component } }) {\n  const actorContext = context.images.actorContext.get(name)\n\n  // Optional chain on colorTransferFunctions in case compare set in createViewer\n  const colorTransferFunction = context.images.colorTransferFunctions?.get(\n    component\n  )\n\n  // if number of components increased after compare set and applyRenderedImage has not happened yet\n  if (!colorTransferFunction) return\n\n  colorTransferFunction.applyColorMap(\n    getColorMap(colorMap, component + COLOR_OFFSET)\n  )\n  colorTransferFunction.modified() // applyColorMap does not always trigger modified()\n  if (actorContext.colorRanges.has(component)) {\n    const range = actorContext.colorRanges.get(component)\n    colorTransferFunction.setMappingRange(range[0], range[1])\n    colorTransferFunction.updateRange()\n  }\n\n  // update UI\n  context.service.send('IMAGE_COLOR_MAP_DEPENDENCIES_UPDATE', {\n    data: {\n      name,\n      component,\n    },\n  })\n  context.service.send('RENDER')\n}\n\nexport default applyColorMap\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyColorRange.js",
    "content": "function applyColorRange(context, e) {\n  const {\n    data: { component, range },\n  } = e\n  if (!context.images.colorTransferFunctions) {\n    return\n  }\n  const colorTransferFunction = context.images.colorTransferFunctions.get(\n    component\n  )\n  colorTransferFunction.setMappingRange(range[0], range[1])\n  colorTransferFunction.updateRange()\n\n  context.service.send('RENDER')\n}\n\nexport default applyColorRange\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyColorRangeBounds.js",
    "content": "const assignColorRangeBounds = (\n  { images },\n  { data: { name, component, range, keepAutoAdjusting = false } }\n) => {\n  const {\n    colorRangeBounds,\n    colorRangeBoundsAutoAdjust,\n  } = images.actorContext.get(name)\n\n  colorRangeBounds.set(component, range)\n\n  colorRangeBoundsAutoAdjust.set(\n    component,\n    colorRangeBoundsAutoAdjust.get(component) && keepAutoAdjusting\n  )\n\n  return images\n}\n\nexport const applyColorRangeBounds = (context, event) => {\n  assignColorRangeBounds(context, event)\n}\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyComponentVisibility.js",
    "content": "import { applyComponentWeights } from './applyComponentWeights'\n\nfunction applyComponentVisibility(context, event) {\n  const name = event.data.name\n  const index = event.data.component\n  const visibility = event.data.visibility\n\n  const actorContext = context.images.actorContext.get(name)\n  const componentVisibilities = actorContext.componentVisibilities\n  const visualizedComponents = actorContext.visualizedComponents\n\n  if (visibility && visualizedComponents.indexOf(index) < 0) {\n    // add component to visualizedComponents\n    visualizedComponents.push(index)\n    for (let i = 0; i < visualizedComponents.length; i++) {\n      if (!componentVisibilities[visualizedComponents[i]]) {\n        visualizedComponents.splice(i, 1)\n        break\n      }\n    }\n    context.service.send({ type: 'UPDATE_RENDERED_IMAGE', data: { name } })\n  }\n\n  applyComponentWeights(context, name)\n}\n\nexport default applyComponentVisibility\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyComponentWeights.js",
    "content": "export function applyComponentWeights(context, name) {\n  const actorContext = context.images.actorContext.get(name)\n\n  const { labelImageBlend } = actorContext\n\n  if (context.images.representationProxy) {\n    const volume = context.images.representationProxy.getVolumes()[0]\n    const volumeProperty = volume.getProperty()\n    const sliceActor = context.images.representationProxy.getActors()[0]\n    const sliceProperty = sliceActor.getProperty()\n\n    const visualizedComponents = actorContext.visualizedComponents\n    const componentVisibilities = actorContext.componentVisibilities\n    const weight = 1.0\n\n    visualizedComponents.forEach((componentIdx, fusedImgIdx) => {\n      let compWeight = componentVisibilities[componentIdx] ? weight : 0\n      if (componentIdx < 0) {\n        compWeight = labelImageBlend\n      }\n      volumeProperty.setComponentWeight(fusedImgIdx, compWeight)\n      sliceProperty.setComponentWeight(fusedImgIdx, compWeight)\n    })\n\n    context.service.send('RENDER')\n  }\n}\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyGradientOpacity.js",
    "content": "function applyGradientOpacity(context, event) {\n  const name = event.data.name\n\n  const actorContext = context.images.actorContext.get(name)\n  const gradientOpacity = actorContext.gradientOpacity\n  const gradientOpacityScale = actorContext.gradientOpacityScale\n  const visualizedComponents = actorContext.visualizedComponents\n\n  if (!!context.images.representationProxy) {\n    const dataArray = context.images.representationProxy.getDataArray()\n    const volume = context.images.representationProxy.getVolumes()[0]\n    if (gradientOpacity === 0) {\n      visualizedComponents.forEach((componentIdx, fusedImgIdx) => {\n        componentIdx >= 0 &&\n          volume.getProperty().setUseGradientOpacity(fusedImgIdx, false)\n      })\n    } else {\n      visualizedComponents.forEach((componentIdx, fusedImgIdx) => {\n        if (componentIdx < 0) {\n          return\n        }\n        const dataRange = dataArray.getRange(componentIdx)\n        volume.getProperty().setUseGradientOpacity(fusedImgIdx, true)\n        const minV = Math.max(0.0, gradientOpacity - 0.3) / 0.7\n        if (minV > 0.0) {\n          volume\n            .getProperty()\n            .setGradientOpacityMinimumValue(\n              fusedImgIdx,\n              Math.exp(\n                Math.log((dataRange[1] - dataRange[0]) * 0.2) *\n                  7 *\n                  gradientOpacityScale *\n                  minV *\n                  minV\n              )\n            )\n        } else {\n          volume.getProperty().setGradientOpacityMinimumValue(fusedImgIdx, 0.0)\n        }\n        volume\n          .getProperty()\n          .setGradientOpacityMaximumValue(\n            fusedImgIdx,\n            Math.exp(\n              Math.log((dataRange[1] - dataRange[0]) * 1.0) *\n                7 *\n                gradientOpacityScale *\n                gradientOpacity *\n                gradientOpacity\n            )\n          )\n      })\n    }\n    context.service.send('RENDER')\n  }\n}\n\nexport default applyGradientOpacity\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyIndependentComponents.js",
    "content": "function applyIndependentComponents(context) {\n  const name = context.images.selectedName\n  const actorContext = context.images.actorContext.get(name)\n  const independentComponents = actorContext.independentComponents\n  if (!!context.images.representationProxy) {\n    const sliceActors = context.images.representationProxy.getActors()\n    sliceActors.forEach((actor, actorIdx) => {\n      const actorProp = actor.getProperty()\n      actorProp.setIndependentComponents(independentComponents)\n    })\n  }\n}\n\nexport default applyIndependentComponents\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyLabelImageBlend.js",
    "content": "import { applyComponentWeights } from './applyComponentWeights'\n\nfunction applyLabelImageBlend(context, event) {\n  applyComponentWeights(context, event.data.name)\n}\n\nexport default applyLabelImageBlend\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyLabelImageWeights.js",
    "content": "import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction'\n\nimport transformLabelImageWeight from './transformLabelImageWeight'\n\nfunction applyLabelImageWeights(context, event) {\n  const name = event.data.name\n  const actorContext = context.images.actorContext.get(name)\n  const labelImageWeights = actorContext.labelImageWeights\n\n  let piecewiseFunction = null\n  if (!context.images.piecewiseFunctions.has('labelImage')) {\n    piecewiseFunction = vtkPiecewiseFunction.newInstance()\n    context.images.piecewiseFunctions.set('labelImage', piecewiseFunction)\n  } else {\n    piecewiseFunction = context.images.piecewiseFunctions.get('labelImage')\n  }\n\n  const haveBackground =\n    labelImageWeights.keys().next().value === 0 ? true : false\n  let minLabelWeight = 0.0\n  let maxLabelWeight = 1.0\n  if (!actorContext.image) {\n    maxLabelWeight = 0.05\n    if (context.main.viewMode !== 'Volume') {\n      maxLabelWeight = 1.0\n      minLabelWeight = 0.4\n    }\n  }\n\n  piecewiseFunction.removeAllPoints()\n\n  const weightIter = labelImageWeights.entries()\n  let entry = weightIter.next()\n  if (haveBackground) {\n    piecewiseFunction.addPointLong(0, 0.0, 0.5, 1.0)\n  } else {\n    piecewiseFunction.addPointLong(\n      entry.value[0],\n      transformLabelImageWeight(entry.value[1], minLabelWeight, maxLabelWeight),\n      0.5,\n      1.0\n    )\n  }\n\n  while (!entry.done) {\n    piecewiseFunction.addPointLong(\n      entry.value[0],\n      transformLabelImageWeight(entry.value[1], minLabelWeight, maxLabelWeight),\n      0.5,\n      1.0\n    )\n    entry = weightIter.next()\n  }\n\n  const volume = context.images.representationProxy.getVolumes()[0]\n  const volumeProperty = volume.getProperty()\n\n  const component = actorContext.visualizedComponents.length - 1\n  volumeProperty.setScalarOpacity(component, piecewiseFunction)\n\n  // The slice shows the same piecewise function as the volume for label map\n  const sliceActors = context.images.representationProxy.getActors()\n  sliceActors.forEach(actor => {\n    const actorProp = actor.getProperty()\n    actorProp.setPiecewiseFunction(component, piecewiseFunction)\n  })\n\n  context.service.send('RENDER')\n}\n\nexport default applyLabelImageWeights\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyLabelNames.js",
    "content": "function applyLabelNames(context, event) {\n  const name = event.data.name\n  const labelNames = event.data.labelNames\n\n  context.itkVtkView.setLabelNames(labelNames)\n}\n\nexport default applyLabelNames\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyLookupTable.js",
    "content": "import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction'\nimport { OpacityMode } from 'vtk.js/Sources/Rendering/Core/VolumeProperty/Constants'\n\nimport applyCategoricalColorToColorTransferFunction from '../../../UI/reference-ui/src/applyCategoricalColorToColorTransferFunction'\n\nfunction applyLookupTable(context, event) {\n  const name = event.data.name\n  const actorContext = context.images.actorContext.get(name)\n\n  const lookupTable = event.data.lookupTable\n\n  let colorTransferFunction = null\n  if (context.images.colorTransferFunctions.has('labelImage')) {\n    colorTransferFunction = context.images.colorTransferFunctions.get(\n      'labelImage'\n    )\n  } else {\n    colorTransferFunction = vtkColorTransferFunction.newInstance()\n    context.images.colorTransferFunctions.set(\n      'labelImage',\n      colorTransferFunction\n    )\n  }\n\n  // wait for assignRenderedImage which computes uniqueLabels, then applyRenderedImage calls applyLookupTable\n  if (!actorContext.uniqueLabels) return\n\n  const uniqueLabels = Array.from(actorContext.uniqueLabels)\n\n  applyCategoricalColorToColorTransferFunction(\n    colorTransferFunction,\n    uniqueLabels,\n    lookupTable\n  )\n\n  const volume = context.images.representationProxy.getVolumes()[0]\n  const volumeProperty = volume.getProperty()\n\n  const component = actorContext.visualizedComponents.length - 1\n  volumeProperty.setRGBTransferFunction(component, colorTransferFunction)\n  volumeProperty.setIndependentComponents(true)\n  volumeProperty.setOpacityMode(component, OpacityMode.PROPORTIONAL)\n\n  // The slice shows the same lut as the volume for label map\n  const sliceActors = context.images.representationProxy.getActors()\n  sliceActors.forEach(actor => {\n    const actorProp = actor.getProperty()\n    actorProp.setIndependentComponents(true)\n    actorProp.setRGBTransferFunction(component, colorTransferFunction)\n  })\n\n  context.service.send('RENDER')\n}\n\nexport default applyLookupTable\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyPiecewiseFunction.js",
    "content": "function applyPiecewiseFunction(context, event) {\n  const name = event.data.name\n  const component = event.data.component\n  // const range = event.data.range\n  const nodes = event.data.nodes\n\n  const actorContext = context.images.actorContext.get(name)\n  const image = actorContext.image\n\n  const pwf = context.images.piecewiseFunctions?.get(component)\n  if (pwf && image) {\n    const slicePiecewiseFunction = pwf.slice\n    const volumePiecewiseFunction = pwf.volume\n\n    volumePiecewiseFunction.setNodes(nodes)\n\n    const sliceNodes = nodes.length > 2 ? nodes.slice(1, -1) : nodes // if more than 2, remove \"window\" nodes with y = 0\n    slicePiecewiseFunction.setNodes(sliceNodes)\n\n    context.service.send('RENDER')\n  }\n}\n\nexport default applyPiecewiseFunction\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyRenderedImage.js",
    "content": "import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction'\nimport vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction'\nimport { OpacityMode } from 'vtk.js/Sources/Rendering/Core/VolumeProperty/Constants'\n\nimport applyGradientOpacity from './applyGradientOpacity'\nimport applyLabelImageBlend from './applyLabelImageBlend'\nimport applyVolumeSampleDistance from './applyVolumeSampleDistance'\nimport {\n  makeCroppable,\n  updateCroppingParametersFromImage,\n} from '../Main/croppingPlanes'\nimport applyLookupTable from './applyLookupTable'\nimport toggleInterpolation from './toggleInterpolation'\n\nconst ANNOTATION_DEFAULT =\n  '<table style=\"margin-left: 0;\"><tr><td style=\"margin-left: auto; margin-right: 0;\">Index:</td><td>${iIndex},</td><td>${jIndex},</td><td>${kIndex}</td></tr><tr><td style=\"margin-left: auto; margin-right: 0;\">Position:</td><td>${xPosition},</td><td>${yPosition},</td><td>${zPosition}</td></tr><tr><td style=\"margin-left: auto; margin-right: 0;\"\">Value:</td><td style=\"text-align:center;\" colspan=\"3\">${value}</td></tr><tr ${annotationLabelStyle}><td style=\"margin-left: auto; margin-right: 0;\">Label:</td><td style=\"text-align:center;\" colspan=\"3\">${annotation}</td></tr></table>'\nconst ANNOTATION_CUSTOM_PREFIX =\n  '<table style=\"margin-left: 0;\"><tr><td style=\"margin-left: auto; margin-right: 0;\">Scale:</td>'\nconst ANNOTATION_CUSTOM_POSTFIX =\n  '<td></td><td></td></tr><tr><td style=\"margin-left: auto; margin-right: 0;\">Position:</td><td>${xPosition},</td><td>${yPosition},</td><td>${zPosition}</td></tr><tr><td style=\"margin-left: auto; margin-right: 0;\"\">Value:</td><td style=\"text-align:center;\" colspan=\"3\">${value}</td></tr><tr ${annotationLabelStyle}><td style=\"margin-left: auto; margin-right: 0;\">Label:</td><td style=\"text-align:center;\" colspan=\"3\">${annotation}</td></tr></table>'\n\nconst getDefaultRangeByDataType = dataType => {\n  const range = []\n  switch (dataType) {\n    case 'Uint8Array':\n      range[0] = 0\n      range[1] = 255\n      break\n    case 'Int8Array':\n      range[0] = -128\n      range[1] = 127\n      break\n    case 'Uint16Array':\n      range[0] = 0\n      range[1] = 65535\n      break\n    case 'Int16Array':\n      range[0] = -32768\n      range[1] = 32767\n      break\n    case 'Uint32Array':\n      range[0] = 0\n      range[1] = 4294967295\n      break\n    case 'Int32Array':\n      range[0] = -2147483648\n      range[1] = 2147483647\n      break\n    case 'BigInt64Array':\n      range[0] = BigInt(-9223372036854775808)\n      range[1] = BigInt(9223372036854775808)\n      break\n    case 'Float32Array':\n      range[0] = 0.0\n      range[1] = 1.0\n      break\n    default:\n      console.error('Unsupported data type')\n  }\n  return range\n}\n\nfunction applyRenderedImage(context, { data: { name } }) {\n  const actorContext = context.images.actorContext.get(name)\n\n  if (!actorContext.fusedImage) {\n    return\n  }\n\n  const image = actorContext.image\n  const labelImage = actorContext.labelImage\n\n  const labelImageComponentFactor = labelImage ? -1 : 0\n\n  // component count minus label image\n  const numberOfComponents = actorContext.fusedImage\n    ? actorContext.fusedImage\n        .getPointData()\n        .getScalars()\n        .getNumberOfComponents() + labelImageComponentFactor\n    : 0\n\n  context.images.source.setInputData(actorContext.fusedImage)\n\n  // VTK.js currently only supports a single image\n  if (!context.images.representationProxy) {\n    context.proxyManager.createRepresentationInAllViews(context.images.source)\n    context.images.representationProxy = context.proxyManager.getRepresentation(\n      context.images.source,\n      context.itkVtkView\n    )\n    const { representationProxy } = context.images\n\n    makeCroppable(context, representationProxy)\n\n    if (context.use2D) {\n      context.itkVtkView.setViewMode('ZPlane')\n      context.itkVtkView.setOrientationAxesVisibility(false)\n    } else {\n      context.itkVtkView.setViewMode('Volume')\n    }\n\n    context.itkVtkView.setAxesNames(image?.scaleInfo[0].axesNames) // ? for no image, only imageLabel case\n\n    const annotationContainer = context.renderingViewContainers\n      .get('volume')\n      .querySelector('.js-se')\n    annotationContainer.style.fontFamily = 'monospace'\n\n    toggleInterpolation(context, { data: name })\n\n    const { widgetCroppingPlanes } = context.main\n    const sliceActors = representationProxy.getActors()\n    sliceActors.forEach((actor, actorIdx) => {\n      const sliceMapper = actor.getMapper()\n      switch (actorIdx) {\n        case 0:\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[2])\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[3])\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[4])\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[5])\n          break\n        case 1:\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[0])\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[1])\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[4])\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[5])\n          break\n        case 2:\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[0])\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[1])\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[2])\n          sliceMapper.addClippingPlane(widgetCroppingPlanes[3])\n          break\n        default:\n          console.error('Unexpected slice actor')\n      }\n    })\n  } else {\n    context.images.representationProxy.setInput(context.images.source)\n  }\n  const { representationProxy } = context.images\n\n  // undo representationProxy.setInput calling volume.setVisibility(false) if it finds dimensions === 2 (may have just been cropped)\n  representationProxy.setVolumeVisibility(\n    !context.use2D && context.main.viewMode === 'Volume'\n  )\n\n  // triggers update of ImageSliceOutlines if fusedImage size changed\n  representationProxy.getActors().forEach(actor => actor.getMapper().modified())\n\n  // Create color map and piecewise function objects as needed\n  if (typeof context.images.colorTransferFunctions === 'undefined') {\n    context.images.colorTransferFunctions = new Map()\n  }\n  if (typeof context.images.piecewiseFunctions === 'undefined') {\n    context.images.piecewiseFunctions = new Map()\n  }\n\n  // Create color map and piecewise function objects as needed\n  for (let component = 0; component < numberOfComponents; component++) {\n    const colorTransferFunction =\n      context.images.colorTransferFunctions.get(component) ??\n      vtkColorTransferFunction.newInstance()\n\n    context.images.colorTransferFunctions.set(component, colorTransferFunction)\n\n    if (!context.images.piecewiseFunctions.has(component)) {\n      const piecewiseFunction = {\n        slice: vtkPiecewiseFunction.newInstance(),\n        volume: vtkPiecewiseFunction.newInstance(),\n      }\n      context.images.piecewiseFunctions.set(component, piecewiseFunction)\n    }\n    // Compare may have increased number of components.\n    //  send({ type: 'IMAGE_COLOR_MAP_CHANGED' }) called below after representations updated\n  }\n\n  // Visualized components may have updated -> set color transfer function, piecewise function, component visibility, independent components in slices\n  const sliceActors = context.images.representationProxy.getActors()\n  sliceActors.forEach(actor => {\n    const actorProperty = actor.getProperty()\n    actorProperty.setIndependentComponents(actorContext.independentComponents)\n    actor.getMapper().setInputData(actorContext.fusedImage)\n\n    actorContext.visualizedComponents\n      .filter(componentIndex => componentIndex >= 0) // skip label map\n      .forEach((componentIndex, fusedImageIndex) => {\n        const colorTransferFunction = context.images.colorTransferFunctions.get(\n          componentIndex\n        )\n        actorProperty.setRGBTransferFunction(\n          fusedImageIndex,\n          colorTransferFunction\n        )\n        const piecewiseFunction = context.images.piecewiseFunctions.get(\n          componentIndex\n        ).slice\n        actorProperty.setPiecewiseFunction(fusedImageIndex, piecewiseFunction)\n\n        const componentVisibility =\n          actorContext.componentVisibilities[componentIndex]\n        actorProperty.setComponentWeight(\n          fusedImageIndex,\n          componentVisibility ? 1.0 : 0.0\n        )\n        actorProperty.setUseLookupTableScalarRange(true)\n      })\n  })\n\n  // Visualized components may have updated -> set color transfer function, piecewise function, component visibility, independent components in volumes\n  const volumeProps = context.images.representationProxy.getVolumes()\n  volumeProps.forEach(volume => {\n    const volumeProperty = volume.getProperty()\n    volume.getMapper().setInputData(actorContext.fusedImage)\n\n    volumeProperty.setIndependentComponents(actorContext.independentComponents)\n\n    let componentsVisible = false\n\n    actorContext.visualizedComponents.forEach(\n      (componentIndex, fusedImageIndex) => {\n        // Set for intensity and label map components.  Components count may have changed.\n        const mode =\n          componentIndex < 0 ? OpacityMode.PROPORTIONAL : OpacityMode.FRACTIONAL\n        volumeProperty.setOpacityMode(fusedImageIndex, mode)\n\n        if (!context.images.colorTransferFunctions.has(componentIndex)) {\n          return\n        }\n        const colorTransferFunction = context.images.colorTransferFunctions.get(\n          componentIndex\n        )\n        const piecewiseFunction = context.images.piecewiseFunctions.get(\n          componentIndex\n        ).volume\n        volumeProperty.setScalarOpacity(fusedImageIndex, piecewiseFunction)\n        volumeProperty.setRGBTransferFunction(\n          fusedImageIndex,\n          colorTransferFunction\n        )\n\n        const componentVisibility =\n          actorContext.componentVisibilities[componentIndex]\n        componentsVisible = componentVisibility ? true : componentsVisible\n        volumeProperty.setComponentWeight(\n          fusedImageIndex,\n          componentVisibility ? 1.0 : 0.0\n        )\n      }\n    )\n  })\n\n  // Todo: results in necessary side-effect?\n  applyGradientOpacity(context, {\n    data: { name, gradientOpacity: actorContext.gradientOpacity },\n  })\n  applyVolumeSampleDistance(context, {\n    data: { name, volumeSampleDistance: actorContext.volumeSampleDistance },\n  })\n\n  representationProxy.getMapper().setMaximumSamplesPerRay(2814)\n\n  // update color ranges\n  actorContext.visualizedComponents\n    .map((componentIndex, fusedImageIndex) => [componentIndex, fusedImageIndex])\n    .filter(([componentIndex]) => componentIndex >= 0) // skip label map\n    .forEach(([componentIndex, fusedImageIndex]) => {\n      const {\n        colorRangeBoundsAutoAdjust,\n        colorRangeBounds,\n        colorRanges,\n        colorRangeMinAutoAdjust,\n        colorRangeMaxAutoAdjust,\n      } = actorContext\n\n      const dataArray = actorContext.fusedImage.getPointData().getScalars()\n      const [dataMin, dataMax] = dataArray.getRange(fusedImageIndex)\n\n      const [newMin, newMax] =\n        !actorContext.independentComponents || dataMin - dataMax === 0\n          ? getDefaultRangeByDataType(dataArray.getDataType())\n          : [dataMin, dataMax]\n\n      const storedColorRange = colorRanges.get(componentIndex)\n      const minAutoAdjust = colorRangeMinAutoAdjust.get(componentIndex)\n      const maxAutoAdjust = colorRangeMaxAutoAdjust.get(componentIndex)\n      if (minAutoAdjust || maxAutoAdjust || !storedColorRange) {\n        const fullRange = actorContext.colorRangeBounds.get(componentIndex) ?? [\n          0,\n          1,\n        ]\n        const range = storedColorRange ?? [0.2, 0.8]\n        // rescale to new range\n        const diff = fullRange[1] - fullRange[0]\n        const colorRangeNormalized = [\n          (range[0] - fullRange[0]) / diff,\n          (range[1] - fullRange[0]) / diff,\n        ]\n        const newDelta = newMax - newMin\n        const newRange = colorRangeNormalized.map(x => {\n          return x * newDelta + newMin\n        })\n\n        if (!minAutoAdjust) newRange[0] = range[0]\n        if (!maxAutoAdjust) newRange[1] = range[1]\n\n        context.service.send({\n          type: 'IMAGE_COLOR_RANGE_CHANGED',\n          data: {\n            name,\n            component: componentIndex,\n            range: newRange,\n            keepAutoAdjusting: true,\n          },\n        })\n      }\n\n      if (colorRangeBoundsAutoAdjust.get(componentIndex)) {\n        const oldRange = colorRangeBounds.get(componentIndex) ?? [\n          Number.POSITIVE_INFINITY,\n          Number.NEGATIVE_INFINITY,\n        ]\n        // only grow range\n        const newRange = [\n          Math.min(newMin, oldRange[0]),\n          Math.max(newMax, oldRange[1]),\n        ]\n        const hasChanged = newRange.some((value, i) => value !== oldRange[i])\n        if (hasChanged) {\n          context.service.send({\n            type: 'IMAGE_COLOR_RANGE_BOUNDS_CHANGED',\n            data: {\n              name,\n              component: componentIndex,\n              range: newRange,\n              keepAutoAdjusting: true,\n            },\n          })\n        }\n      }\n    })\n\n  if (labelImage) {\n    const uniqueLabels = actorContext.uniqueLabels\n\n    const labelNames = actorContext.labelNames\n    let labelNameAdded = false\n    const labelImageWeights = actorContext.labelImageWeights\n    let labelImageWeightAdded = false\n    for (let index = 0; index < uniqueLabels.length; index++) {\n      const label = uniqueLabels[index]\n      if (!labelNames.has(label)) {\n        labelNames.set(label, label.toString())\n        labelNameAdded = true\n      }\n      if (!labelImageWeights.has(label)) {\n        // 0 is usually the background label -- suppress it\n        label === 0\n          ? labelImageWeights.set(label, 0.0)\n          : labelImageWeights.set(label, 1.0)\n        labelImageWeightAdded = true\n      }\n    }\n    if (labelNameAdded) {\n      context.service.send({\n        type: 'LABEL_IMAGE_LABEL_NAMES_CHANGED',\n        data: { name, labelNames },\n      })\n    }\n    if (labelImageWeightAdded) {\n      context.service.send({\n        type: 'LABEL_IMAGE_WEIGHTS_CHANGED',\n        data: { name, labelImageWeights },\n      })\n      context.service.send({\n        type: 'LABEL_IMAGE_LOOKUP_TABLE_CHANGED',\n        data: { name, lookupTable: actorContext.lookupTable },\n      })\n    }\n\n    // Always call if component count changes.\n    // Apply synchronously to avoid error on render in use2D=true case.\n    applyLookupTable(context, {\n      data: { name, lookupTable: actorContext.lookupTable },\n    })\n\n    applyLabelImageBlend(context, {\n      data: { name, labelImageBlend: actorContext.labelImageBlend },\n    })\n  }\n\n  // Call after representations have been updated with possibly more or less components.\n  // IMAGE_COLOR_MAP_CHANGED triggers a render which errors if a slice representation is missing a transfer function for a component\n  for (let component = 0; component < numberOfComponents; component++) {\n    const colorMap = actorContext.colorMaps.get(component)\n    context.service.send({\n      type: 'IMAGE_COLOR_MAP_CHANGED',\n      data: { name, component, colorMap },\n    })\n\n    // Update piecewise function nodes after we have data range\n    // Without this piecewise functions are never \"applied\"\n    const points = context.images.actorContext\n      .get(name)\n      .piecewiseFunctionPoints.get(component)\n    context.service.send({\n      type: 'IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED',\n      data: { name, component, points },\n    })\n  }\n\n  // call after representations are created\n  updateCroppingParametersFromImage(context, actorContext.fusedImage)\n  if (actorContext.image) {\n    context.itkVtkView.updateLabelBoundingBox(\n      name,\n      actorContext.image.getWorldBounds(actorContext.loadedScale)\n    )\n  }\n  if (actorContext.labelImage) {\n    context.itkVtkView.updateLabelBoundingBox(\n      actorContext.labelImageName,\n      actorContext.labelImage.getWorldBounds(actorContext.loadedScale)\n    )\n  }\n\n  const loadedImage = actorContext.image ?? actorContext.labelImage\n  const hasOneScale = loadedImage.scaleInfo.length === 1\n  if (context.itkVtkView.setSeCornerAnnotation) {\n    if (hasOneScale) {\n      context.itkVtkView.setSeCornerAnnotation(ANNOTATION_DEFAULT)\n    } else {\n      context.itkVtkView.setSeCornerAnnotation(\n        `${ANNOTATION_CUSTOM_PREFIX}<td style=\"margin-left: 0; margin-right: auto;\">${actorContext.loadedScale}</td>${ANNOTATION_CUSTOM_POSTFIX}`\n      )\n    }\n  }\n}\n\nexport default applyRenderedImage\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applySelectedLabel.js",
    "content": "function applySelectedLabel(context, event) {}\n\nexport default applySelectedLabel\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyShadow.js",
    "content": "function applyShadow(context, event) {\n  const name = event.data\n  const actorContext = context.images.actorContext.get(name)\n  const useShadow = actorContext.shadowEnabled\n\n  if (!!context.images.representationProxy) {\n    context.images.representationProxy.setUseShadow(useShadow)\n    context.service.send('RENDER')\n  }\n}\n\nexport default applyShadow\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/applyVolumeSampleDistance.js",
    "content": "function applyVolumeSampleDistance(context, event) {\n  if (context.images.representationProxy) {\n    const { volumeSampleDistance } = event.data\n    context.images.representationProxy.setSampleDistance(volumeSampleDistance)\n    const sourceDS = context.images.representationProxy.getInputDataSet()\n    const sampleDistance =\n      0.7 *\n      Math.sqrt(\n        sourceDS\n          .getSpacing()\n          .map(v => v * v)\n          .reduce((a, b) => a + b, 0)\n      )\n    context.images.representationProxy\n      .getMapper()\n      .setSampleDistance(\n        sampleDistance * 2 ** (volumeSampleDistance * 3.0 - 1.5)\n      )\n    context.service.send('RENDER')\n  }\n}\n\nexport default applyVolumeSampleDistance\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/assignRenderedImage.js",
    "content": "import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray'\nimport { assign } from 'xstate'\nimport numericalSort from '../numericalSort'\n\nconst updateContextWithLabelImage = (actorContext, scaleLabelImage) => {\n  const uniqueLabelsSet = new Set(scaleLabelImage.data)\n  const uniqueLabels = Array.from(uniqueLabelsSet)\n  // The volume mapper currently only supports ColorTransferFunction's,\n  // not LookupTable's\n  // lut.setAnnotations(uniqueLabels, uniqueLabels);\n  uniqueLabels.sort(numericalSort)\n  actorContext.uniqueLabels = uniqueLabels\n  actorContext.renderedLabelImage = scaleLabelImage\n}\n\nconst assignRenderedImage = assign({\n  images: (\n    { images },\n    { data: { name, componentRanges, itkImage, vtkImage, labelAtScale } }\n  ) => {\n    const actorContext = images.actorContext.get(name)\n\n    if (labelAtScale) updateContextWithLabelImage(actorContext, labelAtScale)\n\n    if (actorContext.fusedImage) {\n      // re-use fusedImage\n      actorContext.fusedImage.setOrigin(vtkImage.getOrigin())\n      actorContext.fusedImage.setSpacing(vtkImage.getSpacing())\n      actorContext.fusedImage.setDirection(vtkImage.getDirection())\n      actorContext.fusedImage.setDimensions(vtkImage.getDimensions())\n    } else {\n      actorContext.fusedImage = vtkImage\n    }\n    const { fusedImage } = actorContext\n\n    // for areBoundsBigger guard\n    actorContext.loadedBounds = fusedImage.getBounds()\n\n    actorContext.fusedImageData = itkImage.data\n    const imageScalars = vtkImage.getPointData().getScalars()\n\n    const numberOfComponents = itkImage.imageType.components\n    const fusedImageScalars = vtkDataArray.newInstance({\n      name: imageScalars.getName() || 'Scalars',\n      values: actorContext.fusedImageData,\n      numberOfComponents,\n    })\n\n    fusedImage.getPointData().setScalars(fusedImageScalars)\n\n    componentRanges.forEach((range, comp) =>\n      fusedImageScalars.setRange(range, comp)\n    )\n\n    // Keeps ProxyRepresentation's call of fusedImageScalars.getRange() from slow computation of \"magnitude\" combination of components\n    // We don't use.\n    fusedImageScalars.setRange({ min: 0, max: 1 }, numberOfComponents)\n\n    // Trigger VolumeMapper scalarTexture update\n    fusedImage.modified()\n\n    return images\n  },\n})\n\nexport default assignRenderedImage\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/assignVisualizedComponents.js",
    "content": "import { assign } from 'xstate'\nimport { getOutputIntensityComponentCount } from '../../Images/createImageRenderingActor'\n\nconst assignVisualizedComponents = assign({\n  images: context => {\n    const name = context.actorName\n    const actorContext = context.images.actorContext.get(name)\n    const { image, labelImage, editorLabelImage } = actorContext\n    if (image) {\n      const imageComponents = getOutputIntensityComponentCount(actorContext)\n      actorContext.visualizedComponents = Array(imageComponents)\n        .fill(0)\n        .map((_, idx) => idx)\n        .filter(i => actorContext.componentVisibilities[i])\n\n      actorContext.visualizedComponents = actorContext.visualizedComponents.slice(\n        0,\n        getOutputIntensityComponentCount(actorContext)\n      )\n\n      actorContext.maxIntensityComponents = 4\n      if (labelImage) {\n        actorContext.maxIntensityComponents -= 1\n      }\n      if (editorLabelImage) {\n        actorContext.maxIntensityComponents -= 1\n      }\n\n      const numVizComps = Math.min(\n        actorContext.visualizedComponents.length,\n        actorContext.maxIntensityComponents\n      )\n      if (actorContext.visualizedComponents.length > numVizComps) {\n        // turn off unrenderable components\n        actorContext.visualizedComponents = actorContext.visualizedComponents.slice(\n          0,\n          numVizComps\n        )\n        const offComps = [...Array(imageComponents).keys()].filter(\n          comp => !actorContext.visualizedComponents.includes(comp)\n        )\n        offComps.forEach(comp =>\n          context.service.send({\n            type: 'IMAGE_COMPONENT_VISIBILITY_CHANGED',\n            data: { name, component: comp, visibility: false },\n          })\n        )\n      }\n    }\n\n    if (labelImage) {\n      actorContext.visualizedComponents =\n        actorContext.visualizedComponents ?? []\n      actorContext.visualizedComponents.push(-1)\n    }\n\n    return context.images\n  },\n})\n\nexport default assignVisualizedComponents\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/createImageRenderer.js",
    "content": "import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData'\nimport applyIndependentComponents from './applyIndependentComponents'\nimport applyXSlice from '../Main/applyXSlice'\nimport applyYSlice from '../Main/applyYSlice'\nimport applyZSlice from '../Main/applyZSlice'\n\nimport '../vtk/OpenGLImageMapperFractional' // calls registerOverride('vtkImageMapper', newInstance)\n\nasync function createImageRenderer(context) {\n  if (!context.images.source) {\n    context.images.source = context.proxyManager.createProxy(\n      'Sources',\n      'TrivialProducer',\n      { name: 'Image' }\n    )\n  }\n\n  const actorContext = context.images.actorContext.get(\n    context.images.selectedName\n  )\n  actorContext.fusedImage = vtkImageData.newInstance()\n\n  applyIndependentComponents(context)\n  applyXSlice(context, { data: context.main.xSlice })\n  applyYSlice(context, { data: context.main.ySlice })\n  applyZSlice(context, { data: context.main.zSlice })\n}\n\nexport default createImageRenderer\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/fuseImages.js",
    "content": "import WebworkerPromise from 'webworker-promise'\nimport ComposeImageWorker from './ComposeImage.worker.js'\n\nimport itkConfig from '../itkConfig.js'\n\nexport const fuseImages = async ({\n  imageAtScale, //could be array if Conglomerate\n  labelAtScale,\n  visualizedComponents,\n  fixedImageAtScale,\n  compare,\n}) => {\n  // When testing, itkConfig is not full URL, so ensure it's absolute\n  // deep copy\n  const itkWasmConfig = JSON.parse(JSON.stringify(itkConfig))\n  itkWasmConfig.pipelineWorkerUrl = new URL(\n    itkWasmConfig.pipelineWorkerUrl,\n    window.location.href\n  ).href\n  itkWasmConfig.pipelinesUrl = new URL(\n    itkWasmConfig.pipelinesUrl,\n    window.location.href\n  ).href\n\n  const worker = new WebworkerPromise(new ComposeImageWorker())\n  const { image } = await worker.postMessage({\n    image: imageAtScale,\n    labelImage: labelAtScale,\n    visualizedComponents,\n    fixedImage: fixedImageAtScale,\n    compare,\n    itkWasmConfig,\n  })\n  worker.terminate()\n\n  const componentRanges = image.ranges.map(([min, max]) => ({ min, max }))\n\n  return {\n    itkImage: image,\n    componentRanges,\n  }\n}\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/imagesRenderingMachineOptions.js",
    "content": "import { convertVtkToItkImage } from 'vtk.js/Sources/Common/DataModel/ITKHelper'\nimport { writeImageArrayBuffer, copyImage } from 'itk-wasm'\nimport createImageRenderer from './createImageRenderer'\nimport toggleLayerVisibility from './toggleLayerVisibility'\nimport toggleLayerBBox from './toggleLayerBBox'\nimport applyComponentVisibility from './applyComponentVisibility'\nimport updateRenderedImage from './updateRenderedImage'\nimport updateHistogram from './updateHistogram'\nimport selectImageLayer from './selectImageLayer'\nimport toggleInterpolation from './toggleInterpolation'\nimport applyColorRange from './applyColorRange'\nimport { applyColorRangeBounds } from './applyColorRangeBounds'\nimport applyColorMap from './applyColorMap'\nimport applyRenderedImage from './applyRenderedImage'\nimport assignRenderedImage from './assignRenderedImage'\nimport applyPiecewiseFunction from './applyPiecewiseFunction'\nimport applyShadow from './applyShadow'\nimport applyGradientOpacity from './applyGradientOpacity'\nimport applyVolumeSampleDistance from './applyVolumeSampleDistance'\nimport applyBlendMode from './applyBlendMode'\nimport applyLookupTable from './applyLookupTable'\nimport applyLabelImageBlend from './applyLabelImageBlend'\nimport applyLabelNames from './applyLabelNames'\nimport applyLabelImageWeights from './applyLabelImageWeights'\nimport applySelectedLabel from './applySelectedLabel'\nimport mapToPiecewiseFunctionNodes from './mapToPiecewiseFunctionNodes'\nimport mapToColorFunctionRange from './mapToColorFunctionRange'\nimport { getBoundsOfFullImage } from '../Main/croppingPlanes'\nimport { computeRenderedBounds } from '../Main/computeRenderedBounds'\nimport { applyCinematicChanged } from './applyCinematicChanged'\nimport assignVisualizedComponents from './assignVisualizedComponents'\n\nconst EPSILON = 0.000001\n\nconst areBoundsBiggerThanLoaded = context => {\n  const {\n    images: { actorContext },\n    actorName,\n  } = context\n  const { loadedBounds } = actorContext.get(actorName)\n  if (!loadedBounds) return true\n\n  const fullImage = getBoundsOfFullImage(context)\n  const current = computeRenderedBounds(context)\n  // clamp rendered bounds to max size of image\n  current.forEach((b, i) => {\n    current[i] =\n      i % 2\n        ? Math.min(b, fullImage[i]) // high bound case\n        : Math.max(b, fullImage[i]) // low bound case\n  })\n\n  return loadedBounds.some((loaded, i) => {\n    return i % 2\n      ? current[i] - loaded > EPSILON // high bound case: currentBounds[i] > loadedBound\n      : loaded - current[i] > EPSILON // low bound case: currentBounds[i] < loadedBound\n  })\n}\n\nconst isTargetScaleLoaded = context => {\n  const {\n    images: { actorContext },\n    targetScale,\n    actorName,\n  } = context\n  const { loadedScale } = actorContext.get(actorName)\n  return loadedScale === targetScale\n}\n\nfunction downloadArray(content, filename = 'download') {\n  const url = URL.createObjectURL(new Blob([content]))\n  const a = document.createElement('a')\n  a.href = url\n  a.download = filename\n  document.body.appendChild(a)\n  function clickHandler() {\n    setTimeout(() => {\n      URL.revokeObjectURL(url)\n      a.removeEventListener('click', clickHandler)\n    }, 200)\n  }\n  a.addEventListener('click', clickHandler, false)\n  a.click()\n  return a\n}\n\nconst imagesRenderingMachineOptions = {\n  imageRenderingActor: {\n    services: {\n      createImageRenderer,\n      updateRenderedImage,\n      updateHistogram,\n    },\n\n    actions: {\n      applyRenderedImage,\n      assignRenderedImage,\n      assignVisualizedComponents,\n\n      toggleLayerVisibility,\n\n      applyComponentVisibility,\n\n      applyPiecewiseFunction,\n      applyColorRange,\n      applyColorRangeBounds,\n      applyColorMap,\n      mapToPiecewiseFunctionNodes,\n      mapToColorFunctionRange,\n\n      toggleInterpolation,\n      applyShadow,\n      applyGradientOpacity,\n      applyVolumeSampleDistance,\n      applyBlendMode,\n\n      applyLookupTable,\n      applyLabelImageBlend,\n      applyLabelNames,\n      applyLabelImageWeights,\n      applySelectedLabel,\n      applyCinematicChanged,\n\n      toggleLayerBBox,\n    },\n\n    guards: {\n      isFramerateScalePickingOn: ({ images, actorName }) =>\n        images.actorContext.get(actorName).isFramerateScalePickingOn,\n\n      isImageUpdateNeeded: context =>\n        context.isUpdateForced ||\n        (context.images.selectedName === context.actorName && // only update if rendering (aka selected)\n          (!isTargetScaleLoaded(context) ||\n            areBoundsBiggerThanLoaded(context))),\n    },\n  },\n\n  actions: {\n    selectImageLayer,\n    downloadImage: (context, event) => {\n      const { name, format } = event.data\n      const fileName = `${name}.${format}`\n      const actorContext = context.images.actorContext.get(name)\n      const fusedImage = actorContext.fusedImage\n      if (!fusedImage) {\n        console.warn('No image to download')\n        return\n      }\n      const itkImage = copyImage(convertVtkToItkImage(fusedImage, true))\n      writeImageArrayBuffer(null, itkImage, fileName).then(\n        ({ arrayBuffer }) => {\n          downloadArray(arrayBuffer, fileName)\n        }\n      )\n    },\n  },\n}\n\nexport default imagesRenderingMachineOptions\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/mapToColorFunctionRange.js",
    "content": "function mapToColorFunctionRange(\n  context,\n  { data: { name, component, points } }\n) {\n  const actorContext = context.images.actorContext.get(name)\n  const dataRange = actorContext.colorRangeBounds.get(component)\n\n  if (!dataRange) return // viewer.setImagePiecewiseFunctionPoints called at start\n\n  const rangeDelta = dataRange[1] - dataRange[0]\n  const range = points.map(v => v * rangeDelta + dataRange[0])\n\n  // compare with current values to see if updated needed\n  const { colorRanges } = context.images.actorContext.get(name)\n  if (colorRanges.has(component)) {\n    const currentRange = colorRanges.get(component)\n    if (currentRange[0] === range[0] && currentRange[1] === range[1]) {\n      return\n    }\n  }\n\n  context.service.send({\n    type: 'IMAGE_COLOR_RANGE_CHANGED',\n    data: {\n      name,\n      component,\n      range,\n    },\n  })\n}\n\nexport default mapToColorFunctionRange\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/mapToPiecewiseFunctionNodes.js",
    "content": "import { getNodes } from 'itk-viewer-transfer-function-editor'\n\n// grab head and tail or fallback to data range if 1 or less points\nconst getRange = nodes =>\n  nodes.length > 1 ? [nodes[0].x, nodes[nodes.length - 1].x] : undefined\n\nfunction mapToPiecewiseFunctionNodes(\n  context,\n  { data: { name, component, points } }\n) {\n  const actorContext = context.images.actorContext.get(name)\n  const dataRange = actorContext.colorRangeBounds.get(component)\n\n  if (!dataRange) return // viewer.setImagePiecewiseFunctionPoints called at start\n\n  const nodes = getNodes(dataRange, points)\n  const range = getRange(nodes) ?? dataRange\n\n  context.service.send({\n    type: 'IMAGE_PIECEWISE_FUNCTION_CHANGED',\n    data: {\n      name,\n      component,\n      range,\n      nodes,\n    },\n  })\n}\n\nexport default mapToPiecewiseFunctionNodes\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/selectImageLayer.js",
    "content": "function selectImageLayer(context, event) {\n  // This may be highlight the selected image with an outline.\n  // For VTK.js, it currently only supports a single image, so we have to\n  // switch.\n  // Todo\n}\n\nexport default selectImageLayer\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/toggleInterpolation.js",
    "content": "function toggleInterpolation(context, event) {\n  const name = event.data\n  const actorContext = context.images.actorContext.get(name)\n  const interpolation = actorContext.interpolationEnabled\n  context.itkVtkView.setPlanesUseLinearInterpolation(interpolation)\n}\n\nexport default toggleInterpolation\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/toggleLayerBBox.js",
    "content": "function toggleLayerBBox(context, event) {\n  const name = event.data.layerName\n  const actorContext = context.layers.actorContext.get(name)\n  actorContext.bbox = !actorContext.bbox\n  context.itkVtkView.setEnableBBox(name, actorContext.bbox)\n  context.service.send('RENDER')\n}\n\nexport default toggleLayerBBox\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/toggleLayerVisibility.js",
    "content": "import applySlicingPlanes from '../Main/applySlicingPlanes'\n\nfunction toggleLayerVisibility(context, event) {\n  const name = event.data\n  const actorContext = context.layers.actorContext.get(name)\n  const visible = actorContext.visible\n\n  context.itkVtkView.setImageVisibility(visible)\n\n  if (visible) {\n    applySlicingPlanes(context, { data: context.main.slicingPlanes })\n  }\n\n  // Toggle the visibility on the corresponding label image or image layer\n  if (\n    actorContext.type === 'labelImage' &&\n    actorContext.imageName &&\n    context.layers.actorContext.has(actorContext.imageName)\n  ) {\n    const imageLayerContext = context.layers.actorContext.get(\n      actorContext.imageName\n    )\n    if (imageLayerContext.visible !== visible) {\n      context.service.send({\n        type: 'TOGGLE_LAYER_VISIBILITY',\n        data: actorContext.imageName,\n      })\n    }\n  } else if (actorContext.type === 'image') {\n    const imageActorContext = context.images.actorContext.get(name)\n    if (context.layers.actorContext.has(imageActorContext.labelImageName)) {\n      const labelImageLayerContext = context.layers.actorContext.get(\n        imageActorContext.labelImageName\n      )\n      if (labelImageLayerContext.visible !== visible) {\n        context.service.send({\n          type: 'TOGGLE_LAYER_VISIBILITY',\n          data: imageActorContext.labelImageName,\n        })\n      }\n    }\n  }\n\n  context.service.send('RENDER')\n}\n\nexport default toggleLayerVisibility\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/transformLabelImageWeight.js",
    "content": "function transformLabelImageWeight(weight, minWeight, maxWeight) {\n  return weight * (maxWeight - minWeight) + minWeight\n}\n\nexport default transformLabelImageWeight\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/updateHistogram.js",
    "content": "import { computeHistogram } from '../../../IO/Analyze/computeHistograms'\n\nfunction makeHistogram(actorContext, component) {\n  const dataArray = actorContext.fusedImage.getPointData().getScalars()\n  if (!dataArray) return undefined\n  const numberOfComponents = dataArray.getNumberOfComponents()\n\n  const fusedImageComponent = actorContext.visualizedComponents.indexOf(\n    component\n  )\n\n  if (fusedImageComponent === -1) return undefined\n\n  const [min, max] = actorContext.colorRangeBounds.get(component) ?? [0, 0] // [0, 0] default for no image, only imageLabel case\n  return computeHistogram(\n    dataArray.getData(),\n    fusedImageComponent,\n    numberOfComponents,\n    [min, max]\n  )\n}\n\nasync function updateHistogram(context) {\n  const actorContext = context.images.actorContext.get(context.actorName)\n  const component = actorContext.selectedComponent\n\n  const histogram =\n    actorContext.histograms.get(component) ?? // histogram may have been cleared after loading new data\n    (await makeHistogram(actorContext, component))\n\n  if (histogram) actorContext.histograms.set(component, histogram) // component or image may not be loaded\n\n  context.service.send({\n    type: 'IMAGE_HISTOGRAM_UPDATED',\n    data: { name: context.actorName, component, histogram },\n  })\n}\n\nexport default updateHistogram\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/updateLabelImagePiecewiseFunction.js",
    "content": "function transformUserWeight(userWeight, minWeight, maxWeight) {\n  return userWeight * (maxWeight - minWeight) + minWeight\n}\n\nfunction updateLabelImagePiecewiseFunction(\n  context,\n  actorContext,\n  selectedIndices = null\n) {\n  if (!!!actorContext.labelImage) {\n    return\n  }\n\n  const piecewiseFunction = context.images.piecewiseFunctions.get('labelImage')\n  const labelImageWeights = actorContext.labelImageWeights\n\n  let minLabelWeight = 0.0\n  let maxLabelWeight = 1.0\n  if (!actorContext.image) {\n    maxLabelWeight = 0.05\n    if (context.main.viewMode !== 'Volume') {\n      maxLabelWeight = 1.0\n      minLabelWeight = 0.4\n    }\n  }\n\n  if (selectedIndices === null || selectedIndices === 'all') {\n    const uniqueLabels = context.images.uniqueLabels\n    // Update all values from the context\n    const maxOpacity = 1.0\n    const haveBackground = uniqueLabels[0] === 0 ? true : false\n\n    piecewiseFunction.removeAllPoints()\n\n    if (haveBackground) {\n      piecewiseFunction.addPointLong(uniqueLabels[0], 0.0, 0.5, 1.0)\n    } else {\n      piecewiseFunction.addPointLong(\n        uniqueLabels[0],\n        transformUserWeight(\n          labelImageWeights[0],\n          minLabelWeight,\n          maxLabelWeight\n        ),\n        0.5,\n        1.0\n      )\n    }\n\n    for (let i = 1; i < uniqueLabels.length; i++) {\n      piecewiseFunction.addPointLong(\n        uniqueLabels[i],\n        transformUserWeight(\n          labelImageWeights[i],\n          minLabelWeight,\n          maxLabelWeight\n        ),\n        0.5,\n        1.0\n      )\n    }\n  } else {\n    // Otherwise, just update specific values\n    selectedIndices.forEach(value => {\n      const weight = transformUserWeight(\n        labelImageWeights[value],\n        minLabelWeight,\n        maxLabelWeight\n      )\n      piecewiseFunction.setNodeValue(value, [value, weight, 0.5, 1.0])\n    })\n  }\n}\n\nexport default updateLabelImagePiecewiseFunction\n"
  },
  {
    "path": "src/Rendering/VTKJS/Images/updateRenderedImage.js",
    "content": "import vtkITKHelper from 'vtk.js/Sources/Common/DataModel/ITKHelper'\nimport { mat4 } from 'gl-matrix'\n\nimport { fuseImages } from './fuseImages'\nimport { computeRenderedBounds } from '../Main/computeRenderedBounds'\nimport { worldBoundsToIndexBounds } from '../../../IO/MultiscaleSpatialImage'\nimport componentTypeToTypedArray from '../../../IO/componentTypeToTypedArray'\n\nexport const RENDERED_VOXEL_MAX = 512 * 512 * 512 * 2\nconst RENDERED_IMAGE_BYTES_MAX = RENDERED_VOXEL_MAX * 2 // 2 byte pixel type = 1073741824\n\nconst getVoxelCount = async (image, bounds, scale) => {\n  const scaleInfo = image.scaleInfo[scale]\n\n  if (!bounds) {\n    return ['x', 'y', 'z']\n      .map(dim => scaleInfo.arrayShape.get(dim))\n      .reduce((voxels, dimSize) => voxels * dimSize, 1)\n  }\n\n  const indexToWorld = await image.scaleIndexToWorld(scale)\n\n  const fullIndexBounds = image.getIndexBounds(scale)\n  const indexBounds = worldBoundsToIndexBounds({\n    bounds,\n    fullIndexBounds,\n    worldToIndex: mat4.invert([], indexToWorld),\n  })\n  return ['x', 'y', 'z']\n    .map(dim => {\n      const [start, end] = indexBounds.get(dim)\n      return end - start + 1 // plus 1 as bounds are inclusive\n    })\n    .reduce((voxels, dimSize) => voxels * dimSize, 1)\n}\n\nconst computeBytes = async (\n  { imageType: { componentType, components } },\n  voxelCount\n) => {\n  const bytesPerElement = componentTypeToTypedArray.get(componentType)\n    .BYTES_PER_ELEMENT\n  return bytesPerElement * components * voxelCount\n}\n\nconst pickVisualized = (preComputedRanges, visualizedComponents) =>\n  visualizedComponents\n    .map(\n      sourceIdx => preComputedRanges[sourceIdx] ?? [0, 1] // fallback for label component\n    )\n    .map(([min, max]) => ({\n      min,\n      max,\n    }))\n\nasync function updateRenderedImage(context) {\n  const name = context.actorName\n  const actorContext = context.images.actorContext.get(name)\n\n  const {\n    image,\n    labelImage,\n    editorLabelImage,\n    visualizedComponents,\n    compare,\n  } = actorContext\n\n  if (!image && !labelImage && !editorLabelImage) {\n    return\n  }\n\n  const compareEnabled = compare.method && compare.method !== 'disabled'\n  const fixedImage = compareEnabled\n    ? context.images.actorContext.get(compare.fixedImageName)?.image\n    : undefined\n\n  if (compareEnabled && !fixedImage)\n    console.error(\n      `Did not find image to compare with name: ${compare.fixedImageName}`\n    )\n\n  const baseImage = fixedImage ?? image ?? labelImage\n\n  const { targetScale } = context\n\n  const baseImageClampedScale = Math.min(baseImage.coarsestScale, targetScale)\n\n  // always load full image if least detailed scale\n  const isCoarsestScale = baseImage.coarsestScale === baseImageClampedScale\n  const boundsToLoad = isCoarsestScale\n    ? undefined\n    : computeRenderedBounds(context)\n\n  const voxelCount = await getVoxelCount(\n    baseImage,\n    boundsToLoad,\n    baseImageClampedScale\n  )\n  if (voxelCount > RENDERED_VOXEL_MAX)\n    throw new Error(\n      `Voxel count over max at scale ${baseImageClampedScale}. Requested: ${voxelCount} Max: ${RENDERED_VOXEL_MAX}`\n    )\n\n  const imageByteSize = await computeBytes(baseImage, voxelCount)\n  if (!isCoarsestScale && imageByteSize > RENDERED_IMAGE_BYTES_MAX)\n    throw new Error(\n      `Image byte count over max at scale ${targetScale}. Requested: ${imageByteSize} Max: ${RENDERED_IMAGE_BYTES_MAX}`\n    )\n\n  const [imageAtScale, labelAtScale, fixedImageAtScale] = await Promise.all(\n    [image, labelImage, fixedImage].map(image =>\n      image?.getImage(targetScale, boundsToLoad)\n    )\n  )\n  const imageOrLabelAtScale = imageAtScale ?? labelAtScale\n\n  const preComputedRanges =\n    baseImage?.scaleInfo[baseImageClampedScale].ranges ??\n    imageOrLabelAtScale?.ranges\n\n  const isFuseNeeded =\n    (labelAtScale && imageAtScale) || // fuse with label image\n    fixedImageAtScale ||\n    Array.isArray(imageAtScale) || // is conglomerate\n    imageOrLabelAtScale?.imageType.components !== visualizedComponents.length // more components in image than renderable\n\n  const { itkImage, componentRanges } = isFuseNeeded\n    ? await fuseImages({\n        imageAtScale,\n        labelAtScale,\n        fixedImageAtScale,\n        visualizedComponents,\n        compare,\n      })\n    : {\n        itkImage: imageOrLabelAtScale,\n        componentRanges: pickVisualized(\n          preComputedRanges,\n          visualizedComponents\n        ),\n      }\n\n  const vtkImage = vtkITKHelper.convertItkToVtkImage(itkImage)\n  return {\n    itkImage,\n    vtkImage,\n    labelAtScale,\n    componentRanges,\n    loadedScale: targetScale,\n    name,\n  }\n}\n\nexport default updateRenderedImage\n"
  },
  {
    "path": "src/Rendering/VTKJS/Layers/layersRenderingMachineOptions.js",
    "content": "const layersRenderingMachineOptions = {\n  actions: {},\n}\n\nexport default layersRenderingMachineOptions\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/applyCroppingPlanes.js",
    "content": "import vtkMath from 'vtk.js/Sources/Common/Core/Math'\nimport { transformVec3 } from 'vtk.js/Sources/Widgets/Widgets3D/ImageCroppingWidget/helpers'\n\nfunction applyCroppingPlanes(context, event) {\n  if (event.data) {\n    const planes = event.data\n\n    planes.forEach((plane, idx) => {\n      context.main.widgetCroppingPlanes[idx].setOriginFrom(plane.origin)\n      context.main.widgetCroppingPlanes[idx].setNormalFrom(plane.normal)\n    })\n\n    // update widget\n    if (planes.length === 6) {\n      const worldToIndex = context.main.croppingVirtualImage.getWorldToIndex()\n      const cropIndexes = context.main.croppingWidget\n        .getWidgetState()\n        .getCroppingPlanes()\n        .getPlanes()\n      const newCropIndexes = planes\n        .map(({ origin }) => transformVec3(origin, worldToIndex))\n        .map((ijk, idx) => ijk[Math.trunc(idx / 2)]) // index is 0, 0, 1, 1, 2, 2\n      if (!vtkMath.areEquals(cropIndexes, newCropIndexes, 1e-8)) {\n        context.main.croppingWidget\n          .getWidgetState()\n          .getCroppingPlanes()\n          .setPlanes(newCropIndexes)\n      }\n    }\n\n    context.service.send('RENDER')\n  }\n}\n\nexport default applyCroppingPlanes\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/applySlicingPlanes.js",
    "content": "function applySlicingPlanes(context, event) {\n  const slicingPlanes = event.data\n\n  const volumeRep = context.images.representationProxy\n  if (volumeRep) {\n    const outlineActors = context.itkVtkView.getSliceOutlineActors()\n    if (context.use2D) {\n      volumeRep.getActors()[0].setVisibility(false)\n      volumeRep.getActors()[1].setVisibility(false)\n      volumeRep.getActors()[2].setVisibility(true)\n      outlineActors[0].setVisibility(false)\n      outlineActors[1].setVisibility(false)\n      outlineActors[2].setVisibility(false)\n      return\n    }\n\n    const name = context.images.selectedName\n    const imageVisible = context.layers.actorContext.get(name).visible\n    if (imageVisible) {\n      const annotations = context.main.annotationsEnabled\n      switch (context.main.viewMode) {\n        case 'Volume':\n          volumeRep.setXSliceVisibility(slicingPlanes.x.visible)\n          volumeRep.setYSliceVisibility(slicingPlanes.y.visible)\n          volumeRep.setZSliceVisibility(slicingPlanes.z.visible)\n          if (annotations) {\n            outlineActors[0].setVisibility(slicingPlanes.x.visible)\n            outlineActors[1].setVisibility(slicingPlanes.y.visible)\n            outlineActors[2].setVisibility(slicingPlanes.z.visible)\n          }\n          break\n        case 'XPlane':\n          volumeRep.getActors()[0].setVisibility(true)\n          volumeRep.getActors()[1].setVisibility(false)\n          volumeRep.getActors()[2].setVisibility(false)\n          if (annotations) {\n            outlineActors[0].setVisibility(true)\n            outlineActors[1].setVisibility(false)\n            outlineActors[2].setVisibility(false)\n          }\n          break\n        case 'YPlane':\n          volumeRep.getActors()[0].setVisibility(false)\n          volumeRep.getActors()[1].setVisibility(true)\n          volumeRep.getActors()[2].setVisibility(false)\n          if (annotations) {\n            outlineActors[0].setVisibility(false)\n            outlineActors[1].setVisibility(true)\n            outlineActors[2].setVisibility(false)\n          }\n          break\n        case 'ZPlane':\n          volumeRep.getActors()[0].setVisibility(false)\n          volumeRep.getActors()[1].setVisibility(false)\n          volumeRep.getActors()[2].setVisibility(true)\n          if (annotations) {\n            outlineActors[0].setVisibility(false)\n            outlineActors[1].setVisibility(false)\n            outlineActors[2].setVisibility(true)\n          }\n          break\n      }\n    } else {\n      volumeRep.setXSliceVisibility(false)\n      volumeRep.setYSliceVisibility(false)\n      volumeRep.setZSliceVisibility(false)\n      outlineActors.forEach(a => a.setVisibility(false))\n    }\n    if (\n      slicingPlanes.x.visible ||\n      slicingPlanes.y.visible ||\n      slicingPlanes.z.visible\n    ) {\n      context.itkVtkView.setViewPlanes(true)\n    } else {\n      context.itkVtkView.setViewPlanes(false)\n    }\n\n    if (slicingPlanes.x.scroll) {\n      if (!context.main.xPlaneAnimation) {\n        context.itkVtkView.getInteractor().requestAnimation('xPlaneScroll')\n        context.main.xPlaneAnimation = context.itkVtkView\n          .getInteractor()\n          .onAnimation(() => {\n            let xSlice =\n              context.main.xSlice +\n              slicingPlanes.x.step * slicingPlanes.x.scrollDirection\n            if (xSlice > slicingPlanes.x.max) {\n              xSlice = slicingPlanes.x.max\n              slicingPlanes.x.scrollDirection *= -1\n            }\n            if (xSlice < slicingPlanes.x.min) {\n              xSlice = slicingPlanes.x.min\n              slicingPlanes.x.scrollDirection *= -1\n            }\n            context.service.send({\n              type: 'X_SLICE_CHANGED',\n              data: xSlice,\n            })\n          })\n      }\n    } else if (context.main.xPlaneAnimation) {\n      context.main.xPlaneAnimation.unsubscribe()\n      context.itkVtkView.getInteractor().cancelAnimation('xPlaneScroll')\n      context.main.xPlaneAnimation = null\n    }\n\n    if (slicingPlanes.y.scroll) {\n      if (!context.main.yPlaneAnimation) {\n        context.itkVtkView.getInteractor().requestAnimation('yPlaneScroll')\n        context.main.yPlaneAnimation = context.itkVtkView\n          .getInteractor()\n          .onAnimation(() => {\n            let ySlice =\n              context.main.ySlice +\n              slicingPlanes.y.step * slicingPlanes.y.scrollDirection\n            if (ySlice > slicingPlanes.y.max) {\n              ySlice = slicingPlanes.y.max\n              slicingPlanes.y.scrollDirection *= -1\n            }\n            if (ySlice < slicingPlanes.y.min) {\n              ySlice = slicingPlanes.y.min\n              slicingPlanes.y.scrollDirection *= -1\n            }\n            context.service.send({\n              type: 'Y_SLICE_CHANGED',\n              data: ySlice,\n            })\n          })\n      }\n    } else if (context.main.yPlaneAnimation) {\n      context.main.yPlaneAnimation.unsubscribe()\n      context.itkVtkView.getInteractor().cancelAnimation('yPlaneScroll')\n      context.main.yPlaneAnimation = null\n    }\n\n    if (slicingPlanes.z.scroll) {\n      if (!context.main.zPlaneAnimation) {\n        context.itkVtkView.getInteractor().requestAnimation('zPlaneScroll')\n        context.main.zPlaneAnimation = context.itkVtkView\n          .getInteractor()\n          .onAnimation(() => {\n            let zSlice =\n              context.main.zSlice +\n              slicingPlanes.z.step * slicingPlanes.z.scrollDirection\n            if (zSlice > slicingPlanes.z.max) {\n              zSlice = slicingPlanes.z.max\n              slicingPlanes.z.scrollDirection *= -1\n            }\n            if (zSlice < slicingPlanes.z.min) {\n              zSlice = slicingPlanes.z.min\n              slicingPlanes.z.scrollDirection *= -1\n            }\n            context.service.send({\n              type: 'Z_SLICE_CHANGED',\n              data: zSlice,\n            })\n          })\n      }\n    } else if (context.main.zPlaneAnimation) {\n      context.main.zPlaneAnimation.unsubscribe()\n      context.itkVtkView.getInteractor().cancelAnimation('zPlaneScroll')\n      context.main.zPlaneAnimation = null\n    }\n  }\n\n  context.service.send('RENDER')\n}\n\nexport default applySlicingPlanes\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/applyXSlice.js",
    "content": "function applyXSlice(context, event) {\n  const position = event.data\n\n  const volumeRep = context.images.representationProxy\n  if (volumeRep) {\n    volumeRep.setXSlice(Number(position))\n    context.service.send('RENDER')\n  }\n}\n\nexport default applyXSlice\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/applyYSlice.js",
    "content": "function applyYSlice(context, event) {\n  const position = event.data\n\n  const volumeRep = context.images.representationProxy\n  if (volumeRep) {\n    volumeRep.setYSlice(Number(position))\n    context.service.send('RENDER')\n  }\n}\n\nexport default applyYSlice\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/applyZSlice.js",
    "content": "function applyZSlice(context, event) {\n  const position = event.data\n\n  const volumeRep = context.images.representationProxy\n  if (volumeRep) {\n    volumeRep.setZSlice(Number(position))\n    context.service.send('RENDER')\n  }\n}\n\nexport default applyZSlice\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/computeRenderedBounds.js",
    "content": "import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox'\n\nconst NDC_RANGE = [0, 1]\n\n// unproject NDC box\nconst computeFrustumBoundingBox = renderer => {\n  const view = renderer.getRenderWindow().getViews()[0]\n\n  const dims = view.getViewportSize(renderer)\n  const aspect = dims[0] / dims[1]\n\n  const frustumBounds = [...vtkBoundingBox.INIT_BOUNDS]\n  for (const x of NDC_RANGE) {\n    for (const y of NDC_RANGE) {\n      for (const z of NDC_RANGE) {\n        const corner = renderer.normalizedDisplayToWorld(x, y, z, aspect)\n        vtkBoundingBox.addPoint(frustumBounds, ...corner)\n      }\n    }\n  }\n  return frustumBounds\n}\n\nexport const computeCroppingPlanesBoundingBox = croppingPlanes => {\n  const planeBounds = [...vtkBoundingBox.INIT_BOUNDS]\n  croppingPlanes.forEach(({ origin }) =>\n    vtkBoundingBox.addPoint(planeBounds, ...origin)\n  )\n  return planeBounds\n}\n\nconst intersectBoxes = (b1, b2) =>\n  b1.map(\n    (bound, i) =>\n      i % 2\n        ? Math.min(bound, b2[i]) // high bound case\n        : Math.max(bound, b2[i]) // low bound case\n  )\n\nexport const computeRenderedBounds = ({\n  main: { croppingPlanes, areCroppingPlanesTouched },\n  itkVtkView,\n}) => {\n  const frustumBox = computeFrustumBoundingBox(itkVtkView.getRenderer())\n\n  const areCroppingPlanesRelevant =\n    croppingPlanes && croppingPlanes.length === 6 && areCroppingPlanesTouched\n  return areCroppingPlanesRelevant\n    ? intersectBoxes(\n        computeCroppingPlanesBoundingBox(croppingPlanes),\n        frustumBox\n      )\n    : frustumBox\n}\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/createMainRenderer.js",
    "content": "// Load the rendering pieces we want to use (for both WebGL and WebGPU)\nimport 'vtk.js/Sources/Rendering/Profiles/Geometry'\nimport 'vtk.js/Sources/Rendering/Profiles/Glyph'\nimport 'vtk.js/Sources/Rendering/Profiles/Volume'\n\nimport { createCropping } from './croppingPlanes'\n\nfunction createMainRenderer(context) {\n  createCropping(context)\n}\n\nexport default createMainRenderer\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/croppingPlanes.js",
    "content": "import { mat4, vec3, quat, vec4 } from 'gl-matrix'\nimport vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData'\nimport { transformVec3 } from 'vtk.js/Sources/Widgets/Widgets3D/ImageCroppingWidget/helpers'\nimport vtkMath from 'vtk.js/Sources/Common/Core/Math'\nimport vtkPlane from 'vtk.js/Sources/Common/DataModel/Plane'\nimport vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox'\n\nimport toggleCroppingPlanes from './toggleCroppingPlanes'\nimport HandlesInPixelsImageCroppingWidget from '../Widgets/HandlesInPixelsImageCroppingWidget'\nimport { transformBounds } from '../../../transformBounds'\nimport { arraysEqual, makeIndexToWorld } from '../../../internalUtils'\n\nexport function getCropWidgetBounds(context, bounds = []) {\n  const { croppingWidget } = context.main\n\n  vtkBoundingBox.reset(bounds)\n  croppingWidget\n    .getWidgetState()\n    .getStatesWithLabel('faces')\n    .map(h => h.getOrigin())\n    .forEach(point => vtkBoundingBox.addPoint(bounds, ...point))\n  return bounds\n}\n\nexport function getBoundsOfFullImage({ images, actorName }) {\n  const imageActorContext = images.actorContext.get(actorName)\n  if (!imageActorContext || imageActorContext.loadedScale === null)\n    return [...vtkBoundingBox.INIT_BOUNDS]\n\n  const { compare } = imageActorContext\n  const compareEnabled = compare?.method !== 'disabled'\n  const fixedImage = compareEnabled\n    ? images.actorContext.get(compare.fixedImageName)?.image\n    : undefined\n\n  const multiScale =\n    fixedImage ?? imageActorContext.image ?? imageActorContext.labelImage\n  return multiScale.getWorldBounds(imageActorContext.loadedScale)\n}\n\nexport function createCropping(context) {\n  const croppingWidget = HandlesInPixelsImageCroppingWidget.newInstance()\n  context.main.croppingWidget = croppingWidget\n  context.main.widgetCroppingPlanes = Array.from({ length: 6 }, () =>\n    vtkPlane.newInstance()\n  )\n  context.itkVtkView.addCroppingWidget(croppingWidget)\n\n  croppingWidget\n    .getWidgetState()\n    .getStatesWithLabel('handles')\n    .forEach(h => h.setScale1(22))\n  croppingWidget.setFaceHandlesEnabled(true)\n  croppingWidget.setCornerHandlesEnabled(false)\n  croppingWidget.setEdgeHandlesEnabled(false)\n\n  // These are helper objects to bridge datasets in the scene, images,\n  // geometry, and points sets, the croppingPlanes, and the\n  // ImageCroppingWidget.\n  //\n  // The croppingVirtualImage is used to set the worldToIndex transform and\n  // indexToWorld transform with imageCroppingWidget.copyImageDataDescription.\n  //\n  // The Direction of the virtual image is set to the Direction of the\n  // imagesMachineContext.selectedName's Direction.\n  //\n  // The Origin of the virtual image is set to the lower left of the\n  // croppingBoundingBox\n  //\n  // The Spacing of the virtual image is set to the spacing of the selected\n  // image, if one exists, otherwise the extent of the croppingBoundingBox /\n  // 1000 (is there a better approach for this?).\n\n  context.main.croppingVirtualImage = vtkImageData.newInstance()\n\n  const cropState = croppingWidget.getWidgetState().getCroppingPlanes()\n  cropState.onModified(() => {\n    const { croppingWidget } = context.main\n\n    // updates bounds for camera clipping planes\n    const widgetBounds = getCropWidgetBounds(\n      context,\n      croppingWidget.getWidgetState().getBounds()\n    )\n    croppingWidget.placeWidget(widgetBounds)\n\n    const prop = context.itkVtkView.getWidgetProp(croppingWidget)\n    if (\n      prop &&\n      prop.getEnabled() &&\n      croppingWidget\n        .getWidgetState()\n        .getStatesWithLabel('handles')\n        .some(h => h.getActive())\n    ) {\n      const indexes = cropState.getPlanes()\n\n      const indexToWorld = context.main.croppingVirtualImage.getIndexToWorld()\n      const direction = context.main.croppingVirtualImage.getDirection()\n      const croppingPlanes = [\n        {\n          origin: Array.from(\n            transformVec3([indexes[0], indexes[2], indexes[4]], indexToWorld)\n          ),\n          normal: Array.from(direction.slice(0, 3)),\n        },\n        {\n          origin: Array.from(\n            transformVec3([indexes[1], indexes[3], indexes[5]], indexToWorld)\n          ),\n          normal: vtkMath.multiplyScalar(Array.from(direction.slice(0, 3)), -1),\n        },\n        {\n          origin: Array.from(\n            transformVec3([indexes[0], indexes[2], indexes[4]], indexToWorld)\n          ),\n          normal: Array.from(direction.slice(3, 6)),\n        },\n        {\n          origin: Array.from(\n            transformVec3([indexes[1], indexes[3], indexes[5]], indexToWorld)\n          ),\n          normal: vtkMath.multiplyScalar(Array.from(direction.slice(3, 6)), -1),\n        },\n        {\n          origin: Array.from(\n            transformVec3([indexes[0], indexes[2], indexes[4]], indexToWorld)\n          ),\n          normal: Array.from(direction.slice(6, 9)),\n        },\n        {\n          origin: Array.from(\n            transformVec3([indexes[1], indexes[3], indexes[5]], indexToWorld)\n          ),\n          normal: vtkMath.multiplyScalar(Array.from(direction.slice(6, 9)), -1),\n        },\n      ]\n\n      // Don't reset planes after user input\n      context.main.areCroppingPlanesTouched = true\n\n      context.service.send({\n        type: 'CROPPING_PLANES_CHANGED',\n        data: croppingPlanes,\n      })\n\n      context.service.send({\n        type: 'CROPPING_PLANES_CHANGED_BY_USER',\n      })\n    }\n  })\n  context.itkVtkView.setWidgetManagerInitializedCallback(() => {\n    toggleCroppingPlanes(context)\n  })\n}\n\nexport function updateCroppingParameters(context) {\n  const { croppingVirtualImage, croppingWidget } = context.main\n\n  // croppingBoundingBox is an axis-aligned bounding box that encapsulates all\n  // objects in the scene.\n  const croppingBoundingBox = [...vtkBoundingBox.INIT_BOUNDS]\n  context.itkVtkView\n    .getRepresentations()\n    .filter(r => r.getClassName() !== 'vtkVolumeRepresentationProxy') // filter out possibly outdated images which may change in size across scales\n    .map(r => r.getBounds())\n    .concat([getBoundsOfFullImage(context)]) // include latest image\n    .forEach(bounds => {\n      vtkBoundingBox.addBounds(croppingBoundingBox, ...bounds)\n    })\n  const uninitialized = arraysEqual(\n    croppingBoundingBox,\n    vtkBoundingBox.INIT_BOUNDS\n  )\n\n  if (uninitialized) return\n\n  // Put global bounds in image oriented space\n\n  const worldToImageDirection = makeIndexToWorld({\n    direction: croppingVirtualImage.getDirection(),\n    origin: [0, 0, 0],\n    spacing: [1, 1, 1],\n  })\n\n  const orientedBox = transformBounds(\n    worldToImageDirection,\n    croppingBoundingBox\n  )\n\n  const originWorldSpace = vec3.transformMat4(\n    croppingVirtualImage.getOrigin(),\n    [orientedBox[0], orientedBox[2], orientedBox[4]],\n    worldToImageDirection\n  )\n  croppingVirtualImage.setOrigin(originWorldSpace)\n\n  const spacing = croppingVirtualImage.getSpacing()\n  croppingVirtualImage.setDimensions([\n    (orientedBox[1] - orientedBox[0]) / spacing[0],\n    (orientedBox[3] - orientedBox[2]) / spacing[1],\n    (orientedBox[5] - orientedBox[4]) / spacing[2],\n  ])\n\n  const widgetState = croppingWidget.getWidgetState()\n  widgetState.setIndexToWorldT(...croppingVirtualImage.getIndexToWorld())\n  widgetState.setWorldToIndexT(...croppingVirtualImage.getWorldToIndex())\n\n  if (!context.main.areCroppingPlanesTouched) {\n    // fit new actor if planes not changed by user\n    context.service.send('RESET_CROPPING_PLANES')\n  } else {\n    // update widget transforms\n    context.service.send({\n      type: 'CROPPING_PLANES_CHANGED',\n      data: context.main.croppingPlanes,\n    })\n  }\n}\n\nexport function updateCroppingParametersFromImage(context, image) {\n  const { croppingVirtualImage } = context.main\n  croppingVirtualImage.setSpacing(image.getSpacing())\n  croppingVirtualImage.setDirection(image.getDirection())\n\n  updateCroppingParameters(context, image)\n}\n\nexport function addCroppingPlanes(context, actor) {\n  const { widgetCroppingPlanes } = context.main\n  const mapper = actor.getMapper()\n  widgetCroppingPlanes.forEach(plane => {\n    mapper.addClippingPlane(plane)\n  })\n}\n\nexport function makeCroppable(context, representationProxy) {\n  // allows for grabbing crop handles on the other side of volume\n  representationProxy.getVolumes().forEach(v => v.setPickable(false))\n  addCroppingPlanes(context, representationProxy)\n}\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/mainRenderingMachineOptions.js",
    "content": "import setBackgroundColor from './setBackgroundColor'\nimport setUnits from './setUnits'\nimport takeScreenshot from './takeScreenshot'\nimport toggleRotate from './toggleRotate'\nimport toggleAnnotations from './toggleAnnotations'\nimport toggleAxes from './toggleAxes'\nimport toggleCroppingPlanes from './toggleCroppingPlanes'\nimport resetCroppingPlanes from './resetCroppingPlanes'\nimport applyCroppingPlanes from './applyCroppingPlanes'\nimport updateSlicingPlanes from './updateSlicingPlanes'\nimport viewModeXPlane from './viewModeXPlane'\nimport viewModeYPlane from './viewModeYPlane'\nimport viewModeZPlane from './viewModeZPlane'\nimport viewModeVolume from './viewModeVolume'\nimport resetCamera from './resetCamera'\nimport applySlicingPlanes from './applySlicingPlanes'\nimport applyXSlice from './applyXSlice'\nimport applyYSlice from './applyYSlice'\nimport applyZSlice from './applyZSlice'\nimport updateFps from './updateFps'\n\nconst mainRenderingMachineOptions = {\n  actions: {\n    setBackgroundColor,\n\n    setUnits,\n\n    takeScreenshot,\n\n    toggleRotate,\n\n    toggleAnnotations,\n\n    toggleAxes,\n\n    resetCroppingPlanes,\n    toggleCroppingPlanes,\n    applyCroppingPlanes,\n    updateSlicingPlanes,\n\n    viewModeXPlane,\n    viewModeYPlane,\n    viewModeZPlane,\n    viewModeVolume,\n\n    resetCamera,\n\n    applySlicingPlanes,\n    applyXSlice,\n    applyYSlice,\n    applyZSlice,\n\n    updateFps,\n  },\n}\n\nexport default mainRenderingMachineOptions\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/resetCamera.js",
    "content": "import { getCropWidgetBounds } from './croppingPlanes'\n\nfunction resetCamera(context) {\n  context.itkVtkView.resetCamera(getCropWidgetBounds(context))\n}\n\nexport default resetCamera\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/resetCroppingPlanes.js",
    "content": "import vtkMath from 'vtk.js/Sources/Common/Core/Math'\nimport { transformVec3 } from 'vtk.js/Sources/Widgets/Widgets3D/ImageCroppingWidget/helpers'\n\nfunction resetCroppingPlanes(context) {\n  const dims = context.main.croppingVirtualImage.getDimensions()\n  const direction = context.main.croppingVirtualImage.getDirection()\n  const indexToWorld = context.main.croppingVirtualImage.getIndexToWorld()\n  const croppingPlanes = [\n    {\n      origin: Array.from(transformVec3([0, 0, 0], indexToWorld)),\n      normal: Array.from(direction.slice(0, 3)),\n    },\n    {\n      origin: Array.from(\n        transformVec3([dims[0], dims[1], dims[2]], indexToWorld)\n      ),\n      normal: vtkMath.multiplyScalar(Array.from(direction.slice(0, 3)), -1),\n    },\n    {\n      origin: Array.from(transformVec3([0, 0, 0], indexToWorld)),\n      normal: Array.from(direction.slice(3, 6)),\n    },\n    {\n      origin: Array.from(\n        transformVec3([dims[0], dims[1], dims[2]], indexToWorld)\n      ),\n      normal: vtkMath.multiplyScalar(Array.from(direction.slice(3, 6)), -1),\n    },\n    {\n      origin: Array.from(transformVec3([0, 0, 0], indexToWorld)),\n      normal: Array.from(direction.slice(6, 9)),\n    },\n    {\n      origin: Array.from(\n        transformVec3([dims[0], dims[1], dims[2]], indexToWorld)\n      ),\n      normal: vtkMath.multiplyScalar(Array.from(direction.slice(6, 9)), -1),\n    },\n  ]\n  context.service.send({\n    type: 'CROPPING_PLANES_CHANGED',\n    data: croppingPlanes,\n  })\n}\n\nexport default resetCroppingPlanes\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/setBackgroundColor.js",
    "content": "function setBackgroundColor(context, event) {\n  if (event.data) {\n    context.main.backgroundColor = event.data\n  }\n  const backgroundColor = context.main.backgroundColor\n  context.itkVtkView.setBackground(backgroundColor)\n  context.service.send('RENDER')\n}\n\nexport default setBackgroundColor\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/setUnits.js",
    "content": "function setUnits(context, event) {\n  if (event.data) {\n    context.main.units = event.data\n  }\n  context.itkVtkView.setUnits(context.main.units)\n}\n\nexport default setUnits\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/takeScreenshot.js",
    "content": "async function takeScreenshot(context) {\n  const proxy = context.images.representationProxy\n  let mapper = null\n  let imageSampleDistance = 1.0\n  if (proxy) {\n    mapper = proxy.getMapper()\n    mapper.setAutoAdjustSampleDistances(false)\n    imageSampleDistance = mapper.getImageSampleDistance()\n    mapper.setImageSampleDistance(0.1)\n  }\n  const image = new Image()\n  const base64PNG = await context.itkVtkView.captureImage().then(imageURL => {\n    image.src = imageURL\n    const w = window.open('', '_blank')\n    w.document.write(image.outerHTML)\n    w.document.title = 'vtk.js Image Capture'\n    window.focus()\n    return imageURL\n  })\n  context.service.send({ type: 'SCREENSHOT_TAKEN', data: base64PNG })\n  if (proxy) {\n    mapper.setImageSampleDistance(imageSampleDistance)\n    mapper.setAutoAdjustSampleDistances(true)\n  }\n}\n\nexport default takeScreenshot\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/toggleAnnotations.js",
    "content": "function toggleAnnotations(context) {\n  let annotationsEnabled = context.main.annotationsEnabled\n  context.itkVtkView.setOrientationAnnotationVisibility(annotationsEnabled)\n  if (annotationsEnabled) {\n    const outlineActors = context.itkVtkView.getSliceOutlineActors()\n    const slicingPlanes = context.main.slicingPlanes\n    switch (context.main.viewMode) {\n      case 'Volume':\n        outlineActors[0].setVisibility(slicingPlanes.x.visible)\n        outlineActors[1].setVisibility(slicingPlanes.y.visible)\n        outlineActors[2].setVisibility(slicingPlanes.z.visible)\n        break\n      case 'XPlane':\n        outlineActors[0].setVisibility(true)\n        outlineActors[1].setVisibility(false)\n        outlineActors[2].setVisibility(false)\n        break\n      case 'YPlane':\n        outlineActors[0].setVisibility(false)\n        outlineActors[1].setVisibility(true)\n        outlineActors[2].setVisibility(false)\n        break\n      case 'ZPlane':\n        outlineActors[0].setVisibility(false)\n        outlineActors[1].setVisibility(false)\n        outlineActors[2].setVisibility(true)\n        break\n    }\n  } else {\n    context.itkVtkView\n      .getSliceOutlineActors()\n      .forEach(a => a.setVisibility(false))\n  }\n  context.service.send('RENDER')\n}\n\nexport default toggleAnnotations\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/toggleAxes.js",
    "content": "function toggleAxes(context) {\n  context.itkVtkView.setEnableAxes(context.main.axesEnabled)\n  context.service.send('RENDER')\n}\n\nexport default toggleAxes\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/toggleCroppingPlanes.js",
    "content": "function toggleCroppingPlanes(context) {\n  const enabled = context.main.croppingPlanesEnabled\n  const prop = context.itkVtkView.getWidgetProp(context.main.croppingWidget)\n  // Only available after the widget manager has been initialized\n  if (prop) {\n    prop.setEnabled(enabled)\n    if (enabled) {\n      context.itkVtkView.getWidgetManager().enablePicking()\n\n      // Keep handles visible at all angles with fixed directional light in cinematic mode\n      prop.getRepresentations().forEach(rep => {\n        rep.getActors().forEach(actor => {\n          actor.getProperty().setAmbient(1)\n        })\n      })\n    }\n  }\n  context.main.croppingWidget.setVisibility(enabled)\n  context.service.send('RENDER')\n}\n\nexport default toggleCroppingPlanes\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/toggleRotate.js",
    "content": "function toggleRotate(context, event, actionMeta) {\n  context.itkVtkView.setRotate(context.main.rotateEnabled)\n}\n\nexport default toggleRotate\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/updateFps.js",
    "content": "import numericalSort from '../numericalSort'\n\nfunction updateFps(context, event) {\n  const proxy = context.images.representationProxy\n  let mapper = null\n  if (proxy) {\n    mapper = proxy.getMapper()\n    mapper.setAutoAdjustSampleDistances(false)\n  }\n\n  const interactor = context.renderWindow.getInteractor()\n  const requestId = `updateFps${performance.now().toString()}`\n\n  interactor.requestAnimation(requestId)\n  setTimeout(() => {\n    interactor.cancelAnimation(requestId)\n\n    const fps = interactor.getRecentAnimationFrameRate()\n\n    if (proxy) {\n      mapper.setAutoAdjustSampleDistances(true)\n    }\n\n    context.service.send({ type: 'FPS_UPDATED', data: fps })\n  }, 1100)\n}\n\nexport default updateFps\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/updateSlicingPlanes.js",
    "content": "import { computeCroppingPlanesBoundingBox } from './computeRenderedBounds'\n\nconst clampSlice = (old, fallback, { min, max }) =>\n  Math.max(min, Math.min(max, old ?? fallback))\n\nconst updateSlicingPlanes = ({\n  main,\n  images: { representationProxy },\n  service,\n}) => {\n  if (!representationProxy) return // no image loaded\n\n  const { slicingPlanes, croppingPlanes } = main\n  const savedSlicePositions = [\n    slicingPlanes.x.position,\n    slicingPlanes.y.position,\n    slicingPlanes.z.position,\n  ]\n\n  const volumeRep = representationProxy\n  const xSliceDomain = volumeRep.getPropertyDomainByName('xSlice')\n  const ySliceDomain = volumeRep.getPropertyDomainByName('ySlice')\n  const zSliceDomain = volumeRep.getPropertyDomainByName('zSlice')\n\n  // copy min max from loaded image data\n  Object.assign(slicingPlanes.x, xSliceDomain)\n  Object.assign(slicingPlanes.y, ySliceDomain)\n  Object.assign(slicingPlanes.z, zSliceDomain)\n\n  const [xMin, xMax, yMin, yMax, zMin, zMax] = computeCroppingPlanesBoundingBox(\n    croppingPlanes\n  )\n\n  slicingPlanes.x.min = Math.max(xMin, slicingPlanes.x.min)\n  slicingPlanes.x.max = Math.min(xMax, slicingPlanes.x.max)\n  slicingPlanes.y.max = Math.min(yMax, slicingPlanes.y.max)\n  slicingPlanes.y.min = Math.max(yMin, slicingPlanes.y.min)\n  slicingPlanes.z.min = Math.max(zMin, slicingPlanes.z.min)\n  slicingPlanes.z.max = Math.min(zMax, slicingPlanes.z.max)\n\n  service.send({\n    type: 'SLICING_PLANES_CHANGED',\n    data: slicingPlanes,\n  })\n\n  const xSlice = clampSlice(\n    savedSlicePositions?.[0],\n    volumeRep.getXSlice(),\n    slicingPlanes.x\n  )\n  service.send({ type: 'X_SLICE_CHANGED', data: xSlice })\n  const ySlice = clampSlice(\n    savedSlicePositions?.[1],\n    volumeRep.getYSlice(),\n    slicingPlanes.y\n  )\n  service.send({ type: 'Y_SLICE_CHANGED', data: ySlice })\n  const zSlice = clampSlice(\n    savedSlicePositions?.[2],\n    volumeRep.getZSlice(),\n    slicingPlanes.z\n  )\n  service.send({ type: 'Z_SLICE_CHANGED', data: zSlice })\n}\n\nexport default updateSlicingPlanes\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/viewModeVolume.js",
    "content": "function viewModeVolume(context) {\n  context.itkVtkView.setViewMode('Volume')\n\n  const volumeRep = context.images.representationProxy\n  if (volumeRep) {\n    const slicingPlanes = context.main.slicingPlanes\n    volumeRep.setXSliceVisibility(slicingPlanes.x.visible)\n    volumeRep.setYSliceVisibility(slicingPlanes.y.visible)\n    volumeRep.setZSliceVisibility(slicingPlanes.z.visible)\n    volumeRep.setVolumeVisibility(true)\n    const annotations = context.main.annotationsEnabled\n    const outlineActors = context.itkVtkView.getSliceOutlineActors()\n    if (annotations) {\n      outlineActors[0].setVisibility(slicingPlanes.x.visible)\n      outlineActors[1].setVisibility(slicingPlanes.y.visible)\n      outlineActors[2].setVisibility(slicingPlanes.z.visible)\n    }\n    context.service.send('RENDER')\n  }\n}\n\nexport default viewModeVolume\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/viewModeXPlane.js",
    "content": "function viewModeXPlane(context) {\n  context.itkVtkView.setViewMode('XPlane')\n\n  const volumeRep = context.images.representationProxy\n  if (volumeRep) {\n    volumeRep.setXSliceVisibility(true)\n    volumeRep.setYSliceVisibility(false)\n    volumeRep.setZSliceVisibility(false)\n    volumeRep.setVolumeVisibility(false)\n    const annotations = context.main.annotationsEnabled\n    const outlineActors = context.itkVtkView.getSliceOutlineActors()\n    if (annotations) {\n      outlineActors[0].setVisibility(true)\n      outlineActors[1].setVisibility(false)\n      outlineActors[2].setVisibility(false)\n    }\n    context.service.send('RENDER')\n  }\n}\n\nexport default viewModeXPlane\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/viewModeYPlane.js",
    "content": "function viewModeYPlane(context) {\n  context.itkVtkView.setViewMode('YPlane')\n\n  const volumeRep = context.images.representationProxy\n  if (volumeRep) {\n    volumeRep.setXSliceVisibility(false)\n    volumeRep.setYSliceVisibility(true)\n    volumeRep.setZSliceVisibility(false)\n    volumeRep.setVolumeVisibility(false)\n    const annotations = context.main.annotationsEnabled\n    const outlineActors = context.itkVtkView.getSliceOutlineActors()\n    if (annotations) {\n      outlineActors[0].setVisibility(false)\n      outlineActors[1].setVisibility(true)\n      outlineActors[2].setVisibility(false)\n    }\n    context.service.send('RENDER')\n  }\n}\n\nexport default viewModeYPlane\n"
  },
  {
    "path": "src/Rendering/VTKJS/Main/viewModeZPlane.js",
    "content": "function viewModeZPlane(context) {\n  context.itkVtkView.setViewMode('ZPlane')\n\n  const volumeRep = context.images.representationProxy\n  if (volumeRep) {\n    volumeRep.setXSliceVisibility(false)\n    volumeRep.setYSliceVisibility(false)\n    volumeRep.setZSliceVisibility(true)\n    volumeRep.setVolumeVisibility(false)\n    const annotations = context.main.annotationsEnabled\n    const outlineActors = context.itkVtkView.getSliceOutlineActors()\n    if (annotations) {\n      outlineActors[0].setVisibility(false)\n      outlineActors[1].setVisibility(false)\n      outlineActors[2].setVisibility(true)\n    }\n    context.service.send('RENDER')\n  }\n}\n\nexport default viewModeZPlane\n"
  },
  {
    "path": "src/Rendering/VTKJS/Widgets/DistanceWidget/DistanceWidget.js",
    "content": "import macro from 'vtk.js/Sources/macros'\nimport vtkLineWidget from 'vtk.js/Sources/Widgets/Widgets3D/LineWidget'\nimport vtkLineWidgetBehavior from 'vtk.js/Sources/Widgets/Widgets3D/LineWidget/behavior'\nimport stateGenerator from 'vtk.js/Sources/Widgets/Widgets3D/LineWidget/state'\n\n// ----------------------------------------------------------------------------\n// Factory\n// ----------------------------------------------------------------------------\n\nfunction DistanceWidget(publicAPI, model) {\n  model.classHierarchy.push('DistanceWidget')\n\n  // --- Widget Requirement ---------------------------------------------------\n\n  model.methodsToLink = [\n    ...(model.methodsToLink ?? []),\n    'circleProps',\n    'lineProps',\n    'textProps',\n    'text',\n    'textStateIndex',\n  ]\n  model.behavior = vtkLineWidgetBehavior\n  model.widgetState = stateGenerator()\n}\n\n// ----------------------------------------------------------------------------\n\nconst DEFAULT_VALUES = {}\n\n// ----------------------------------------------------------------------------\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  vtkLineWidget.extend(publicAPI, model, {\n    ...initialValues,\n    useCameraFocalPoint: true,\n  })\n\n  DistanceWidget(publicAPI, model)\n}\n\n// ----------------------------------------------------------------------------\n\nexport const newInstance = macro.newInstance(extend, 'DistanceWidget')\n\n// ----------------------------------------------------------------------------\n\nexport default { newInstance, extend }\n"
  },
  {
    "path": "src/Rendering/VTKJS/Widgets/DistanceWidget/state.js",
    "content": "import vtkStateBuilder from 'vtk.js/Sources/Widgets/Core/StateBuilder'\n\nexport default function generateState() {\n  return vtkStateBuilder\n    .createBuilder()\n    .addStateFromMixin({\n      labels: ['moveHandle'],\n      mixins: ['origin', 'color', 'scale1', 'visible', 'manipulator'],\n      name: 'moveHandle',\n      initialValues: {\n        scale1: 20,\n        visible: false,\n      },\n    })\n    .addDynamicMixinState({\n      labels: ['handles'],\n      mixins: ['origin', 'color', 'scale1', 'visible', 'manipulator'],\n      name: 'handle',\n      initialValues: {\n        scale1: 20,\n      },\n    })\n    .build()\n}\n"
  },
  {
    "path": "src/Rendering/VTKJS/Widgets/HandlesInPixelsImageCroppingWidget.js",
    "content": "import macro from 'vtk.js/Sources/macros'\nimport vtkImageCroppingWidget from 'vtk.js/Sources/Widgets/Widgets3D/ImageCroppingWidget'\nimport vtkSphereHandleRepresentation from 'vtk.js/Sources/Widgets/Representations/SphereHandleRepresentation'\nimport vtkCroppingOutlineRepresentation from 'vtk.js/Sources/Widgets/Representations/CroppingOutlineRepresentation'\n\nimport { ViewTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'\n\n// ----------------------------------------------------------------------------\n// Factory\n// ----------------------------------------------------------------------------\n\nfunction HandlesInPixelsImageCroppingWidget(publicAPI, model) {\n  model.classHierarchy.push('HandlesInPixelsImageCroppingWidget')\n\n  publicAPI.getRepresentationsForViewType = viewType => {\n    switch (viewType) {\n      case ViewTypes.DEFAULT:\n      case ViewTypes.GEOMETRY:\n      case ViewTypes.SLICE:\n      case ViewTypes.VOLUME:\n      default:\n        return [\n          // Describes constructing a vtkSphereHandleRepresentation, and every\n          // time the widget state updates, we will give the representation\n          // a list of all handle states (which have the label \"handles\").\n          {\n            builder: vtkSphereHandleRepresentation,\n            labels: ['handles'],\n            initialValues: {\n              scaleInPixels: true,\n            },\n          },\n          {\n            builder: vtkCroppingOutlineRepresentation,\n            // outline is defined by corner points\n            labels: ['corners'],\n          },\n        ]\n    }\n  }\n}\n\n// ----------------------------------------------------------------------------\n\nconst DEFAULT_VALUES = {}\n\n// ----------------------------------------------------------------------------\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  vtkImageCroppingWidget.extend(publicAPI, model, initialValues)\n\n  HandlesInPixelsImageCroppingWidget(publicAPI, model)\n}\n\n// ----------------------------------------------------------------------------\n\nexport const newInstance = macro.newInstance(\n  extend,\n  'HandlesInPixelsImageCroppingWidget'\n)\n\n// ----------------------------------------------------------------------------\n\nexport default { newInstance, extend }\n"
  },
  {
    "path": "src/Rendering/VTKJS/Widgets/createWidgets.js",
    "content": "function createWidgets(/*context, events*/) {}\n\nexport default createWidgets\n"
  },
  {
    "path": "src/Rendering/VTKJS/Widgets/toggleDistanceWidget.js",
    "content": "import DistanceWidget from './DistanceWidget/DistanceWidget'\n\nlet valueChangedSubscription\n\nfunction toggleDistanceWidget(context) {\n  const {\n    widgets: { distanceWidget },\n  } = context\n  const widgetManager = context.itkVtkView.getWidgetManager()\n  if (context.widgets.distanceEnabled) {\n    const distanceWidget = DistanceWidget.newInstance()\n    context.widgets.distanceWidget = distanceWidget\n    widgetManager.addWidget(distanceWidget)\n\n    valueChangedSubscription = distanceWidget\n      .getWidgetState()\n      .onModified(() => {\n        context.service.send({\n          type: 'DISTANCE_WIDGET_VALUE_CHANGED',\n          data: distanceWidget.getDistance().toFixed(3),\n        })\n      })\n\n    widgetManager.grabFocus(distanceWidget)\n\n    // image loaded, not just geometry?\n    if (context.images.representationProxy) {\n      // Avoid appearing under the x slice\n      const firstSlice = context.images.representationProxy.getActors()[0]\n      const xCoord = firstSlice.getBoundsForSlice()[0]\n      distanceWidget.getManipulator().setHandleOrigin([xCoord, 0, 0])\n    }\n  } else {\n    valueChangedSubscription.unsubscribe()\n    widgetManager.removeWidget(distanceWidget)\n    distanceWidget.delete()\n\n    context.service.send({\n      type: 'DISTANCE_WIDGET_VALUE_CHANGED',\n      data: 0,\n    })\n  }\n\n  context.service.send('RENDER')\n}\n\nexport default toggleDistanceWidget\n"
  },
  {
    "path": "src/Rendering/VTKJS/Widgets/widgetsRenderingMachineOptions.js",
    "content": "import createWidgets from './createWidgets'\nimport toggleDistanceWidget from './toggleDistanceWidget'\n\nconst widgetsRenderingMachineOptions = {\n  actions: {\n    createWidgets,\n\n    toggleDistanceWidget,\n  },\n}\n\nexport default widgetsRenderingMachineOptions\n"
  },
  {
    "path": "src/Rendering/VTKJS/cancelAnimation.js",
    "content": "function cancelAnimation(context, event) {\n  const identifier = event.data\n  context.renderWindow.getInteractor().cancelAnimation(identifier)\n}\n\nexport default cancelAnimation\n"
  },
  {
    "path": "src/Rendering/VTKJS/createRenderer.js",
    "content": "import vtkGestureCameraManipulator from 'vtk.js/Sources/Interaction/Manipulators/GestureCameraManipulator'\nimport createMainRenderer from './Main/createMainRenderer'\n\n// Load the rendering pieces we want to use (for both WebGL and WebGPU)\nimport 'vtk.js/Sources/Rendering/Profiles/Geometry'\nimport 'vtk.js/Sources/Rendering/Profiles/Glyph'\nimport 'vtk.js/Sources/Rendering/Profiles/Volume'\n\nfunction createRenderer(context) {\n  context.itkVtkView.setContainer(context.renderingViewContainers.get('volume'))\n  context.itkVtkView.setXyLowerLeft(context.xyLowerLeft)\n\n  createMainRenderer(context)\n\n  const interactor = context.itkVtkView.getInteractor()\n  interactor.onRenderEvent(() => context.service.send('POST_RENDER'))\n\n  const gestureManipulator = vtkGestureCameraManipulator.newInstance({\n    pinchEnabled: true,\n    rotateEnabled: true,\n    panEnabled: true,\n  })\n  context.itkVtkView\n    .getInteractorStyle2D()\n    .addGestureManipulator(gestureManipulator)\n  context.itkVtkView\n    .getInteractorStyle3D()\n    .addGestureManipulator(gestureManipulator)\n}\n\nexport default createRenderer\n"
  },
  {
    "path": "src/Rendering/VTKJS/numericalSort.js",
    "content": "function numericalSort(eltA, eltB) {\n  if (eltA < eltB) {\n    return -1\n  } else if (eltB < eltA) {\n    return 1\n  }\n  return 0\n}\n\nexport default numericalSort\n"
  },
  {
    "path": "src/Rendering/VTKJS/proxyManagerConfiguration.js",
    "content": "import vtkSourceProxy from 'vtk.js/Sources/Proxy/Core/SourceProxy'\nimport vtkGeometryRepresentationProxy from 'vtk.js/Sources/Proxy/Representations/GeometryRepresentationProxy'\nimport vtkVolumeRepresentationProxy from 'vtk.js/Sources/Proxy/Representations/VolumeRepresentationProxy'\nimport vtkSliceRepresentationProxy from 'vtk.js/Sources/Proxy/Representations/SliceRepresentationProxy'\nimport vtkLookupTableProxy from 'vtk.js/Sources/Proxy/Core/LookupTableProxy'\nimport vtkPiecewiseFunctionProxy from 'vtk.js/Sources/Proxy/Core/PiecewiseFunctionProxy'\nimport vtkPointSetRepresentationProxy from './vtk/PointSetRepresentationProxy'\n\nimport ItkVtkView from './vtk/ItkVtkViewProxy'\n\nconst commonInteractor = [\n  { type: 'pan', options: { button: 3 } }, // Pan on Right button drag\n  { type: 'pan', options: { button: 1, shift: true } }, // Pan on Shift + Left button drag\n  { type: 'zoom', options: { button: 1, control: true } }, // Zoom on Ctrl + Left button drag\n  { type: 'zoom', options: { dragEnabled: false, scrollEnabled: true } }, // Zoom on scroll\n]\n\nconst interactorStyle3D = commonInteractor.concat([\n  { type: 'rotate', options: { button: 1 } }, // Rotate on Left button drag\n])\n\nconst interactorStyle2D = commonInteractor.concat([\n  { type: 'pan', options: { button: 1 } }, // Pan on Left button drag\n])\n\nconst proxyManagerConfiguration = {\n  definitions: {\n    Proxy: {\n      LookupTable: {\n        class: vtkLookupTableProxy,\n      },\n      PiecewiseFunction: {\n        class: vtkPiecewiseFunctionProxy,\n      },\n    },\n    Sources: {\n      TrivialProducer: {\n        class: vtkSourceProxy,\n        options: {},\n      },\n    },\n    Representations: {\n      Geometry: {\n        class: vtkGeometryRepresentationProxy,\n        options: {},\n      },\n      Slice: {\n        class: vtkSliceRepresentationProxy,\n        options: {},\n      },\n      Volume: {\n        class: vtkVolumeRepresentationProxy,\n        options: {},\n      },\n      PointSet: {\n        class: vtkPointSetRepresentationProxy,\n        options: {},\n      },\n    },\n    Views: {\n      ItkVtkView: {\n        class: ItkVtkView,\n        options: {\n          axis: 1, // Y\n          orientation: -1, // Y- (A)\n          viewUp: [0, 0, 1], // Z+ (S)\n          useParallelRendering: false,\n        },\n        props: {\n          presetToInteractor3D: interactorStyle3D,\n          presetToInteractor2D: interactorStyle2D,\n        },\n      },\n    },\n  },\n  representations: {\n    ItkVtkView: {\n      vtkPolyData: { name: 'Geometry' },\n      vtkImageData: { name: 'Volume' },\n    },\n  },\n}\n\nexport default proxyManagerConfiguration\n"
  },
  {
    "path": "src/Rendering/VTKJS/render.js",
    "content": "function render(context) {\n  if (!context.renderWindow.getInteractor().isAnimating()) {\n    context.renderWindow.render()\n  }\n}\n\nexport default render\n"
  },
  {
    "path": "src/Rendering/VTKJS/requestAnimation.js",
    "content": "function requestAnimation(context, event) {\n  const identifier = event.data\n  context.renderWindow.getInteractor().requestAnimation(identifier)\n}\n\nexport default requestAnimation\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/AxesLabelsWidget/behavior.js",
    "content": "export default function widgetBehavior(publicAPI, model) {\n  model.classHierarchy.push('vtkAxesLabelsWidgetProp')\n}\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/AxesLabelsWidget/index.js",
    "content": "import macro from 'vtk.js/Sources/macros'\nimport vtkAbstractWidgetFactory from 'vtk.js/Sources/Widgets/Core/AbstractWidgetFactory'\nimport vtkPolyLineRepresentation from 'vtk.js/Sources/Widgets/Representations/PolyLineRepresentation'\nimport vtkSVGMarkerTextRepresentation from '../SVGMarkerTextRepresentation'\n\nimport widgetBehavior from './behavior'\nimport stateGenerator from './state'\n\nimport { ViewTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'\n\n// ----------------------------------------------------------------------------\n// Factory\n// ----------------------------------------------------------------------------\n\nfunction vtkAxesLabelsWidget(publicAPI, model) {\n  model.classHierarchy.push('vtkAxesLabelsWidget')\n\n  // --- Widget Requirement ---------------------------------------------------\n\n  model.methodsToLink = ['circleProps', 'textProps', 'closePolyLine']\n  model.behavior = widgetBehavior\n  model.widgetState = stateGenerator()\n\n  publicAPI.getRepresentationsForViewType = viewType => {\n    switch (viewType) {\n      case ViewTypes.DEFAULT:\n      case ViewTypes.GEOMETRY:\n      case ViewTypes.SLICE:\n      case ViewTypes.VOLUME:\n      default:\n        return [\n          { builder: vtkSVGMarkerTextRepresentation, labels: ['handles'] },\n          {\n            builder: vtkPolyLineRepresentation,\n            labels: ['handles'],\n          },\n        ]\n    }\n  }\n\n  // --------------------------------------------------------------------------\n  // initialization\n  // --------------------------------------------------------------------------\n\n  model.widgetState.onBoundsChange(bounds => {\n    const center = [\n      (bounds[0] + bounds[1]) * 0.5,\n      (bounds[2] + bounds[3]) * 0.5,\n      (bounds[4] + bounds[5]) * 0.5,\n    ]\n  })\n}\n\n// ----------------------------------------------------------------------------\n\nconst DEFAULT_VALUES = {\n  manipulator: null,\n}\n\n// ----------------------------------------------------------------------------\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  vtkAbstractWidgetFactory.extend(publicAPI, model, initialValues)\n\n  vtkAxesLabelsWidget(publicAPI, model)\n}\n\n// ----------------------------------------------------------------------------\n\nexport const newInstance = macro.newInstance(extend, 'vtkAxesLabelsWidget')\n\n// ----------------------------------------------------------------------------\n\nexport default { newInstance, extend }\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/AxesLabelsWidget/state.js",
    "content": "import vtkStateBuilder from 'vtk.js/Sources/Widgets/Core/StateBuilder'\n\nexport default function generateState() {\n  return vtkStateBuilder\n    .createBuilder()\n    .addDynamicMixinState({\n      labels: ['handles'],\n      mixins: ['origin', 'color', 'text'],\n      name: 'handle',\n      initialValues: {\n        origin: [-1, -1, -1],\n      },\n    })\n    .build()\n}\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/ItkVtkViewProxy.js",
    "content": "import macro from 'vtk.js/Sources/macros'\n\nimport vtkViewProxy from 'vtk.js/Sources/Proxy/Core/ViewProxy'\nimport vtkPointPicker from 'vtk.js/Sources/Rendering/Core/PointPicker'\nimport vtkActor from 'vtk.js/Sources/Rendering/Core/Actor'\nimport vtkCubeSource from 'vtk.js/Sources/Filters/Sources/CubeSource'\nimport vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper'\nimport vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate'\nimport vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData'\nimport vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox'\nimport vtkAxesLabelsWidget from './AxesLabelsWidget'\n\nimport WidgetManagerPickWhileAnimating from './WidgetManagerPickWhileAnimating'\nimport vtkSliceOutlineFilter from './SliceOutlineFilter'\nimport vtkPoints from 'vtk.js/Sources/Common/Core/Points'\nimport vtkCellArray from 'vtk.js/Sources/Common/Core/CellArray'\n\nexport const VOLUME_DIFFUSE_DEFAULT = 1.0\nexport const VOLUME_AMBIENT_DEFAULT = 0.4\n\nconst CursorCornerAnnotation =\n  '<table class=\"corner-annotation\" style=\"margin-left: auto; margin-right: 6px; margin-top: 2em;\"><tr><td style=\"margin-left: auto; margin-right: 0;\">Index:</td><td>${iIndex},</td><td>${jIndex},</td><td>${kIndex}</td></tr><tr><td style=\"margin-left: auto; margin-right: 0;\">Position:</td><td>${xPosition},</td><td>${yPosition},</td><td>${zPosition}</td></tr><tr><td style=\"margin-left: auto; margin-right: 0;\"\">Value:</td><td style=\"text-align:center;\" colspan=\"3\">${value}</td></tr><tr ${annotationLabelStyle}><td style=\"margin-left: auto; margin-right: 0;\">Label:</td><td style=\"text-align:center;\" colspan=\"3\">${annotation}</td></tr></table>'\n\nconst { vtkErrorMacro } = macro\n\nfunction numberToText(number, precision) {\n  let text = Number.parseFloat(number).toPrecision(precision)\n  if (number > 1) {\n    text = Number.parseInt(Number.parseFloat(text))\n  }\n  return text\n}\n\n// ----------------------------------------------------------------------------\n// ItkVtkViewProxy methods\n// ----------------------------------------------------------------------------\n\nfunction ItkVtkViewProxy(publicAPI, model) {\n  // Set our className\n  model.classHierarchy.push('ItkVtkViewProxy')\n\n  // Private --------------------------------------------------------------------\n  //\n  function updateAxesVisibility() {\n    if (!model.axesOriginWidget) {\n      return\n    }\n    if (!model.enableAxes) {\n      model.axesGridActor.setVisibility(false)\n      model.axesOriginWidget.setVisibility(false)\n      model.axesXWidget.setVisibility(false)\n      model.axesXActor.setVisibility(false)\n      model.axesYWidget.setVisibility(false)\n      model.axesYActor.setVisibility(false)\n      model.axesZWidget.setVisibility(false)\n      model.axesZActor.setVisibility(false)\n      return\n    }\n\n    model.axesOriginWidget.setVisibility(true)\n    switch (model.viewMode) {\n      case 'XPlane':\n        model.axesGridActor.setVisibility(false)\n        model.axesOriginHandle.setText(model.axesOriginXText)\n        model.axesYHandle.setText(model.axesYXText)\n        model.axesZHandle.setText(model.axesZXText)\n        model.axesXWidget.setVisibility(false)\n        model.axesXActor.setVisibility(false)\n        model.axesYWidget.setVisibility(true)\n        model.axesYActor.setVisibility(true)\n        model.axesZWidget.setVisibility(true)\n        model.axesZActor.setVisibility(true)\n        break\n      case 'YPlane':\n        model.axesGridActor.setVisibility(false)\n        model.axesOriginHandle.setText(model.axesOriginYText)\n        model.axesXHandle.setText(model.axesXYText)\n        model.axesZHandle.setText(model.axesZYText)\n        model.axesXWidget.setVisibility(true)\n        model.axesXActor.setVisibility(true)\n        model.axesYWidget.setVisibility(false)\n        model.axesYActor.setVisibility(false)\n        model.axesZWidget.setVisibility(true)\n        model.axesZActor.setVisibility(true)\n        break\n      case 'ZPlane':\n        model.axesGridActor.setVisibility(false)\n        model.axesOriginHandle.setText(model.axesOriginZText)\n        model.axesXHandle.setText(model.axesXZText)\n        model.axesYHandle.setText(model.axesYZText)\n        model.axesXWidget.setVisibility(true)\n        model.axesXActor.setVisibility(true)\n        model.axesYWidget.setVisibility(true)\n        model.axesYActor.setVisibility(true)\n        model.axesZWidget.setVisibility(false)\n        model.axesZActor.setVisibility(false)\n        break\n      case 'Volume':\n        model.axesGridActor.setVisibility(true)\n        model.axesOriginHandle.setText(model.axesOriginVText)\n        model.axesXHandle.setText(model.axesXVText)\n        model.axesYHandle.setText(model.axesYVText)\n        model.axesZHandle.setText(model.axesZVText)\n        model.axesXWidget.setVisibility(true)\n        model.axesXActor.setVisibility(true)\n        model.axesYWidget.setVisibility(true)\n        model.axesYActor.setVisibility(true)\n        model.axesZWidget.setVisibility(true)\n        model.axesZActor.setVisibility(true)\n        break\n      default:\n        vtkErrorMacro('Unexpected view mode')\n    }\n  }\n\n  function setVisualizationMode(axisIndex) {\n    if (model.enableAxes) {\n      updateAxesVisibility()\n    }\n\n    if (axisIndex === -1) {\n      // volume rendering\n      model.interactor.setInteractorStyle(model.interactorStyle3D)\n      if (model.rotate && !model.rotateAnimationCallback) {\n        model.rotateAnimationCallback = model.interactor.onAnimation(\n          rotateAzimuth\n        )\n        model.interactor.requestAnimation('itk-vtk-view-rotate')\n      }\n      if (model.volumeCameraState) {\n        model.camera.setFocalPoint(...model.volumeCameraState.focalPoint)\n        model.camera.setPosition(...model.volumeCameraState.position)\n        model.camera.setViewUp(...model.volumeCameraState.viewUp)\n        model.camera.setViewAngle(model.volumeCameraState.viewAngle)\n        model.camera.setParallelScale(model.volumeCameraState.parallelScale)\n        model.camera.setPhysicalTranslation(\n          ...model.volumeCameraState.physicalTranslation\n        )\n      }\n      model.camera.setParallelProjection(false)\n      if (model.volumeRepresentation) {\n        if (model.viewPlanes) {\n          publicAPI.setCornerAnnotation('ne', model.neCornerAnnotation)\n        } else {\n          publicAPI.setCornerAnnotation('ne', '')\n        }\n        if (model.imageVisibility) {\n          model.volumeRepresentation.setVolumeVisibility(true)\n        }\n      }\n\n      model.croppingWidget.setFaceHandlesEnabled(true)\n      model.croppingWidget.setCornerHandlesEnabled(false)\n    } else {\n      // slice views\n      model.camera.setParallelProjection(true)\n      publicAPI.setCornerAnnotation('ne', model.neCornerAnnotation)\n      model.interactor.setInteractorStyle(model.interactorStyle2D)\n      if (model.rotate && !!model.rotateAnimationCallback) {\n        model.interactor.cancelAnimation('itk-vtk-view-rotate')\n        model.rotateAnimationCallback.unsubscribe()\n        model.rotateAnimationCallback = null\n      }\n      if (model.volumeRepresentation) {\n        model.volumeRepresentation.setVolumeVisibility(false)\n        model.volumeRepresentation.getActors().forEach((actor, index) => {\n          if (index === axisIndex) {\n            model.imageVisibility && actor.setVisibility(true)\n          } else {\n            actor.setVisibility(false)\n          }\n        })\n      }\n\n      // Disable to avoid Warning: Resetting view-up since view plane normal is parallel\n      const previousState = model.orientationWidget.getEnabled()\n      model.orientationWidget.setEnabled(false)\n\n      switch (axisIndex) {\n        case 0:\n          publicAPI.updateOrientation(0, 1, [0, 0, 1])\n          break\n        case 1:\n          publicAPI.updateOrientation(1, -1, [0, 0, 1])\n          break\n        case 2:\n          if (model.xyLowerLeft) {\n            publicAPI.updateOrientation(2, 1, [0, 1, 0])\n          } else {\n            publicAPI.updateOrientation(2, -1, [0, -1, 0])\n          }\n          break\n        default:\n          vtkErrorMacro('Unexpected view mode')\n      }\n\n      model.orientationWidget.setEnabled(previousState)\n\n      model.croppingWidget.setFaceHandlesEnabled(false)\n      model.croppingWidget.setCornerHandlesEnabled(true)\n    }\n  }\n\n  function getAnnotationText(value) {\n    const labelValue = value[model.labelIndex]\n    if (model.labelNames !== null && model.labelNames.has(labelValue)) {\n      return model.labelNames.get(labelValue)\n    }\n    return labelValue\n  }\n\n  function getAnnotationLabelStyle() {\n    return model.labelIndex === null ? 'style=\"display: none;\"' : ''\n  }\n\n  function updateAnnotations(callData) {\n    const renderPosition = callData.position\n    model.annotationPicker.pick(\n      [renderPosition.x, renderPosition.y, 0.0],\n      callData.pokedRenderer\n    )\n    const ijk = model.annotationPicker.getPointIJK()\n    if (model.volumeRepresentation) {\n      publicAPI.setCornerAnnotation('ne', model.neCornerAnnotation)\n      const imageData = model.volumeRepresentation.getInputDataSet()\n      const size = imageData.getDimensions()\n      const scalarData = imageData.getPointData().getScalars()\n      const fusedValue = scalarData.getTuple(\n        size[0] * size[1] * ijk[2] + size[0] * ijk[1] + ijk[0]\n      )\n      const annotation = getAnnotationText(fusedValue)\n      const worldPositions = model.annotationPicker.getPickedPositions()\n      if (ijk.length > 0 && worldPositions.length > 0) {\n        const worldPosition = worldPositions[0]\n        model.dataProbeCubeSource.setCenter(worldPosition)\n        model.dataProbeActor.setVisibility(true)\n        model.dataProbeFrameActor.setVisibility(true)\n        model.lastPickedValues = {\n          iIndex: ijk[0],\n          jIndex: ijk[1],\n          kIndex: ijk[2],\n          xPosition: Number.parseFloat(worldPosition[0]).toPrecision(4),\n          yPosition: Number.parseFloat(worldPosition[1]).toPrecision(4),\n          zPosition: Number.parseFloat(worldPosition[2]).toPrecision(4),\n          value:\n            model.labelIndex === null\n              ? fusedValue\n              : fusedValue.slice(0, model.labelIndex),\n          label:\n            model.labelIndex === null ? null : fusedValue[model.labelIndex],\n          annotation,\n          annotationLabelStyle: getAnnotationLabelStyle(),\n        }\n        publicAPI.updateCornerAnnotation(model.lastPickedValues)\n      } else {\n        publicAPI.setCornerAnnotation('ne', '')\n        model.dataProbeActor.setVisibility(false)\n        model.dataProbeFrameActor.setVisibility(false)\n        model.lastPickedValues = null\n      }\n    } else {\n      model.lastPickedValues = null\n    }\n  }\n\n  function updateAxes() {\n    vtkBoundingBox.reset(model.axesBoundingBox)\n    model.representations.forEach(representation => {\n      vtkBoundingBox.addBounds(\n        model.axesBoundingBox,\n        ...representation.getBounds()\n      )\n    })\n    const minPoint = vtkBoundingBox.getMinPoint(model.axesBoundingBox)\n    const maxPoint = vtkBoundingBox.getMaxPoint(model.axesBoundingBox)\n    const axisTicks = model.numberOfAxisTicks\n    const xDelta = (maxPoint[0] - minPoint[0]) / (axisTicks - 1)\n    const yDelta = (maxPoint[1] - minPoint[1]) / (axisTicks - 1)\n    const zDelta = (maxPoint[2] - minPoint[2]) / (axisTicks - 1)\n\n    const axesPoints = new Float32Array(axisTicks * axisTicks * 3 * 3)\n    let offset = 0\n    // x-y plane\n    for (let i = 0; i < axisTicks; i++) {\n      for (let j = 0; j < axisTicks; j++) {\n        axesPoints[offset] = minPoint[0] + i * xDelta\n        axesPoints[offset + 1] = minPoint[1] + j * yDelta\n        axesPoints[offset + 2] = minPoint[2]\n        offset += 3\n      }\n    }\n    // y-z plane\n    for (let i = 0; i < axisTicks; i++) {\n      for (let j = 0; j < axisTicks; j++) {\n        axesPoints[offset] = minPoint[0]\n        axesPoints[offset + 1] = minPoint[1] + i * yDelta\n        axesPoints[offset + 2] = minPoint[2] + j * zDelta\n        offset += 3\n      }\n    }\n    // x-z plane\n    for (let i = 0; i < axisTicks; i++) {\n      for (let j = 0; j < axisTicks; j++) {\n        axesPoints[offset] = minPoint[0] + i * xDelta\n        axesPoints[offset + 1] = minPoint[1]\n        axesPoints[offset + 2] = minPoint[2] + j * zDelta\n        offset += 3\n      }\n    }\n\n    function addLines(linesArray, offset, axisTicks) {\n      for (let i = 0; i < axisTicks - 1; i++) {\n        for (let j = 0; j < axisTicks - 1; j++) {\n          const start = i * axisTicks + j + offset\n          linesArray.push(\n            5,\n            start,\n            start + 1,\n            (i + 1) * axisTicks + j + 1 + offset,\n            (i + 1) * axisTicks + j + offset,\n            start\n          )\n        }\n      }\n      return linesArray\n    }\n\n    const axesLines = []\n    // x-y plane\n    offset = 0\n    addLines(axesLines, offset, axisTicks)\n    // y-z plane\n    offset += axisTicks * axisTicks\n    addLines(axesLines, offset, axisTicks)\n    // x-z plane\n    offset += axisTicks * axisTicks\n    addLines(axesLines, offset, axisTicks)\n\n    const verts = new Uint32Array(axesPoints.length)\n    verts.fill(1)\n    for (let i = 0; i < axesPoints.length; i++) {\n      verts[i * 2 + 1] = i\n    }\n    model.axesPolyData.getPoints().setData(axesPoints, 3)\n    model.axesPolyData.getVerts().setData(verts)\n    model.axesPolyData.getLines().setData(new Uint32Array(axesLines))\n\n    const axesNames = Object.fromEntries(\n      ['x', 'y', 'z'].map(axis => [\n        axis,\n        model.axesNames?.get(axis) ?? axis.toUpperCase(),\n      ])\n    )\n\n    const minPointText = minPoint.map(point => numberToText(point, 2))\n    const maxPointText = maxPoint.map(point => numberToText(point, 2))\n    model.axesOriginHandle.setOrigin(minPoint)\n    model.axesOriginXText = `Origin: ${minPointText[1]}, ${minPointText[2]}`\n    model.axesOriginYText = `Origin: ${minPointText[0]}, ${minPointText[2]}`\n    model.axesOriginZText = `Origin: ${minPointText[0]}, ${minPointText[1]}`\n    model.axesOriginVText = `Origin: ${minPointText[0]}, ${minPointText[1]}, ${minPointText[2]}`\n    model.axesOriginHandle.setText(model.axesOriginVText)\n\n    model.axesXOriginHandle.setOrigin(minPoint)\n    model.axesXOriginHandle.setText('')\n    model.axesXHandle.setOrigin([maxPoint[0], minPoint[1], minPoint[2]])\n    model.axesXYText = `${axesNames.x}: ${maxPointText[0]}, ${axesNames.z}: ${minPointText[2]}`\n    model.axesXZText = `${axesNames.x}: ${maxPointText[0]}, ${axesNames.y}: ${minPointText[1]}`\n    model.axesXVText = `${axesNames.x}: ${maxPointText[0]}, ${minPointText[1]}, ${minPointText[2]}`\n    model.axesXHandle.setText(model.axesXVText)\n\n    model.axesYOriginHandle.setOrigin(minPoint)\n    model.axesYOriginHandle.setText('')\n    model.axesYHandle.setOrigin([minPoint[0], maxPoint[1], minPoint[2]])\n    model.axesYXText = `${axesNames.y}: ${maxPointText[1]}, ${axesNames.z}: ${minPointText[2]}`\n    model.axesYZText = `${axesNames.x}: ${minPointText[0]}, ${axesNames.y}: ${maxPointText[1]}`\n    model.axesYVText = `${axesNames.y}: ${minPointText[0]}, ${maxPointText[1]}, ${minPointText[2]}`\n    model.axesYHandle.setText(model.axesYVText)\n\n    model.axesZOriginHandle.setOrigin(minPoint)\n    model.axesZOriginHandle.setText('')\n    model.axesZHandle.setOrigin([minPoint[0], minPoint[1], maxPoint[2]])\n    model.axesZXText = `${axesNames.y}: ${minPointText[1]}, ${axesNames.z}: ${maxPointText[2]}`\n    model.axesZYText = `${axesNames.x}: ${minPointText[0]}, ${axesNames.z}: ${maxPointText[2]}`\n    model.axesZVText = `${axesNames.z}: ${minPointText[0]}, ${minPointText[1]}, ${maxPointText[2]}`\n    model.axesZHandle.setText(model.axesZVText)\n  }\n\n  publicAPI.setAxesNames = axes => {\n    model.axesNames = axes\n    updateAxes()\n  }\n\n  // Setup --------------------------------------------------------------------\n\n  publicAPI.setCornerAnnotation('ne', '')\n  publicAPI.updateCornerAnnotation({\n    iIndex: '&nbsp;N/A',\n    jIndex: '&nbsp;N/A',\n    kIndex: '&nbsp;N/A',\n    xPosition: '&nbsp;N/A',\n    yPosition: '&nbsp;N/A',\n    zPosition: '&nbsp;N/A',\n    value: 'N/A&nbsp;',\n    annotation: 'N/A&nbsp;',\n    annotationLabelStyle: getAnnotationLabelStyle(),\n  })\n  publicAPI.setAnnotationOpacity(0.0)\n  model.annotationPicker = vtkPointPicker.newInstance()\n  model.annotationPicker.setPickFromList(1)\n  model.annotationPicker.initializePickList()\n  model.interactor.onLeftButtonPress(() => {\n    if (model.clickCallback && model.lastPickedValues) {\n      model.clickCallback(model.lastPickedValues)\n    }\n  })\n  model.interactor.onMouseMove(event => {\n    updateAnnotations(event)\n  })\n  model.interactor.onStartMouseMove(() => {\n    if (model.viewMode !== 'Volume' || model.viewPlanes) {\n      publicAPI.getInteractor().requestAnimation('annotationMouseMove')\n    }\n  })\n  model.interactor.onEndMouseMove(() => {\n    if (model.viewMode !== 'Volume' || model.viewPlanes) {\n      publicAPI.getInteractor().cancelAnimation('annotationMouseMove')\n    }\n  })\n  model.interactor.onEndMouseWheel(() => {\n    updateDataProbeSize()\n  })\n\n  // use the same color map in the planes\n  // colormap changes with window / level\n  // window / level changes piecewise =jk\n\n  model.dataProbeCubeSource = vtkCubeSource.newInstance()\n  model.dataProbeMapper = vtkMapper.newInstance()\n  model.dataProbeMapper.setInputConnection(\n    model.dataProbeCubeSource.getOutputPort()\n  )\n  model.dataProbeActor = vtkActor.newInstance()\n  model.dataProbeActor.setMapper(model.dataProbeMapper)\n  model.dataProbeFrameActor = vtkActor.newInstance()\n  model.dataProbeFrameActor.setMapper(model.dataProbeMapper)\n  model.renderer.addActor(model.dataProbeActor)\n  const dataProbeProperty = model.dataProbeActor.getProperty()\n  dataProbeProperty.setLighting(false)\n  dataProbeProperty.setColor(1.0, 1.0, 1.0)\n  const dataProbeFrameProperty = model.dataProbeFrameActor.getProperty()\n  dataProbeFrameProperty.setRepresentation(1)\n  dataProbeFrameProperty.setColor(0.0, 0.0, 0.0)\n  model.renderer.addActor(model.dataProbeFrameActor)\n  model.dataProbeActor.setVisibility(false)\n  model.dataProbeFrameActor.setVisibility(false)\n  model.dataProbeActor.setPickable(false)\n  model.dataProbeFrameActor.setPickable(false)\n\n  function updateDataProbeSize() {\n    if (model.volumeRepresentation) {\n      const image = model.volumeRepresentation.getInputDataSet()\n      const spacing = image.getSpacing()\n      let viewableScale = null\n      if (model.camera.getParallelProjection()) {\n        viewableScale = model.camera.getParallelScale() / 40\n      } else {\n        const distance = model.camera.getDistance()\n        // Heuristic assuming a constant view angle\n        viewableScale = distance / 150\n      }\n      model.dataProbeCubeSource.setXLength(Math.max(spacing[0], viewableScale))\n      model.dataProbeCubeSource.setYLength(Math.max(spacing[1], viewableScale))\n      model.dataProbeCubeSource.setZLength(Math.max(spacing[2], viewableScale))\n    }\n  }\n\n  model.camera.pitch(-30.0)\n  model.camera.azimuth(30.0)\n\n  model.xSliceOutliner = vtkSliceOutlineFilter.newInstance()\n  model.xSliceMapper = vtkMapper.newInstance()\n  model.xSliceMapper.setInputConnection(model.xSliceOutliner.getOutputPort())\n  model.xSliceActor = vtkActor.newInstance()\n  model.xSliceActor.getProperty().setColor([0.94, 0.32, 0.31])\n  model.xSliceActor.setMapper(model.xSliceMapper)\n  model.xSliceActor.setVisibility(false)\n  model.ySliceOutliner = vtkSliceOutlineFilter.newInstance()\n  model.ySliceMapper = vtkMapper.newInstance()\n  model.ySliceMapper.setInputConnection(model.ySliceOutliner.getOutputPort())\n  model.ySliceActor = vtkActor.newInstance()\n  model.ySliceActor.getProperty().setColor([0.99, 0.84, 0.21])\n  model.ySliceActor.setMapper(model.ySliceMapper)\n  model.ySliceActor.setVisibility(false)\n  model.zSliceOutliner = vtkSliceOutlineFilter.newInstance()\n  model.zSliceMapper = vtkMapper.newInstance()\n  model.zSliceMapper.setInputConnection(model.zSliceOutliner.getOutputPort())\n  model.zSliceActor = vtkActor.newInstance()\n  model.zSliceActor.getProperty().setColor([0.3, 0.67, 0.31])\n  model.zSliceActor.setMapper(model.zSliceMapper)\n  model.zSliceActor.setVisibility(false)\n\n  publicAPI.getSliceOutlineActors = () => {\n    return [model.xSliceActor, model.ySliceActor, model.zSliceActor]\n  }\n\n  publicAPI.getSliceOutlineFilters = () => {\n    return [model.zSliceOutliner, model.zSliceOutliner, model.zSliceOutliner]\n  }\n\n  // Must be called before the initial render.\n  publicAPI.addWidgetToRegister = widget => {\n    model.widgetsToRegister.push(widget)\n  }\n\n  publicAPI.addCroppingWidget = widget => {\n    model.croppingWidget = widget\n    publicAPI.addWidgetToRegister(widget)\n  }\n\n  publicAPI.getWidgetProp = widget => {\n    return model.widgetProps.get(widget)\n  }\n\n  model.orientationWidget.setViewportSize(0.1)\n  const superRenderLater = publicAPI.renderLater\n  publicAPI.renderLater = () => {\n    superRenderLater()\n    if (!model.widgetManagerInitialized) {\n      // Needs to come after initial render\n      model.widgetManager.setRenderer(model.renderer)\n      model.widgetManager.disablePicking()\n      model.widgetsToRegister.forEach(widget => {\n        model.widgetProps.set(widget, model.widgetManager.addWidget(widget))\n      })\n      model.axesOriginWidget = model.widgetProps.get(model.axesOriginLabel)\n      model.axesXWidget = model.widgetProps.get(model.axesXLabels)\n      model.axesYWidget = model.widgetProps.get(model.axesYLabels)\n      model.axesZWidget = model.widgetProps.get(model.axesZLabels)\n      const color =\n        model.axesGridActor.getProperty().getColor()[0] === 0.0\n          ? 'black'\n          : 'white'\n      model.axesOriginWidget.setCircleProps({\n        r: model.axesCircleRadius,\n        stroke: color,\n        fill: color,\n      })\n      model.axesOriginWidget.setTextProps({\n        fill: color,\n        dx: -10 * model.axesTextOffset,\n        dy: 2 * model.axesTextOffset,\n      })\n      model.axesXWidget.setCircleProps({\n        r: model.axesCircleRadius,\n        stroke: color,\n        fill: color,\n      })\n      model.axesXWidget.setTextProps({\n        fill: color,\n        dx: model.axesTextOffset,\n        dy: 2 * model.axesTextOffset,\n      })\n      model.axesYWidget.setCircleProps({\n        r: model.axesCircleRadius,\n        stroke: color,\n        fill: color,\n      })\n      model.axesYWidget.setTextProps({\n        fill: color,\n        dx: model.axesTextOffset,\n        dy: 2 * model.axesTextOffset,\n      })\n      model.axesZWidget.setCircleProps({\n        r: model.axesCircleRadius,\n        stroke: color,\n        fill: color,\n      })\n      model.axesZWidget.setTextProps({\n        fill: color,\n        dx: model.axesTextOffset,\n        dy: -1 * model.axesTextOffset,\n      })\n      let widgetState = model.axesOriginLabel.getWidgetState()\n      model.axesOriginHandle = widgetState.addHandle()\n      widgetState = model.axesXLabels.getWidgetState()\n      model.axesXOriginHandle = widgetState.addHandle()\n      model.axesXHandle = widgetState.addHandle()\n      model.axesXActor = model.axesXWidget\n        .getRepresentations()[1]\n        .getActors()[0]\n      const rgbColor = model.axesGridActor.getProperty().getColor()\n      model.axesXActor.getProperty().setColor(...rgbColor)\n      widgetState = model.axesYLabels.getWidgetState()\n      model.axesYOriginHandle = widgetState.addHandle()\n      model.axesYHandle = widgetState.addHandle()\n      model.axesYActor = model.axesYWidget\n        .getRepresentations()[1]\n        .getActors()[0]\n      model.axesYActor.getProperty().setColor(...rgbColor)\n      widgetState = model.axesZLabels.getWidgetState()\n      model.axesZOriginHandle = widgetState.addHandle()\n      model.axesZHandle = widgetState.addHandle()\n      model.axesZActor = model.axesZWidget\n        .getRepresentations()[1]\n        .getActors()[0]\n      model.axesZActor.getProperty().setColor(...rgbColor)\n      model.widgetManagerInitialized = true\n\n      updateAxes()\n      updateAxesVisibility()\n\n      if (model.widgetManagerInitializedCallback) {\n        model.widgetManagerInitializedCallback()\n      }\n    }\n    updateScaleBar()\n  }\n\n  publicAPI.setWidgetManagerInitializedCallback = callback => {\n    model.widgetManagerInitializedCallback = callback\n  }\n\n  model.scaleBarCanvas = document.createElement('canvas')\n  model.scaleBarCanvas.style.position = 'absolute'\n  model.scaleBarCanvas.style.right = '3em'\n  model.scaleBarCanvas.style.top = '12px'\n  model.scaleBarCanvas.style.width = '100px'\n  model.scaleBarCanvas.style.height = '30px'\n  model.scaleBarCanvas.width = 100 * window.devicePixelRatio\n  model.scaleBarCanvas.height = 30 * window.devicePixelRatio\n  model.scaleBarCenterCoord = vtkCoordinate.newInstance()\n  model.scaleBarCenterCoord.setRenderer(model.renderer)\n  model.scaleBarCenterCoord.setCoordinateSystemToNormalizedViewport()\n  model.scaleBarCenterCoord.setValue(0.5, 0.5)\n  model.scaleBarCoordWidth = vtkCoordinate.newInstance()\n  model.scaleBarCoordWidth.setReferenceCoordinate(model.scaleBarCenterCoord)\n  model.scaleBarCoordWidth.setCoordinateSystemToViewport()\n  model.scaleBarCoordWidth.setRenderer(model.renderer)\n  model.scaleBarCoordWidth.setValue(model.scaleBarCanvas.width, 0)\n  function updateScaleBar() {\n    const devicePixelRatio = window.devicePixelRatio || 1\n    const scaleBarCtx = model.scaleBarCanvas.getContext('2d')\n\n    const dims = {\n      width: model.scaleBarCanvas.clientWidth * devicePixelRatio,\n      height: model.scaleBarCanvas.clientHeight * devicePixelRatio,\n    }\n\n    scaleBarCtx.clearRect(0, 0, dims.width, dims.height)\n    scaleBarCtx.fillStyle = model.cornerAnnotation.getAnnotationContainer().style.color\n    scaleBarCtx.fillRect(0, 0, dims.width, 2 * devicePixelRatio)\n\n    // try catch block to work around Firefox bug https://bugzilla.mozilla.org/show_bug.cgi?id=941146\n    try {\n      scaleBarCtx.font = `${16 * devicePixelRatio}px arial`\n      scaleBarCtx.textAlign = 'center'\n      scaleBarCtx.textBaseline = 'top'\n      model.scaleBarCoordWidth.setValue(dims.width, 0)\n      const cw = model.scaleBarCoordWidth.getComputedWorldValue()\n      const cc = model.scaleBarCenterCoord.getComputedWorldValue()\n      const length = Math.sqrt(\n        (cw[0] - cc[0]) * (cw[0] - cc[0]) + (cw[1] - cc[1]) * (cw[1] - cc[1]),\n        (cw[2] - cc[2]) * (cw[2] - cc[2])\n      )\n      model.lengthPixelRatio = length / dims.width\n      const text = numberToText(length, 1)\n      scaleBarCtx.fillText(\n        `${text} ${model.units}`,\n        dims.width * 0.5,\n        6 * devicePixelRatio,\n        dims.width * 0.9\n      )\n    } catch (e) {\n      console.error(e)\n    }\n  }\n  model.interactor.onEndMouseWheel(updateScaleBar)\n  model.interactor.onEndPinch(updateScaleBar)\n\n  model.widgetManagerInitialized = false\n  model.widgetManager = WidgetManagerPickWhileAnimating.newInstance()\n  model.widgetsToRegister = []\n  model.widgetProps = new Map()\n\n  model.axesPolyData = vtkPolyData.newInstance()\n  model.axesMapper = vtkMapper.newInstance()\n  model.axesMapper.setInputData(model.axesPolyData)\n  model.axesGridActor = vtkActor.newInstance()\n  model.axesGridActor.setMapper(model.axesMapper)\n  model.axesGridActor.getProperty().setOpacity(0.5)\n  model.axesGridActor.setVisibility(false)\n  model.renderer.addActor(model.axesGridActor)\n  model.numberOfAxisTicks = 7\n  model.axesBoundingBox = [...vtkBoundingBox.INIT_BOUNDS]\n  model.axesOriginLabel = vtkAxesLabelsWidget.newInstance()\n  model.widgetsToRegister.push(model.axesOriginLabel)\n  model.axesXLabels = vtkAxesLabelsWidget.newInstance()\n  model.widgetsToRegister.push(model.axesXLabels)\n  model.axesYLabels = vtkAxesLabelsWidget.newInstance()\n  model.widgetsToRegister.push(model.axesYLabels)\n  model.axesZLabels = vtkAxesLabelsWidget.newInstance()\n  model.widgetsToRegister.push(model.axesZLabels)\n  model.axesCircleRadius = 4\n  model.axesTextOffset = 14\n\n  model.layerBBoxes = new Map()\n\n  // API ----------------------------------------------------------------------\n  publicAPI.updateDataProbeSize = updateDataProbeSize\n  publicAPI.updateScaleBar = updateScaleBar\n\n  const superSetBackground = publicAPI.setBackground\n  publicAPI.setBackground = color => {\n    superSetBackground(color)\n    if (color[0] + color[1] + color[2] <= 1.5) {\n      model.axesGridActor.getProperty().setColor([1.0, 1.0, 1.0])\n      if (model.widgetManagerInitialized) {\n        model.axesXActor.getProperty().setColor(1.0, 1.0, 1.0)\n        model.axesOriginWidget.setCircleProps({\n          r: model.axesCircleRadius,\n          stroke: 'white',\n          fill: 'white',\n        })\n        model.axesOriginWidget.setTextProps({\n          fill: 'white',\n          dx: -10 * model.axesTextOffset,\n          dy: 2 * model.axesTextOffset,\n        })\n        model.axesXWidget.setCircleProps({\n          r: model.axesCircleRadius,\n          stroke: 'white',\n          fill: 'white',\n        })\n        model.axesXWidget.setTextProps({\n          fill: 'white',\n          dx: model.axesTextOffset,\n          dy: 2 * model.axesTextOffset,\n        })\n        model.axesYActor.getProperty().setColor(1.0, 1.0, 1.0)\n        model.axesYWidget.setCircleProps({\n          r: model.axesCircleRadius,\n          stroke: 'white',\n          fill: 'white',\n        })\n        model.axesYWidget.setTextProps({\n          fill: 'white',\n          dx: model.axesTextOffset,\n          dy: 2 * model.axesTextOffset,\n        })\n        model.axesZActor.getProperty().setColor(1.0, 1.0, 1.0)\n        model.axesZWidget.setCircleProps({\n          r: model.axesCircleRadius,\n          stroke: 'white',\n          fill: 'white',\n        })\n        model.axesZWidget.setTextProps({\n          fill: 'white',\n          dx: model.axesTextOffset,\n          dy: -1 * model.axesTextOffset,\n        })\n      }\n    } else {\n      model.axesGridActor.getProperty().setColor([0.0, 0.0, 0.0])\n      if (model.widgetManagerInitialized) {\n        model.axesXActor.getProperty().setColor(0.0, 0.0, 0.0)\n        model.axesOriginWidget.setCircleProps({\n          r: model.axesCircleRadius,\n          stroke: 'black',\n          fill: 'black',\n        })\n        model.axesOriginWidget.setTextProps({\n          fill: 'black',\n          dx: -10 * model.axesTextOffset,\n          dy: 2 * model.axesTextOffset,\n        })\n        model.axesXWidget.setCircleProps({\n          r: model.axesCircleRadius,\n          stroke: 'black',\n          fill: 'black',\n        })\n        model.axesXWidget.setTextProps({\n          fill: 'black',\n          dx: model.axesTextOffset,\n          dy: 2 * model.axesTextOffset,\n        })\n        model.axesYActor.getProperty().setColor(0.0, 0.0, 0.0)\n        model.axesYWidget.setCircleProps({\n          r: model.axesCircleRadius,\n          stroke: 'black',\n          fill: 'black',\n        })\n        model.axesYWidget.setTextProps({\n          fill: 'black',\n          dx: model.axesTextOffset,\n          dy: 2 * model.axesTextOffset,\n        })\n        model.axesZActor.getProperty().setColor(0.0, 0.0, 0.0)\n        model.axesZWidget.setCircleProps({\n          r: model.axesCircleRadius,\n          stroke: 'black',\n          fill: 'black',\n        })\n        model.axesZWidget.setTextProps({\n          fill: 'black',\n          dx: model.axesTextOffset,\n          dy: -1 * model.axesTextOffset,\n        })\n      }\n    }\n  }\n\n  publicAPI.setViewMode = mode => {\n    if (model.viewMode === 'Volume') {\n      model.volumeCameraState = model.camera.getState()\n    }\n    switch (mode) {\n      case 'XPlane':\n        if (model.viewMode === 'XPlane') {\n          break\n        }\n        model.viewMode = mode\n        model.axesZWidget.setVisibility(false)\n        model.axesZActor.setVisibility(false)\n        setVisualizationMode(0)\n        break\n      case 'YPlane':\n        if (model.viewMode === 'YPlane') {\n          break\n        }\n        model.viewMode = mode\n        setVisualizationMode(1)\n        break\n      case 'ZPlane':\n        if (model.viewMode === 'ZPlane') {\n          break\n        }\n        model.viewMode = mode\n        setVisualizationMode(2)\n        break\n      case 'Volume':\n        if (model.viewMode === 'Volume') {\n          break\n        }\n        model.viewMode = mode\n        setVisualizationMode(-1)\n        break\n      default:\n        vtkErrorMacro('Unexpected view mode')\n    }\n    publicAPI.resetCamera()\n    updateDataProbeSize()\n  }\n\n  publicAPI.setImageVisibility = visible => {\n    if (model.imageVisibility === visible || !model.volumeRepresentation) {\n      return\n    }\n    model.imageVisibility = visible\n    publicAPI.modified()\n    if (visible) {\n      switch (model.viewMode) {\n        case 'Volume': {\n          model.volumeRepresentation.setVolumeVisibility(true)\n          break\n        }\n        case 'XPlane':\n          model.volumeRepresentation.setXSliceVisibility(true)\n          break\n        case 'YPlane':\n          model.volumeRepresentation.setYSliceVisibility(true)\n          break\n        case 'ZPlane':\n          model.volumeRepresentation.setZSliceVisibility(true)\n          break\n      }\n    } else {\n      model.volumeRepresentation.setXSliceVisibility(false)\n      model.volumeRepresentation.setYSliceVisibility(false)\n      model.volumeRepresentation.setZSliceVisibility(false)\n      model.volumeRepresentation.setVolumeVisibility(false)\n    }\n  }\n\n  publicAPI.setViewPlanes = viewPlanes => {\n    model.viewPlanes = viewPlanes\n    if (model.viewMode === 'Volume' && model.volumeRepresentation) {\n      if (viewPlanes) {\n        publicAPI.setCornerAnnotation('ne', model.neCornerAnnotation)\n      }\n    }\n  }\n\n  publicAPI.setOrientationAnnotationVisibility = visible => {\n    if (visible) {\n      model.scaleBarCanvas.style.display = 'block'\n      if (model.volumeRepresentation) {\n        publicAPI.setAnnotationOpacity(1.0)\n        model.orientationWidget.setEnabled(true)\n        if (!model.renderWindow.getInteractor().isAnimating()) {\n          model.renderWindow.render()\n        }\n      }\n    } else {\n      model.scaleBarCanvas.style.display = 'none'\n      publicAPI.setAnnotationOpacity(0.0)\n      model.orientationWidget.setEnabled(false)\n      if (!model.renderWindow.getInteractor().isAnimating()) {\n        model.renderWindow.render()\n      }\n    }\n  }\n\n  publicAPI.setPlanesUseLinearInterpolation = interpolate => {\n    if (model.volumeRepresentation) {\n      if (interpolate) {\n        model.volumeRepresentation.getActors().forEach(actor => {\n          const property = actor.getProperty()\n          property.setInterpolationTypeToLinear()\n          if (property.getRGBTransferFunction()) {\n            property.getRGBTransferFunction().modified()\n          }\n        })\n        if (!model.renderWindow.getInteractor().isAnimating()) {\n          model.renderWindow.render()\n        }\n      } else {\n        model.volumeRepresentation.getActors().forEach(actor => {\n          const property = actor.getProperty()\n          property.setInterpolationTypeToNearest()\n          if (property.getRGBTransferFunction()) {\n            property.getRGBTransferFunction().modified()\n          }\n        })\n        if (!model.renderWindow.getInteractor().isAnimating()) {\n          model.renderWindow.render()\n        }\n      }\n    }\n  }\n\n  publicAPI.setEnableAxes = enable => {\n    if (enable != model.enableAxes) {\n      model.enableAxes = enable\n      updateAxesVisibility()\n      publicAPI.modified()\n      if (!model.renderWindow.getInteractor().isAnimating()) {\n        model.renderWindow.render()\n      }\n    }\n  }\n\n  publicAPI.setEnableBBox = (name, enable) => {\n    const data = model.layerBBoxes.get(name)\n    if (data.actor.getVisibility() !== enable) {\n      data.actor.setVisibility(enable)\n    }\n  }\n\n  const superAddRepresentation = publicAPI.addRepresentation\n  publicAPI.addRepresentation = representation => {\n    superAddRepresentation(representation)\n\n    if (!representation) {\n      return\n    }\n\n    const volumeRepresentations = model.representations.filter(rep => {\n      const isVolumeRepresentation = !!rep.getVolumes().length\n      return isVolumeRepresentation\n    })\n    if (volumeRepresentations[0]) {\n      model.volumeRepresentation = volumeRepresentations[0]\n      const volume = model.volumeRepresentation.getVolumes()[0]\n      const property = volume.getProperty()\n      property.setAmbient(VOLUME_AMBIENT_DEFAULT)\n      property.setDiffuse(VOLUME_DIFFUSE_DEFAULT)\n      property.setSpecular(0.4)\n      property.setSpecularPower(25)\n      const actors = model.volumeRepresentation.getActors()\n      actors.forEach(model.annotationPicker.addPickList)\n      model.xSliceOutliner.setInputData(actors[0].getMapper())\n      model.renderer.addActor(model.xSliceActor)\n      model.ySliceOutliner.setInputData(actors[1].getMapper())\n      model.renderer.addActor(model.ySliceActor)\n      model.zSliceOutliner.setInputData(actors[2].getMapper())\n      model.renderer.addActor(model.zSliceActor)\n      updateDataProbeSize()\n      publicAPI.setAnnotationOpacity(1.0)\n    }\n\n    if (model.widgetManagerInitialized) {\n      updateAxes()\n    }\n  }\n\n  const superRemoveRepresentation = publicAPI.removeRepresentation\n  publicAPI.removeRepresentation = representation => {\n    superRemoveRepresentation(representation)\n\n    if (!representation) {\n      return\n    }\n    if (representation.getVolumes().length) {\n      model.renderer.removeActor(model.xSliceActor)\n      model.renderer.removeActor(model.ySliceActor)\n      model.renderer.removeActor(model.zSliceActor)\n    }\n    representation.getActors().forEach(model.annotationPicker.deletePickList)\n  }\n\n  // Continuously rotate in 3D\n  function rotateAzimuth() {\n    model.renderer.getActiveCamera().azimuth(0.25)\n    model.renderer.resetCameraClippingRange()\n  }\n  model.rotateAnimationCallback = null\n  publicAPI.setRotate = rotate => {\n    if (model.rotate === rotate) {\n      return\n    }\n    model.rotate = rotate\n\n    if (rotate) {\n      model.rotateAnimationCallback = model.interactor.onAnimation(\n        rotateAzimuth\n      )\n      model.interactor.requestAnimation('itk-vtk-view-rotate')\n    } else {\n      model.interactor.cancelAnimation('itk-vtk-view-rotate')\n      if (model.rotateAnimationCallback) {\n        model.rotateAnimationCallback.unsubscribe()\n        model.rotateAnimationCallback = null\n      }\n    }\n  }\n\n  const superSetContainer = publicAPI.setContainer\n  publicAPI.setContainer = container => {\n    superSetContainer(container)\n    if (container) {\n      container.appendChild(model.scaleBarCanvas)\n    }\n  }\n\n  publicAPI.resize = () => {\n    if (model.container) {\n      const dims = model.container.getBoundingClientRect()\n      if (dims.width === dims.height && dims.width === 0) {\n        return\n      }\n      const devicePixelRatio = window.devicePixelRatio || 1\n      const width = Math.max(10, Math.floor(devicePixelRatio * dims.width))\n      const height = Math.max(10, Math.floor(devicePixelRatio * dims.height))\n      model._openGLRenderWindow.setSize(width, height)\n\n      model.scaleBarCanvas.width = (100 * devicePixelRatio).toFixed()\n      model.scaleBarCanvas.height = (30 * devicePixelRatio).toFixed()\n\n      publicAPI.invokeResize({ width, height })\n      publicAPI.renderLater()\n    }\n  }\n\n  publicAPI.resetCamera = bounds => {\n    model.renderer.resetCamera(bounds)\n    model.renderer.resetCameraClippingRange()\n    model.interactorStyle2D.setCenterOfRotation(model.camera.getFocalPoint())\n    model.interactorStyle3D.setCenterOfRotation(model.camera.getFocalPoint())\n    publicAPI.renderLater()\n  }\n\n  publicAPI.createLayerBoundingBox = name => {\n    const labelBBoxPolyData = vtkPolyData.newInstance()\n    const labelBBoxMapper = vtkMapper.newInstance()\n    labelBBoxMapper.setInputData(labelBBoxPolyData)\n    const labelBBoxGridActor = vtkActor.newInstance()\n    labelBBoxGridActor.setMapper(labelBBoxMapper)\n    labelBBoxGridActor.getProperty().setColor([1.0, 0.0, 0.0])\n    labelBBoxGridActor.setVisibility(false)\n    const data = {\n      polyData: labelBBoxPolyData,\n      actor: labelBBoxGridActor,\n    }\n    model.layerBBoxes.set(name, data)\n    model.renderer.addActor(data.actor)\n  }\n\n  publicAPI.updateLabelBoundingBox = (name, bounds) => {\n    if (!model.layerBBoxes.has(name)) {\n      publicAPI.createLayerBoundingBox(name)\n    }\n\n    const data = model.layerBBoxes.get(name)\n    let points = vtkPoints.newInstance()\n    for (let i = 0; i < 2; i++) {\n      for (let j = 2; j < 4; j++) {\n        for (let k = 4; k < 6; k++) {\n          points.insertNextPoint(bounds[i], bounds[j], bounds[k])\n        }\n      }\n    }\n    data.polyData.setPoints(points)\n\n    let lines = vtkCellArray.newInstance()\n    lines.insertNextCell([0, 1, 3, 2, 0])\n    lines.insertNextCell([4, 5, 7, 6, 4])\n    lines.insertNextCell([0, 4, 6, 2])\n    lines.insertNextCell([1, 5, 7, 3])\n    data.polyData.setLines(lines)\n  }\n}\n\n// ----------------------------------------------------------------------------\n// Object factory\n// ----------------------------------------------------------------------------\n\nconst DEFAULT_VALUES = {\n  viewMode: 'Volume',\n  viewPlanes: false,\n  imageVisibility: true,\n  rotate: false,\n  units: '',\n  neCornerAnnotation: CursorCornerAnnotation,\n  labelIndex: null,\n  labelNames: null,\n  clickCallback: null,\n  lengthPixelRatio: 1.0,\n  lastPickedValues: {\n    iIndex: null,\n    jIndex: null,\n    kIndex: null,\n    xPosition: null,\n    yPosition: null,\n    zPosition: null,\n    value: null,\n    label: null,\n  },\n  widgetManagerInitializedCallback: null,\n  enableAxes: false,\n  xyLowerLeft: false,\n  axesNames: null,\n}\n\n// ----------------------------------------------------------------------------\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  vtkViewProxy.extend(publicAPI, model, initialValues)\n  macro.get(publicAPI, model, [\n    'viewMode',\n    'viewPlanes',\n    'imageVisibility',\n    'rotate',\n    'lengthPixelRatio',\n    'axesActor',\n    'enableAxes',\n    'widgetManager',\n  ])\n\n  macro.setGet(publicAPI, model, [\n    'units',\n    'neCornerAnnotation',\n    'labelNames',\n    'labelIndex',\n    'clickCallback',\n    'xyLowerLeft',\n    'axesNames',\n  ])\n\n  // Object specific methods\n  ItkVtkViewProxy(publicAPI, model)\n}\n// ----------------------------------------------------------------------------\n\nexport const newInstance = macro.newInstance(extend, 'ItkVtkViewProxy')\n\n// ----------------------------------------------------------------------------\n\nexport default { newInstance, extend }\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/OpenGLImageMapperFractional.js",
    "content": "// ----------------------------------------------------------------------------\n// Additive mixing of components rather than weighted\n// ----------------------------------------------------------------------------\n\nimport * as macro from 'vtk.js/Sources/macros'\nimport vtkShaderProgram from 'vtk.js/Sources/Rendering/OpenGL/ShaderProgram'\nimport vtkOpenGlImageMapper from 'vtk.js/Sources/Rendering/OpenGL/ImageMapper'\n\nimport { registerOverride } from 'vtk.js/Sources/Rendering/OpenGL/ViewNodeFactory'\n\nconst { vtkErrorMacro } = macro\n\nfunction OpenGLImageMapperFractional(publicAPI, model) {\n  // Set our className\n  model.classHierarchy.push('OpenGLImageMapperFractional')\n\n  // Changes from vtk.js code: Add component values together after transfer function and don't normalize to 1\n  publicAPI.replaceShaderValues = (shaders, ren, actor) => {\n    let VSSource = shaders.Vertex\n    let FSSource = shaders.Fragment\n\n    VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Camera::Dec', [\n      'uniform mat4 MCPCMatrix;',\n    ]).result\n    VSSource = vtkShaderProgram.substitute(\n      VSSource,\n      '//VTK::PositionVC::Impl',\n      ['  gl_Position = MCPCMatrix * vertexMC;']\n    ).result\n\n    VSSource = vtkShaderProgram.substitute(\n      VSSource,\n      '//VTK::TCoord::Impl',\n      'tcoordVCVSOutput = tcoordMC;'\n    ).result\n\n    VSSource = vtkShaderProgram.substitute(\n      VSSource,\n      '//VTK::TCoord::Dec',\n      'attribute vec2 tcoordMC; varying vec2 tcoordVCVSOutput;'\n    ).result\n\n    const tNumComp = model.openGLTexture.getComponents()\n    const iComps = actor.getProperty().getIndependentComponents()\n\n    let tcoordDec = [\n      'varying vec2 tcoordVCVSOutput;',\n      // color shift and scale\n      'uniform float cshift0;',\n      'uniform float cscale0;',\n      // pwf shift and scale\n      'uniform float pwfshift0;',\n      'uniform float pwfscale0;',\n      'uniform sampler2D texture1;',\n      'uniform sampler2D colorTexture1;',\n      'uniform sampler2D pwfTexture1;',\n      'uniform float opacity;',\n    ]\n    if (iComps) {\n      for (let comp = 1; comp < tNumComp; comp++) {\n        tcoordDec = tcoordDec.concat([\n          // color shift and scale\n          `uniform float cshift${comp};`,\n          `uniform float cscale${comp};`,\n          // weighting shift and scale\n          `uniform float pwfshift${comp};`,\n          `uniform float pwfscale${comp};`,\n        ])\n      }\n      // the heights defined below are the locations\n      // for the up to four components of the tfuns\n      // the tfuns have a height of 2XnumComps pixels so the\n      // values are computed to hit the middle of the two rows\n      // for that component\n      switch (tNumComp) {\n        case 1:\n          tcoordDec = tcoordDec.concat([\n            'uniform float mix0;',\n            '#define height0 0.5',\n          ])\n          break\n        case 2:\n          tcoordDec = tcoordDec.concat([\n            'uniform float mix0;',\n            'uniform float mix1;',\n            '#define height0 0.25',\n            '#define height1 0.75',\n          ])\n          break\n        case 3:\n          tcoordDec = tcoordDec.concat([\n            'uniform float mix0;',\n            'uniform float mix1;',\n            'uniform float mix2;',\n            '#define height0 0.17',\n            '#define height1 0.5',\n            '#define height2 0.83',\n          ])\n          break\n        case 4:\n          tcoordDec = tcoordDec.concat([\n            'uniform float mix0;',\n            'uniform float mix1;',\n            'uniform float mix2;',\n            'uniform float mix3;',\n            '#define height0 0.125',\n            '#define height1 0.375',\n            '#define height2 0.625',\n            '#define height3 0.875',\n          ])\n          break\n        default:\n          vtkErrorMacro('Unsupported number of independent coordinates.')\n      }\n    }\n    FSSource = vtkShaderProgram.substitute(\n      FSSource,\n      '//VTK::TCoord::Dec',\n      tcoordDec\n    ).result\n\n    if (iComps) {\n      const rgba = ['r', 'g', 'b', 'a']\n      let tcoordImpl = ['vec4 tvalue = texture2D(texture1, tcoordVCVSOutput);']\n      for (let comp = 0; comp < tNumComp; comp++) {\n        tcoordImpl = tcoordImpl.concat([\n          `vec3 tcolor${comp} = mix${comp} * texture2D(colorTexture1, vec2(tvalue.${rgba[comp]} * cscale${comp} + cshift${comp}, height${comp})).rgb;`,\n          `float compWeight${comp} = mix${comp} * texture2D(pwfTexture1, vec2(tvalue.${rgba[comp]} * pwfscale${comp} + pwfshift${comp}, height${comp})).r;`,\n        ])\n      }\n      switch (tNumComp) {\n        case 1:\n          tcoordImpl = tcoordImpl.concat([\n            'gl_FragData[0] = vec4(tcolor0.rgb, opacity);',\n          ])\n          break\n        case 2:\n          tcoordImpl = tcoordImpl.concat([\n            // 'float weightSum = compWeight0 + compWeight1;', // vtk.js original code\n            'float weightSum = 1.0;', // the change\n            'gl_FragData[0] = vec4(vec3((tcolor0.rgb * (compWeight0 / weightSum)) + (tcolor1.rgb * (compWeight1 / weightSum))), opacity);',\n          ])\n          break\n        case 3:\n          tcoordImpl = tcoordImpl.concat([\n            // 'float weightSum = compWeight0 + compWeight1 + compWeight2;',\n            'float weightSum = 1.0;',\n            'gl_FragData[0] = vec4(vec3((tcolor0.rgb * (compWeight0 / weightSum)) + (tcolor1.rgb * (compWeight1 / weightSum)) + (tcolor2.rgb * (compWeight2 / weightSum))), opacity);',\n          ])\n          break\n        case 4:\n          tcoordImpl = tcoordImpl.concat([\n            // 'float weightSum = compWeight0 + compWeight1 + compWeight2 + compWeight3;',\n            'float weightSum = 1.0;',\n            'gl_FragData[0] = vec4(vec3((tcolor0.rgb * (compWeight0 / weightSum)) + (tcolor1.rgb * (compWeight1 / weightSum)) + (tcolor2.rgb * (compWeight2 / weightSum)) + (tcolor3.rgb * (compWeight3 / weightSum))), opacity);',\n          ])\n          break\n        default:\n          vtkErrorMacro('Unsupported number of independent coordinates.')\n      }\n      FSSource = vtkShaderProgram.substitute(\n        FSSource,\n        '//VTK::TCoord::Impl',\n        tcoordImpl\n      ).result\n    } else {\n      // dependent components\n      switch (tNumComp) {\n        case 1:\n          FSSource = vtkShaderProgram.substitute(\n            FSSource,\n            '//VTK::TCoord::Impl',\n            [\n              'float intensity = texture2D(texture1, tcoordVCVSOutput).r;',\n              'vec3 tcolor = texture2D(colorTexture1, vec2(intensity * cscale0 + cshift0, 0.5)).rgb;',\n              'float scalarOpacity = texture2D(pwfTexture1, vec2(intensity * pwfscale0 + pwfshift0, 0.5)).r;',\n              'gl_FragData[0] = vec4(tcolor, scalarOpacity * opacity);',\n            ]\n          ).result\n          break\n        case 2:\n          FSSource = vtkShaderProgram.substitute(\n            FSSource,\n            '//VTK::TCoord::Impl',\n            [\n              'vec4 tcolor = texture2D(texture1, tcoordVCVSOutput);',\n              'float intensity = tcolor.r*cscale0 + cshift0;',\n              'gl_FragData[0] = vec4(texture2D(colorTexture1, vec2(intensity, 0.5)).rgb, pwfscale0*tcolor.g + pwfshift0);',\n            ]\n          ).result\n          break\n        default:\n          FSSource = vtkShaderProgram.substitute(\n            FSSource,\n            '//VTK::TCoord::Impl',\n            [\n              'vec4 tcolor = cscale0*texture2D(texture1, tcoordVCVSOutput.st) + cshift0;',\n              'gl_FragData[0] = vec4(texture2D(colorTexture1, vec2(tcolor.r,0.5)).r,',\n              '  texture2D(colorTexture1, vec2(tcolor.g,0.5)).r,',\n              '  texture2D(colorTexture1, vec2(tcolor.b,0.5)).r, tcolor.a);',\n            ]\n          ).result\n      }\n    }\n\n    if (model.haveSeenDepthRequest) {\n      FSSource = vtkShaderProgram.substitute(\n        FSSource,\n        '//VTK::ZBuffer::Dec',\n        'uniform int depthRequest;'\n      ).result\n      FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Impl', [\n        'if (depthRequest == 1) {',\n        'float iz = floor(gl_FragCoord.z*65535.0 + 0.1);',\n        'float rf = floor(iz/256.0)/255.0;',\n        'float gf = mod(iz,256.0)/255.0;',\n        'gl_FragData[0] = vec4(rf, gf, 0.0, 1.0); }',\n      ]).result\n    }\n\n    shaders.Vertex = VSSource\n    shaders.Fragment = FSSource\n\n    publicAPI.replaceShaderClip(shaders, ren, actor)\n    publicAPI.replaceShaderCoincidentOffset(shaders, ren, actor)\n  }\n}\n\n// ----------------------------------------------------------------------------\n// Object factory\n// ----------------------------------------------------------------------------\n\nconst DEFAULT_VALUES = {}\n\n// ----------------------------------------------------------------------------\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  vtkOpenGlImageMapper.extend(publicAPI, model, initialValues)\n\n  OpenGLImageMapperFractional(publicAPI, model)\n}\n\n// ----------------------------------------------------------------------------\n\nexport const newInstance = macro.newInstance(\n  extend,\n  'OpenGLImageMapperFractional'\n)\n\n// ----------------------------------------------------------------------------\n\nexport default { newInstance, extend }\n\n// Register ourself to OpenGL backend if imported\nregisterOverride('vtkImageMapper', newInstance)\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/PointSetRepresentationProxy/index.js",
    "content": "import macro from 'vtk.js/Sources/macros'\nimport vtkActor from 'vtk.js/Sources/Rendering/Core/Actor'\nimport vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper'\nimport vtkSphereSource from 'vtk.js/Sources/Filters/Sources/SphereSource'\nimport vtkGlyph3DMapper from 'vtk.js/Sources/Rendering/Core/Glyph3DMapper'\n\nimport vtkAbstractRepresentationProxy from 'vtk.js/Sources/Proxy/Core/AbstractRepresentationProxy'\n\nconst PROPERTIES_STATE = {}\n\nconst PROPERTIES_DEFAULT = {}\n\n// ----------------------------------------------------------------------------\n// vtkPointSetRepresentationProxy methods\n// ----------------------------------------------------------------------------\n\nfunction vtkPointSetRepresentationProxy(publicAPI, model) {\n  // Set our className\n  model.classHierarchy.push('vtkPointSetRepresentationProxy')\n\n  // Internals\n  model.mapper = vtkMapper.newInstance({\n    interpolateScalarsBeforeMapping: true,\n    useLookupTableScalarRange: true,\n    scalarVisibility: false,\n  })\n  model.actor = vtkActor.newInstance()\n  model.property = model.actor.getProperty()\n\n  model.glyphMapper = vtkGlyph3DMapper.newInstance({\n    interpolateScalarsBeforeMapping: true,\n    useLookupTableScalarRange: true,\n    scalarVisibility: false,\n  })\n  model.sphereSource = vtkSphereSource.newInstance()\n  model.glyphMapper.setInputConnection(model.sphereSource.getOutputPort(), 1)\n  model.glyphMapper.setScaleModeToScaleByConstant()\n\n  function updateGlyphMapper(inputDataSet) {\n    model.glyphMapper.setInputData(inputDataSet, 0)\n  }\n\n  // Auto connect mappers\n  model.sourceDependencies.push(model.mapper)\n  model.sourceDependencies.push({ setInputData: updateGlyphMapper })\n  // connect rendering pipeline\n  model.actor.setMapper(model.mapper)\n  model.actors.push(model.actor)\n  model.glyphActor = vtkActor.newInstance()\n  model.glyphActor.setMapper(model.glyphMapper)\n  model.actors.push(model.glyphActor)\n  model.glyphProperty = model.glyphActor.getProperty()\n\n  // Initialize state\n  model.property.setRepresentationToPoints()\n  model.glyphActor.setVisibility(false)\n\n  publicAPI.setRadiusFactor = radiusFactor => {\n    model.radiusFactor = radiusFactor\n    model.sphereSource.setRadius(model.pointSize * radiusFactor)\n  }\n\n  publicAPI.setVisibility = visible => {\n    if (visible) {\n      switch (model.representation) {\n        case 'Points':\n          model.actor.setVisibility(visible)\n          break\n        case 'Spheres':\n          model.glyphActor.setVisibility(visible)\n          break\n        default:\n          throw Error('Unexpected point set representation')\n      }\n    } else {\n      model.actor.setVisibility(visible)\n      model.glyphActor.setVisibility(visible)\n    }\n    model.visibility = visible\n  }\n\n  publicAPI.setRepresentation = representation => {\n    if (model.visibility) {\n      switch (representation) {\n        case 'Points':\n          model.actor.setVisibility(true)\n          model.glyphActor.setVisibility(false)\n          break\n        case 'Spheres':\n          model.actor.setVisibility(false)\n          model.glyphActor.setVisibility(true)\n          break\n        default:\n          throw Error('Unexpected point set representation')\n      }\n    }\n    model.representation = representation\n  }\n\n  publicAPI.setOpacity = opacity => {\n    model.property.setOpacity(opacity)\n    model.glyphProperty.setOpacity(opacity)\n    model.opacity = opacity\n  }\n\n  publicAPI.setColor = color => {\n    model.property.setDiffuseColor(color)\n    model.glyphProperty.setDiffuseColor(color)\n    model.color = color\n  }\n\n  publicAPI.setInterpolateScalarsBeforeMapping = interpolate => {\n    model.mapper.setInterpolateScalarsBeforeMapping(interpolate)\n    model.glyphMapper.setInterpolateScalarsBeforeMapping(interpolate)\n    model.interpolateScalarsBeforeMapping = interpolate\n  }\n\n  publicAPI.setPointSize = pointSize => {\n    model.property.setPointSize(pointSize)\n    model.sphereSource.setRadius(pointSize * model.radiusFactor)\n    model.pointSize = pointSize\n  }\n\n  publicAPI.setUseShadow = useShadow => {\n    model.property.setLighting(useShadow)\n    model.glyphProperty.setLighting(useShadow)\n    model.useShadow = useShadow\n  }\n\n  publicAPI.setUseBounds = useBounds => {\n    model.actor.setUseBounds(useBounds)\n    model.glyphActor.setUseBounds(useBounds)\n    model.useBounds = useBounds\n  }\n\n  const abstractSetColorBy = publicAPI.setColorBy\n  publicAPI.setColorBy = (arrayName, arrayLocation, componentIndex = -1) => {\n    // Configures model.mapper\n    abstractSetColorBy(arrayName, arrayLocation, componentIndex)\n\n    // Now also configure model.glyphMapper\n    let colorMode = vtkMapper.ColorMode.DEFAULT\n    let scalarMode = vtkMapper.ScalarMode.DEFAULT\n    const colorByArrayName = arrayName\n    const activeArray = publicAPI.getDataArray(arrayName, arrayLocation)\n    const scalarVisibility = !!activeArray\n    const lookupTable = arrayName\n      ? publicAPI.getLookupTableProxy(arrayName).getLookupTable()\n      : null\n\n    if (scalarVisibility) {\n      colorMode = vtkMapper.ColorMode.MAP_SCALARS\n      scalarMode =\n        arrayLocation === 'pointData'\n          ? vtkMapper.ScalarMode.USE_POINT_FIELD_DATA\n          : vtkMapper.ScalarMode.USE_CELL_FIELD_DATA\n\n      model.glyphMapper.setLookupTable(lookupTable)\n    }\n\n    model.glyphMapper.set(\n      {\n        colorByArrayName,\n        colorMode,\n        scalarMode,\n        scalarVisibility,\n      },\n      true\n    )\n  }\n}\n\n// ----------------------------------------------------------------------------\n// Object factory\n// ----------------------------------------------------------------------------\n\nconst DEFAULT_VALUES = {\n  representation: 'Points',\n  radiusFactor: 0.1,\n  visibility: true,\n  opacity: 1.0,\n  color: [1.0, 1.0, 1.0],\n  interpolateScalarsBeforeMapping: true,\n  pointSize: 0.3,\n  useShadow: true,\n  useBounds: true,\n}\n\n// ----------------------------------------------------------------------------\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  // Object methods\n  vtkAbstractRepresentationProxy.extend(publicAPI, model)\n\n  // Object specific methods\n  vtkPointSetRepresentationProxy(publicAPI, model)\n\n  macro.get(publicAPI, model, [\n    'radiusFactor',\n    'representation',\n    'visibility',\n    'opacity',\n    'color',\n    'interpolateScalarsBeforeMapping',\n    'pointSize',\n    'useShadow',\n    'useBounds',\n  ])\n\n  // Map proxy properties\n  macro.proxyPropertyState(\n    publicAPI,\n    model,\n    PROPERTIES_STATE,\n    PROPERTIES_DEFAULT\n  )\n  macro.proxyPropertyMapping(publicAPI, model, {})\n}\n\n// ----------------------------------------------------------------------------\n\nexport const newInstance = macro.newInstance(\n  extend,\n  'vtkPointSetRepresentationProxy'\n)\n\n// ----------------------------------------------------------------------------\n\nexport default { newInstance, extend }\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/SVGMarkerTextRepresentation/index.js",
    "content": "import macro from 'vtk.js/Sources/macros'\nimport vtkSVGRepresentation from '../SVGRepresentation'\n\nconst { createSvgElement } = vtkSVGRepresentation\n\n// ----------------------------------------------------------------------------\n// vtkSVGMarkerTextRepresentation\n// ----------------------------------------------------------------------------\n\nfunction vtkSVGMarkerTextRepresentation(publicAPI, model) {\n  // Set our className\n  model.classHierarchy.push('vtkSVGMarkerTextRepresentation')\n\n  publicAPI.render = () => {\n    if (!publicAPI.getVisibility()) {\n      return\n    }\n    const list = publicAPI.getRepresentationStates()\n\n    const coords = []\n    const textContents = []\n    for (let i = 0; i < list.length; i++) {\n      coords.push(list[i].getOrigin())\n    }\n\n    let index = 0\n    return publicAPI.worldPointsToPixelSpace(coords).then(pixelSpace => {\n      const points2d = pixelSpace.coords\n      const winHeight = pixelSpace.windowSize[1]\n\n      const root = createSvgElement('g')\n\n      for (let i = 0; i < points2d.length; i++) {\n        const xy = points2d[i]\n        const x = xy[0]\n        const y = winHeight - xy[1]\n\n        const circle = createSvgElement('circle')\n        Object.keys(model.circleProps || {}).forEach(prop =>\n          circle.setAttribute(prop, model.circleProps[prop])\n        )\n        circle.setAttribute('cx', x)\n        circle.setAttribute('cy', y)\n\n        const text = createSvgElement('text')\n        Object.keys(model.textProps || {}).forEach(prop =>\n          text.setAttribute(prop, model.textProps[prop])\n        )\n        text.setAttribute('x', x)\n        text.setAttribute('y', y)\n        text.textContent = list[index].getText()\n\n        root.appendChild(circle)\n        root.appendChild(text)\n        index++\n      }\n\n      return root\n    })\n  }\n}\n\n// ----------------------------------------------------------------------------\n// Object factory\n// ----------------------------------------------------------------------------\n\nconst DEFAULT_VALUES = {\n  circleProps: {\n    r: 5,\n    stroke: 'red',\n    fill: 'red',\n  },\n  textProps: {\n    fill: 'white',\n    dx: 12,\n    dy: -12,\n  },\n}\n\n// ----------------------------------------------------------------------------\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  vtkSVGRepresentation.extend(publicAPI, model, initialValues)\n\n  macro.setGet(publicAPI, model, ['circleProps', 'textProps'])\n\n  // Object specific methods\n  vtkSVGMarkerTextRepresentation(publicAPI, model)\n}\n\n// ----------------------------------------------------------------------------\n\nexport const newInstance = macro.newInstance(\n  extend,\n  'vtkSVGMarkerTextRepresentation'\n)\n\n// ----------------------------------------------------------------------------\n\nexport default { extend, newInstance }\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/SVGRepresentation/index.js",
    "content": "import macro from 'vtk.js/Sources/macros'\nimport vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData'\nimport vtkActor from 'vtk.js/Sources/Rendering/Core/Actor'\nimport vtkPixelSpaceCallbackMapper from 'vtk.js/Sources/Rendering/Core/PixelSpaceCallbackMapper'\nimport vtkWidgetRepresentation from 'vtk.js/Sources/Widgets/Representations/WidgetRepresentation'\n\nimport { Behavior } from 'vtk.js/Sources/Widgets/Representations/WidgetRepresentation/Constants'\nimport { RenderingTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'\n\nconst SVG_XMLNS = 'http://www.w3.org/2000/svg'\n\n// ----------------------------------------------------------------------------\n\nfunction createSvgElement(tag) {\n  return {\n    name: tag,\n    attrs: {},\n    eventListeners: {},\n    // implies no children if set\n    textContent: null,\n    children: [],\n    setAttribute(attr, val) {\n      this.attrs[attr] = val\n    },\n    removeAttribute(attr) {\n      delete this.attrs[attr]\n    },\n    appendChild(n) {\n      this.children.push(n)\n    },\n    addEventListeners(event, callback) {\n      this.eventListeners[event] = callback\n    },\n  }\n}\n\n// ----------------------------------------------------------------------------\n\nfunction createSvgDomElement(tag) {\n  return document.createElementNS(SVG_XMLNS, tag)\n}\n\n// ----------------------------------------------------------------------------\n\nfunction defer() {\n  let resolve\n  let reject\n  const promise = new Promise((res, rej) => {\n    resolve = res\n    reject = rej\n  })\n  return {\n    promise,\n    resolve,\n    reject,\n  }\n}\n\n// ----------------------------------------------------------------------------\n// vtkSVGRepresentation\n// ----------------------------------------------------------------------------\n\nfunction vtkSVGRepresentation(publicAPI, model) {\n  // Set our className\n  model.classHierarchy.push('vtkSVGRepresentation')\n\n  let deferred = null\n\n  model.psActor = vtkActor.newInstance({\n    pickable: false,\n    _parentProp: publicAPI,\n  })\n  model.psMapper = vtkPixelSpaceCallbackMapper.newInstance()\n  model.points = vtkPolyData.newInstance()\n\n  model.psMapper.setInputData(model.points)\n  model.psActor.setMapper(model.psMapper)\n\n  model.psMapper.setCallback((...args) => {\n    if (deferred) {\n      const d = deferred\n      deferred = null\n\n      d.resolve({\n        coords: args[0],\n        camera: args[1],\n        aspect: args[2],\n        depthValues: args[3],\n        windowSize: args[4],\n      })\n    }\n  })\n\n  publicAPI.addActor(model.psActor)\n\n  // --------------------------------------------------------------------------\n\n  publicAPI.worldPointsToPixelSpace = points3d => {\n    const pts = new Float32Array(points3d.length * 3)\n    for (let i = 0; i < points3d.length; i++) {\n      pts[i * 3 + 0] = points3d[i][0]\n      pts[i * 3 + 1] = points3d[i][1]\n      pts[i * 3 + 2] = points3d[i][2]\n    }\n    model.points.getPoints().setData(pts)\n    model.points.modified()\n\n    deferred = defer()\n    return deferred.promise\n  }\n\n  publicAPI.createListenableSvgElement = (tag, id) => {\n    const element = createSvgElement(tag)\n    if (model.pickable) {\n      element.addEventListeners('mouseenter', () => {\n        publicAPI.setHover(id)\n      })\n      element.addEventListeners('mouseleave', () => {\n        if (publicAPI.getHover() === id) {\n          publicAPI.setHover(null)\n        }\n      })\n    }\n    return element\n  }\n\n  // --------------------------------------------------------------------------\n\n  publicAPI.updateActorVisibility = (\n    renderingType = RenderingTypes.FRONT_BUFFER,\n    ctxVisible = true,\n    handleVisible = true\n  ) => {\n    if (model.behavior === Behavior.CONTEXT) {\n      publicAPI.setVisibility(ctxVisible)\n    } else if (model.behavior === Behavior.HANDLE) {\n      publicAPI.setVisibility(handleVisible)\n    }\n  }\n\n  // --------------------------------------------------------------------------\n\n  // Subclasses must implement this method\n  publicAPI.render = () => {\n    throw new Error('Not implemented')\n  }\n}\n\n// ----------------------------------------------------------------------------\n// Object factory\n// ----------------------------------------------------------------------------\n\n/**\n * 'hover' is not null when a pickable SVG element is mouse hovered.\n */\nconst DEFAULT_VALUES = {\n  visibility: true,\n}\n\n// ----------------------------------------------------------------------------\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  // Extend methods\n  vtkWidgetRepresentation.extend(publicAPI, model, initialValues)\n\n  macro.setGet(publicAPI, model, ['visibility', 'hover'])\n\n  // Object specific methods\n  vtkSVGRepresentation(publicAPI, model)\n}\n\n// ----------------------------------------------------------------------------\n\nexport default { extend, createSvgElement, createSvgDomElement }\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/SliceOutlineFilter/index.js",
    "content": "import macro from 'vtk.js/Sources/macros'\nimport vtkPolyData from 'vtk.js/Sources/Common/DataModel/PolyData'\nimport vtkMath from 'vtk.js/Sources/Common/Core/Math'\nimport { SlicingMode } from 'vtk.js/Sources/Rendering/Core/ImageMapper/Constants'\n\nconst { vtkErrorMacro } = macro\n\n// prettier-ignore\nexport const BOUNDS_MAP = [\n  0, 2, 4, // pt 0\n  1, 2, 4, // pt 1\n  0, 3, 4, // pt 2\n  1, 3, 4, // pt 3\n  0, 2, 5, // pt 4\n  1, 2, 5, // pt 5\n  0, 3, 5, // pt 6\n  1, 3, 5, // pt 7\n];\n\n// prettier-ignore\nexport const LINE_ARRAY = [\n  2, 0, 1,\n  2, 2, 3,\n  2, 4, 5,\n  2, 6, 7,\n  2, 0, 2,\n  2, 1, 3,\n  2, 4, 6,\n  2, 5, 7,\n  2, 0, 4,\n  2, 1, 5,\n  2, 2, 6,\n  2, 3, 7,\n];\n\n// ----------------------------------------------------------------------------\n// vtkSliceOutlineFilter methods\n// ----------------------------------------------------------------------------\n\nfunction vtkSliceOutlineFilter(publicAPI, model) {\n  // Set our className\n  model.classHierarchy.push('vtkOutlineFilter')\n\n  const spatialBoundsForSlice = (input, thickness = 0) => {\n    const image = input.getInputData()\n    if (!image) {\n      return vtkMath.createUninitializedBounds()\n    }\n    const extent = image.getSpatialExtent()\n    const { ijkMode } = input.getClosestIJKAxis()\n    let nSlice = input.getSlice()\n    if (ijkMode !== model.slicingMode) {\n      // If not IJK slicing, get the IJK slice from the XYZ position/slice\n      nSlice = input.getSliceAtPosition(nSlice)\n    }\n    switch (ijkMode) {\n      case SlicingMode.I:\n        extent[0] = nSlice - thickness\n        extent[1] = nSlice + thickness\n        break\n      case SlicingMode.J:\n        extent[2] = nSlice - thickness\n        extent[3] = nSlice + thickness\n        break\n      case SlicingMode.K:\n        extent[4] = nSlice - thickness\n        extent[5] = nSlice + thickness\n        break\n      default:\n        break\n    }\n    return image.extentToBounds(extent)\n  }\n\n  publicAPI.requestData = (inData, outData) => {\n    // implement requestData\n    const input = inData[0]\n\n    if (!input) {\n      vtkErrorMacro('Invalid or missing input')\n      return\n    }\n\n    const bounds = spatialBoundsForSlice(input)\n    const output = vtkPolyData.newInstance()\n\n    output\n      .getPoints()\n      .setData(Float32Array.from(BOUNDS_MAP.map(idx => bounds[idx])), 3)\n    output.getLines().setData(Uint16Array.from(LINE_ARRAY))\n\n    outData[0] = output\n  }\n}\n\n// ----------------------------------------------------------------------------\n// Object factory\n// ----------------------------------------------------------------------------\n\nconst DEFAULT_VALUES = {}\n\n// ----------------------------------------------------------------------------\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  // Make this a VTK object\n  macro.obj(publicAPI, model)\n\n  // Also make it an algorithm with one input and one output\n  macro.algo(publicAPI, model, 1, 1)\n\n  // Object specific methods\n  vtkSliceOutlineFilter(publicAPI, model)\n}\n\n// ----------------------------------------------------------------------------\n\nexport const newInstance = macro.newInstance(extend, 'vtkSliceOutlineFilter')\n\n// ----------------------------------------------------------------------------\n\nexport default { newInstance, extend, BOUNDS_MAP, LINE_ARRAY }\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtk/WidgetManagerPickWhileAnimating.js",
    "content": "import Macro from 'vtk.js/Sources/macros'\nimport vtkWidgetManager from 'vtk.js/Sources/Widgets/Core/WidgetManager'\n\n// Let widgets handleEvents while interactor is animating\nfunction WidgetManagerPickWhileAnimating(publicAPI, model) {\n  model.classHierarchy.push('WidgetManagerPickWhileAnimating')\n\n  const subscriptions = []\n\n  const superSetRenderer = publicAPI.setRenderer\n  publicAPI.setRenderer = renderer => {\n    superSetRenderer(renderer)\n\n    subscriptions.push(\n      model._interactor.onStartAnimation(() => {\n        model.isAnimating = false // undoes super class setting this to true\n      })\n    )\n  }\n\n  const superDelete = publicAPI.delete\n  publicAPI.delete = () => {\n    while (subscriptions.length) {\n      subscriptions.pop().unsubscribe()\n    }\n    superDelete()\n  }\n}\n\nconst DEFAULT_VALUES = {}\n\nexport function extend(publicAPI, model, initialValues = {}) {\n  Object.assign(model, DEFAULT_VALUES, initialValues)\n\n  vtkWidgetManager.extend(publicAPI, model, initialValues)\n\n  WidgetManagerPickWhileAnimating(publicAPI, model)\n}\n\n// ----------------------------------------------------------------------------\n\nexport const newInstance = Macro.newInstance(\n  extend,\n  'WidgetManagerPickWhileAnimating'\n)\n\n// ----------------------------------------------------------------------------\n\nexport default { newInstance, extend }\n"
  },
  {
    "path": "src/Rendering/VTKJS/vtkJSRenderingMachineOptions.js",
    "content": "import createRenderer from './createRenderer'\nimport render from './render'\nimport requestAnimation from './requestAnimation'\nimport cancelAnimation from './cancelAnimation'\n\nimport mainRenderingMachineOptions from './Main/mainRenderingMachineOptions'\nimport layersRenderingMachineOptions from './Layers/layersRenderingMachineOptions'\nimport imagesRenderingMachineOptions from './Images/imagesRenderingMachineOptions'\nimport widgetsRenderingMachineOptions from './Widgets/widgetsRenderingMachineOptions'\n\nconst isNotAnimating = context =>\n  !context.renderWindow.getInteractor().isAnimating()\n\nconst vtkJSRenderingMachineOptions = {\n  main: mainRenderingMachineOptions,\n\n  layers: layersRenderingMachineOptions,\n\n  images: imagesRenderingMachineOptions,\n\n  widgets: widgetsRenderingMachineOptions,\n\n  actions: {\n    createRenderer,\n\n    render,\n    requestAnimation,\n    cancelAnimation,\n  },\n\n  guards: {\n    isNotAnimating,\n  },\n}\n\nexport default vtkJSRenderingMachineOptions\n"
  },
  {
    "path": "src/Rendering/Widgets/createWidgetsRenderingMachine.js",
    "content": "import { Machine, assign, spawn, send } from 'xstate'\n\nfunction createWidgetsRenderingMachine(options, context) {\n  return Machine(\n    {\n      id: 'widgetsRendering',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          always: {\n            target: 'active',\n            actions: 'createWidgets',\n          },\n        },\n        active: {\n          on: {\n            TOGGLE_DISTANCE_WIDGET: {\n              actions: 'toggleDistanceWidget',\n            },\n          },\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createWidgetsRenderingMachine\n"
  },
  {
    "path": "src/Rendering/createRenderingMachine.js",
    "content": "import { Machine, forwardTo, sendParent, send } from 'xstate'\n\nimport createMainRenderingMachine from './Main/createMainRenderingMachine'\nimport createLayersRenderingMachine from './Layers/createLayersRenderingMachine'\nimport createImagesRenderingMachine from './Images/createImagesRenderingMachine'\nimport createWidgetsRenderingMachine from './Widgets/createWidgetsRenderingMachine'\n\nconst createRenderingMachine = (options, context) => {\n  const { main, layers, images, widgets } = options\n  const mainMachine = createMainRenderingMachine(main, context)\n  const layersMachine = createLayersRenderingMachine(layers, context)\n  const imagesMachine = createImagesRenderingMachine(images, context)\n  const widgetsMachine = createWidgetsRenderingMachine(widgets, context)\n  return Machine(\n    {\n      id: 'rendering',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          always: {\n            target: 'active',\n            actions: ['createRenderer'],\n          },\n        },\n        active: {\n          invoke: [\n            {\n              id: 'main',\n              src: mainMachine,\n            },\n            {\n              id: 'layers',\n              src: layersMachine,\n            },\n            {\n              id: 'images',\n              src: imagesMachine,\n            },\n            {\n              id: 'widgets',\n              src: widgetsMachine,\n            },\n          ],\n          initial: 'idle',\n          states: {\n            idle: {\n              on: {\n                RENDER: {\n                  cond: 'isNotAnimating',\n                  target: 'render',\n                },\n              },\n            },\n            render: {\n              entry: 'render',\n              initial: 'waitingForRequest',\n              states: {\n                waitingForRequest: {\n                  on: { RENDER: 'renderRequested' },\n                },\n                renderRequested: {},\n              },\n              on: {\n                RENDERED: [\n                  {\n                    in: '#rendering.active.render.renderRequested', // got render request while rendering?\n                    cond: 'isNotAnimating',\n                    target: 'render', // loopback\n                  },\n                  { target: 'idle' },\n                ],\n              },\n              invoke: {\n                id: 'waitForAnimationFrame',\n                src: () => send => {\n                  let timeoutId\n                  const animationId = requestAnimationFrame(() => {\n                    timeoutId = setTimeout(() => send('RENDERED'), 0) // send after paint\n                  })\n                  return () => {\n                    cancelAnimationFrame(animationId)\n                    clearTimeout(timeoutId)\n                  }\n                },\n              },\n            },\n          },\n          on: {\n            BACKGROUND_TURNED_LIGHT: {\n              actions: sendParent('TOGGLE_DARK_MODE'),\n            },\n            BACKGROUND_TURNED_DARK: {\n              actions: sendParent('TOGGLE_DARK_MODE'),\n            },\n            UPDATE_FPS: {\n              actions: forwardTo('main'),\n            },\n            FPS_UPDATED: {\n              actions: [forwardTo('main'), forwardTo('images')],\n            },\n            SET_IMAGE_SCALE: {\n              actions: forwardTo('images'),\n            },\n            SET_CINEMATIC_PARAMETERS: {\n              actions: forwardTo('images'),\n            },\n            CINEMATIC_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            REQUEST_ANIMATION: {\n              actions: 'requestAnimation',\n            },\n            CANCEL_ANIMATION: {\n              actions: 'cancelAnimation',\n            },\n            SET_BACKGROUND_COLOR: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_BACKGROUND_COLOR: {\n              actions: forwardTo('main'),\n            },\n            SET_UNITS: {\n              actions: forwardTo('main'),\n            },\n            TAKE_SCREENSHOT: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_ROTATE: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_ANNOTATIONS: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_AXES: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_CROPPING_PLANES: {\n              actions: forwardTo('main'),\n            },\n            RESET_CROPPING_PLANES: {\n              actions: forwardTo('main'),\n            },\n            CROPPING_PLANES_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            CROPPING_PLANES_CHANGED_BY_USER: {\n              actions: forwardTo('images'),\n            },\n            VIEW_MODE_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            SLICING_PLANES_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            X_SLICE_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            Y_SLICE_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            Z_SLICE_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            RESET_CAMERA: {\n              actions: forwardTo('main'),\n            },\n            SELECT_LAYER: {\n              actions: forwardTo('images'),\n            },\n            TOGGLE_LAYER_VISIBILITY: {\n              actions: send((_, e) => e, {\n                to: (c, e) => {\n                  switch (c.layers.actorContext.get(e.data).type) {\n                    case 'image':\n                      return 'images'\n                    case 'labelImage':\n                      return 'images'\n                    default:\n                      console.error(`Unsupported layer type for ${e.data}`)\n                  }\n                },\n              }),\n            },\n            IMAGE_ASSIGNED: {\n              actions: forwardTo('images'),\n            },\n            UPDATE_RENDERED_IMAGE: {\n              actions: forwardTo('images'),\n            },\n            TOGGLE_IMAGE_INTERPOLATION: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_RANGE_BOUNDS_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_RANGE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_RANGE_MIN_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_RANGE_MAX_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_RANGE_POINTS_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_MAP_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COMPONENT_VISIBILITY_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_PIECEWISE_FUNCTION_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            TOGGLE_IMAGE_SHADOW: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_GRADIENT_OPACITY_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_GRADIENT_OPACITY_SCALE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_VOLUME_SAMPLE_DISTANCE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_BLEND_MODE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_ASSIGNED: {\n              actions: forwardTo('images'),\n            },\n            TOGGLE_DISTANCE_WIDGET: {\n              actions: forwardTo('widgets'),\n            },\n            LABEL_IMAGE_LOOKUP_TABLE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_BLEND_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_WEIGHTS_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_LABEL_NAMES_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_SELECTED_LABEL_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            UPDATE_IMAGE_HISTOGRAM: {\n              actions: forwardTo('images'),\n            },\n            SET_FIXED_IMAGE: {\n              actions: forwardTo('images'),\n            },\n            COMPARE_IMAGES: {\n              actions: forwardTo('images'),\n            },\n            ANIMATE_IMAGE_MIX: {\n              actions: forwardTo('images'),\n            },\n            WINDOW_LEVEL_TOGGLED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_RANGE_RESET: {\n              actions: forwardTo('images'),\n            },\n            TOGGLE_LAYER_BBOX: {\n              actions: forwardTo('images'),\n            },\n            DOWNLOAD_IMAGE: {\n              actions: forwardTo('images'),\n            },\n          },\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createRenderingMachine\n"
  },
  {
    "path": "src/Rendering/updateLabelMapComponentWeight.js",
    "content": "function updateLabelMapComponentWeight(store) {\n  if (!store.imageUI.haveLabelMap) {\n    return\n  }\n  const labelMapBlend = store.imageUI.labelMapBlend\n  const volume = store.imageUI.representationProxy.getVolumes()[0]\n  const volumeProperty = volume.getProperty()\n  const sliceActor = store.imageUI.representationProxy.getActors()[0]\n  const sliceProperty = sliceActor.getProperty()\n  const numberOfComponents = store.imageUI.numberOfComponents\n  const visualizedComponents = store.imageUI.visualizedComponents\n  const componentVisibilities = store.imageUI.componentVisibilities\n\n  visualizedComponents.forEach((componentIdx, fusedImgIdx) => {\n    const componentVisibility = componentVisibilities[componentIdx]\n    componentVisibility.weight = 1.0 - labelMapBlend\n    if (componentVisibility.visible) {\n      volumeProperty.setComponentWeight(fusedImgIdx, componentVisibility.weight)\n      sliceProperty.setComponentWeight(fusedImgIdx, componentVisibility.weight)\n    }\n  })\n\n  volumeProperty.setComponentWeight(numberOfComponents, labelMapBlend)\n  sliceProperty.setComponentWeight(numberOfComponents, labelMapBlend)\n}\n\nexport default updateLabelMapComponentWeight\n"
  },
  {
    "path": "src/UI/Images/createImagesUIMachine.js",
    "content": "import { Machine, assign, forwardTo } from 'xstate'\nimport { createTransferFunctionManipulators } from './transferFunctionManipulators'\n\nconst assignSelectedComponentIndex = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.selectedComponent = event.data.component\n    return images\n  },\n})\n\nconst assignComponentVisibility = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const actorContext = context.images.actorContext.get(name)\n    const componentVisibilities = actorContext.componentVisibilities\n    const index = event.data.component\n    const visibility = event.data.visibility\n\n    if (visibility && !componentVisibilities[index]) {\n      // A component was made visible, and it was not already in the list\n      // of visualized components\n      const currentNumVisualized = componentVisibilities.reduce(\n        (count, isVisible) => count + isVisible,\n        0\n      )\n      if (currentNumVisualized + 1 > actorContext.maxIntensityComponents) {\n        // Replace last touched component with turned on component\n        componentVisibilities[\n          actorContext.lastComponentVisibilityChanged\n        ] = false\n      }\n    }\n    if (visibility) actorContext.lastComponentVisibilityChanged = index\n\n    componentVisibilities[index] = visibility\n\n    return images\n  },\n})\n\nconst assignPiecewiseFunction = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const actorContext = context.images.actorContext.get(name)\n    const component = event.data.component\n    const range = event.data.range\n    const nodes = event.data.nodes\n\n    actorContext.piecewiseFunctions.set(component, { range, nodes })\n\n    return images\n  },\n})\n\nconst assignPiecewiseFunctionGaussians = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const actorContext = context.images.actorContext.get(name)\n    const component = event.data.component\n    const gaussians = event.data.gaussians\n\n    actorContext.piecewiseFunctionGaussians.set(component, gaussians)\n\n    return images\n  },\n})\n\nconst assignPiecewiseFunctionPoints = assign({\n  images: (\n    { images },\n    { data: { component, points, name, keepAutoAdjusting = true } }\n  ) => {\n    const {\n      piecewiseFunctionPoints,\n      piecewiseFunctionPointsAutoAdjust,\n    } = images.actorContext.get(name)\n    piecewiseFunctionPoints.set(component, points)\n\n    piecewiseFunctionPointsAutoAdjust.set(\n      component,\n      piecewiseFunctionPointsAutoAdjust.get(component) && keepAutoAdjusting\n    )\n\n    return images\n  },\n})\n\nconst assignColorMap = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const component = event.data.component\n    const colorMap = event.data.colorMap\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.colorMaps.set(component, colorMap)\n\n    return images\n  },\n})\n\nconst assignLookupTable = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const lookupTable = event.data.lookupTable\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.lookupTable = lookupTable\n\n    return images\n  },\n})\n\nconst assignShadowEnabled = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.shadowEnabled = !actorContext.shadowEnabled\n    return images\n  },\n})\n\nconst assignInterpolationEnabled = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.interpolationEnabled = !actorContext.interpolationEnabled\n    return images\n  },\n})\n\nconst assignGradientOpacity = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const gradientOpacity = event.data.gradientOpacity\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.gradientOpacity = gradientOpacity\n    return images\n  },\n})\n\nconst assignGradientOpacityScale = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const gradientOpacityScale = event.data.gradientOpacityScale\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.gradientOpacityScale = gradientOpacityScale\n    return images\n  },\n})\n\nconst assignVolumeSampleDistance = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const volumeSampleDistance = event.data.volumeSampleDistance\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.volumeSampleDistance = volumeSampleDistance\n    return images\n  },\n})\n\nconst assignBlendMode = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const blendMode = event.data.blendMode\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.blendMode = blendMode\n    return images\n  },\n})\n\nconst assignLabelImageBlend = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const labelImageBlend = event.data.labelImageBlend\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.labelImageBlend = labelImageBlend\n    return images\n  },\n})\n\nconst assignLabelImageWeights = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const labelImageWeights = event.data.labelImageWeights\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.labelImageWeights = labelImageWeights\n    return images\n  },\n})\n\nconst assignLabelNames = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const labelNames = event.data.labelNames\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.labelNames = labelNames\n    return images\n  },\n})\n\nconst assignSelectedLabel = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n    const selectedLabel = event.data.selectedLabel\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.selectedLabel = selectedLabel\n    return images\n  },\n})\n\nconst assignWindowLevelEnabled = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data.name\n\n    const actorContext = context.images.actorContext.get(name)\n    actorContext.windowLevelEnabled = !actorContext.windowLevelEnabled\n    return images\n  },\n})\n\nfunction createImagesUIMachine(options, context) {\n  return Machine(\n    {\n      id: 'images',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          on: {\n            IMAGE_ASSIGNED: {\n              target: 'active',\n              actions: ['createImagesInterface', 'updateImageInterface'],\n            },\n            LABEL_IMAGE_ASSIGNED: {\n              target: 'active',\n              actions: ['createImagesInterface', 'updateLabelImageInterface'],\n            },\n          },\n        },\n        active: {\n          invoke: [\n            {\n              id: 'scaleSelector',\n              src: 'scaleSelector',\n            },\n            {\n              id: 'transferFunctionManipulators',\n              src: createTransferFunctionManipulators,\n            },\n          ],\n          on: {\n            IMAGE_ASSIGNED: {\n              actions: [\n                'updateImageInterface',\n                'updateLabelImageInterface',\n                forwardTo('scaleSelector'),\n              ],\n            },\n            RENDERED_IMAGE_ASSIGNED: {\n              actions: [\n                'updateRenderedImageInterface',\n                forwardTo('scaleSelector'),\n              ],\n            },\n            IMAGE_RENDERING_ACTIVE: {\n              actions: forwardTo('scaleSelector'),\n            },\n            TOGGLE_IMAGE_INTERPOLATION: {\n              actions: [assignInterpolationEnabled, 'toggleInterpolation'],\n            },\n            SELECT_IMAGE_COMPONENT: {\n              actions: [\n                assignSelectedComponentIndex,\n                'selectImageComponent',\n                forwardTo('transferFunctionManipulators'),\n              ],\n            },\n            IMAGE_COMPONENT_VISIBILITY_CHANGED: {\n              actions: [assignComponentVisibility, 'applyComponentVisibility'],\n            },\n            IMAGE_PIECEWISE_FUNCTION_CHANGED: {\n              actions: assignPiecewiseFunction,\n            },\n            IMAGE_PIECEWISE_FUNCTION_GAUSSIANS_CHANGED: {\n              actions: [\n                assignPiecewiseFunctionGaussians,\n                'applyPiecewiseFunctionGaussians',\n              ],\n            },\n            IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED: {\n              actions: [\n                assignPiecewiseFunctionPoints,\n                'applyPiecewiseFunctionPointsToEditor',\n              ],\n            },\n            IMAGE_COLOR_RANGE_CHANGED: {\n              actions: [\n                'applyColorRange',\n                forwardTo('transferFunctionManipulators'),\n              ],\n            },\n            IMAGE_COLOR_RANGE_BOUNDS_CHANGED: {\n              actions: ['applyColorRangeBounds'],\n            },\n            IMAGE_COLOR_MAP_CHANGED: {\n              actions: assignColorMap,\n            },\n            IMAGE_COLOR_MAP_DEPENDENCIES_UPDATE: {\n              actions: 'applyColorMap',\n            },\n            TOGGLE_IMAGE_SHADOW: {\n              actions: [assignShadowEnabled, 'toggleShadow'],\n            },\n            IMAGE_GRADIENT_OPACITY_CHANGED: {\n              actions: [assignGradientOpacity, 'applyGradientOpacity'],\n            },\n            IMAGE_GRADIENT_OPACITY_SCALE_CHANGED: {\n              actions: [\n                assignGradientOpacityScale,\n                'applyGradientOpacityScale',\n              ],\n            },\n            IMAGE_VOLUME_SAMPLE_DISTANCE_CHANGED: {\n              actions: [\n                assignVolumeSampleDistance,\n                'applyVolumeSampleDistance',\n              ],\n            },\n            IMAGE_BLEND_MODE_CHANGED: {\n              actions: [assignBlendMode, 'applyBlendMode'],\n            },\n            IMAGE_HISTOGRAM_UPDATED: {\n              actions: ['applyHistogram'],\n            },\n            LABEL_IMAGE_ASSIGNED: {\n              actions: ['updateLabelImageInterface'],\n            },\n            LABEL_IMAGE_LOOKUP_TABLE_CHANGED: {\n              actions: [assignLookupTable, 'applyLookupTable'],\n            },\n            LABEL_IMAGE_BLEND_CHANGED: {\n              actions: [assignLabelImageBlend, 'applyLabelImageBlend'],\n            },\n            LABEL_IMAGE_WEIGHTS_CHANGED: {\n              actions: [assignLabelImageWeights, 'applyLabelImageWeights'],\n            },\n            LABEL_IMAGE_LABEL_NAMES_CHANGED: {\n              actions: [assignLabelNames, 'applyLabelNames'],\n            },\n            LABEL_IMAGE_SELECTED_LABEL_CHANGED: {\n              actions: [assignSelectedLabel, 'applySelectedLabel'],\n            },\n            CINEMATIC_CHANGED: { actions: 'applyCinematicChanged' },\n            COMPONENT_VISIBILITIES_UPDATED: {\n              actions: 'updateImageInterface',\n            },\n            WINDOW_LEVEL_TOGGLED: {\n              actions: [\n                assignWindowLevelEnabled,\n                'toggleWindowLevel',\n                forwardTo('transferFunctionManipulators'),\n              ],\n            },\n            IMAGE_COLOR_RANGE_RESET: {\n              actions: ['applyWindowLevelReset'],\n            },\n          },\n        },\n      },\n    },\n    // need scaleSelector service stub to avoid errors if overridden options does not define\n    { services: { scaleSelector: () => () => undefined }, ...options }\n  )\n}\n\nexport default createImagesUIMachine\n"
  },
  {
    "path": "src/UI/Images/transferFunctionManipulators.js",
    "content": "import vtkMouseRangeManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseRangeManipulator'\n\nconst MIN_WINDOW = 1e-8\n\nexport const createTransferFunctionManipulators = context => (\n  callback,\n  onReceive\n) => {\n  const getPoints = () => {\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const component = actorContext.selectedComponent\n    return actorContext.piecewiseFunctionPoints.get(component)\n  }\n\n  const setPoints = points => {\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const component = actorContext.selectedComponent\n    context.service.send({\n      type: 'IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED',\n      data: {\n        name,\n        component,\n        points,\n        keepAutoAdjusting: false,\n      },\n    })\n  }\n\n  const newRange = (width, level) => {\n    return [level - width / 2, level + width / 2]\n  }\n\n  const windowGet = () => {\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const component = actorContext.selectedComponent\n    const [lower, upper] = actorContext.colorRanges.get(component)\n    return upper - lower\n  }\n\n  const windowSet = newWidth => {\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const component = actorContext.selectedComponent\n    context.service.send({\n      type: 'IMAGE_COLOR_RANGE_CHANGED',\n      data: {\n        name: context.images.selectedName,\n        component,\n        range: newRange(newWidth, levelGet()),\n      },\n    })\n  }\n\n  const levelGet = () => {\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const component = actorContext.selectedComponent\n    const [lower, upper] = actorContext.colorRanges.get(component)\n    return (upper + lower) / 2\n  }\n\n  const levelSet = newLevel => {\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const component = actorContext.selectedComponent\n    context.service.send({\n      type: 'IMAGE_COLOR_RANGE_CHANGED',\n      data: {\n        name: context.images.selectedName,\n        component,\n        range: newRange(windowGet(), newLevel),\n      },\n    })\n  }\n\n  // pan\n  const manipulator2D = context.itkVtkView\n    .getInteractorStyle2D()\n    .findMouseManipulator(1, false, false, false)\n  // rotate\n  const manipulator3D = context.itkVtkView\n    .getInteractorStyle3D()\n    .findMouseManipulator(1, false, false, false)\n  // window/level\n  const rangeManipulator = vtkMouseRangeManipulator.newInstance({\n    button: 1,\n  })\n\n  const pwfGet = () => {\n    const opacities = getPoints().map(([, y]) => y)\n    return Math.max(...opacities)\n  }\n  const pwfSet = newMaxOpacity => {\n    const oldMax = pwfGet()\n    const delta = newMaxOpacity - oldMax\n    const newPoints = getPoints().map(([x, y]) => [x, Math.min(y + delta, 1)])\n    setPoints(newPoints)\n  }\n  // opacity up/down\n  const pwfRangeManipulator = vtkMouseRangeManipulator.newInstance({\n    button: 3, // Right mouse\n    alt: true,\n  })\n  const pwfRangeManipulatorShift = vtkMouseRangeManipulator.newInstance({\n    button: 1, // Left mouse\n    shift: true, // For the macOS folks\n    alt: true,\n  })\n\n  // max as 1.01 not 1.0 to allow for squishing of low function points if a point is already at 1\n  pwfRangeManipulator.setVerticalListener(0, 1.01, 0.01, pwfGet, pwfSet)\n  pwfRangeManipulatorShift.setVerticalListener(0, 1.01, 0.01, pwfGet, pwfSet)\n  ;[rangeManipulator, pwfRangeManipulator, pwfRangeManipulatorShift].forEach(\n    m => {\n      context.itkVtkView.getInteractorStyle2D().addMouseManipulator(m)\n      context.itkVtkView.getInteractorStyle3D().addMouseManipulator(m)\n    }\n  )\n\n  const applyColorRange = (context, event) => {\n    const name = event.data.name\n    const component = event.data.component\n    const actorContext = context.images.actorContext.get(name)\n\n    if (\n      name !== context.images.selectedName ||\n      component !== actorContext.selectedComponent\n    ) {\n      return\n    }\n\n    const colorRange = event.data.range\n\n    let fullRange = colorRange\n    if (actorContext.colorRangeBounds.has(component)) {\n      fullRange = actorContext.colorRangeBounds.get(component)\n    }\n    const diff = fullRange[1] - fullRange[0]\n\n    // level\n    rangeManipulator.setVerticalListener(\n      fullRange[0] - diff,\n      fullRange[1] + diff,\n      Math.min(diff, 1) / 256,\n      levelGet,\n      levelSet\n    )\n\n    // window\n    rangeManipulator.setHorizontalListener(\n      MIN_WINDOW,\n      diff * 2,\n      Math.min(diff, 1) / 256,\n      windowGet,\n      windowSet\n    )\n  }\n\n  onReceive(event => {\n    const { type } = event\n    const name = event.data.name\n    const actorContext = context.images.actorContext.get(name)\n    const component = event.data.component\n    if (type === 'WINDOW_LEVEL_TOGGLED') {\n      if (actorContext.windowLevelEnabled) {\n        context.itkVtkView\n          .getInteractorStyle2D()\n          .removeMouseManipulator(manipulator2D)\n        context.itkVtkView\n          .getInteractorStyle3D()\n          .removeMouseManipulator(manipulator3D)\n        context.itkVtkView\n          .getInteractorStyle2D()\n          .addMouseManipulator(rangeManipulator)\n        context.itkVtkView\n          .getInteractorStyle3D()\n          .addMouseManipulator(rangeManipulator)\n      } else {\n        context.itkVtkView\n          .getInteractorStyle2D()\n          .removeMouseManipulator(rangeManipulator)\n        context.itkVtkView\n          .getInteractorStyle3D()\n          .removeMouseManipulator(rangeManipulator)\n        context.itkVtkView\n          .getInteractorStyle2D()\n          .addMouseManipulator(manipulator2D)\n        context.itkVtkView\n          .getInteractorStyle3D()\n          .addMouseManipulator(manipulator3D)\n      }\n    }\n    if (\n      actorContext.windowLevelEnabled &&\n      (type === 'SELECT_IMAGE_COMPONENT' ||\n        type === 'IMAGE_COLOR_RANGE_CHANGED' ||\n        type === 'WINDOW_LEVEL_TOGGLED')\n    ) {\n      if (\n        actorContext.selectedComponent === component &&\n        actorContext.colorRanges.has(component)\n      ) {\n        const range = actorContext.colorRanges.get(component)\n        applyColorRange(context, {\n          data: {\n            name,\n            component,\n            range,\n          },\n        })\n      }\n    }\n  })\n}\n"
  },
  {
    "path": "src/UI/Layers/createLayerUIActor.js",
    "content": "import { Machine, assign } from 'xstate'\n\nconst assignLayerVisibility = assign({\n  layers: (context, event) => {\n    const layers = context.layers\n    const name = event.data\n    const actorContext = layers.actorContext.get(name)\n    actorContext.visible = !actorContext.visible\n    layers.actorContext.set(name, actorContext)\n    return layers\n  },\n})\n\nconst createLayerUIActor = (options, context, actorContext) => {\n  return Machine(\n    {\n      id: 'layerUI',\n      initial: 'active',\n      context: { actorContext, ...context },\n      states: {\n        active: {\n          entry: 'createLayerInterface',\n          on: {\n            SELECT_LAYER: {\n              actions: 'selectLayer',\n            },\n            TOGGLE_LAYER_VISIBILITY: {\n              actions: [assignLayerVisibility, 'toggleLayerVisibility'],\n            },\n          },\n          initial: 'idle',\n          states: {\n            idle: {\n              entry: 'finishDataUpdate',\n              on: { START_DATA_UPDATE: 'dataUpdating' },\n            },\n            dataUpdating: {\n              entry: 'startDataUpdate',\n              on: { FINISH_DATA_UPDATE: 'dataLoading' },\n            },\n            dataLoading: {\n              // wait until data is loaded on GPU\n              on: { POST_RENDER: 'idle' },\n            },\n          },\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createLayerUIActor\n"
  },
  {
    "path": "src/UI/Layers/createLayersUIMachine.js",
    "content": "import { Machine, assign, spawn, send, actions, forwardTo } from 'xstate'\n\nimport { PixelTypes } from 'itk-wasm'\n\nimport createLayerUIActor from './createLayerUIActor'\nimport LayerActorContext from '../../Context/LayerActorContext'\nimport ImageActorContext from '../../Context/ImageActorContext'\nimport { getOutputIntensityComponentCount } from '../../Rendering/Images/createImageRenderingActor'\n\nfunction resize(arr, newSize, defaultValue) {\n  return [\n    ...arr,\n    ...Array(Math.max(newSize - arr.length, 0)).fill(defaultValue),\n  ]\n}\n\nfunction spawnLayerRenderingActor(options) {\n  return assign({\n    layers: (context, event) => {\n      const layers = context.layers\n      switch (event.type) {\n        case 'ADD_IMAGE': {\n          let name = event.data.name\n          // Ensure unique name\n          let nameNumber = 0\n          while (layers.layerUIActors.has(name)) {\n            name = `${event.data.name}-${nameNumber + 1}`\n            nameNumber++\n          }\n          const actorContext =\n            layers.actorContext.get(name) ?? new LayerActorContext()\n          actorContext.type = 'image'\n          actorContext.bbox = false\n          layers.actorContext.set(name, actorContext)\n          layers.lastAddedData = { name, data: event.data }\n          layers.layerUIActors.set(\n            name,\n            spawn(\n              createLayerUIActor(options, context, actorContext),\n              `layerUIActor-${name}`,\n              actorContext\n            )\n          )\n          break\n        }\n        case 'ADD_LABEL_IMAGE': {\n          let name = event.data.labelImage.name\n          // Ensure unique name\n          let nameNumber = 0\n          while (layers.layerUIActors.has(name)) {\n            name = `${event.data.labelImage.name}-${nameNumber + 1}`\n            nameNumber++\n          }\n          const actorContext =\n            layers.actorContext.get(name) ?? new LayerActorContext()\n          actorContext.type = 'labelImage'\n          actorContext.bbox = false\n          layers.actorContext.set(name, actorContext)\n          layers.lastAddedData = { name, data: event.data }\n          layers.layerUIActors.set(\n            name,\n            spawn(\n              createLayerUIActor(options, context, actorContext),\n              `layerUIActor-${name}`\n            )\n          )\n          break\n        }\n        default:\n          throw new Error(`Unexpected event type: ${event.type}`)\n      }\n      return layers\n    },\n  })\n}\n\nconst assignImageContext = assign({\n  images: context => {\n    const images = context.images\n    let actorName = null\n    let image = null\n    let labelImage = null\n    let imageName = null\n    let labelImageName = null\n\n    if ('labelImage' in context.layers.lastAddedData.data) {\n      labelImage = context.layers.lastAddedData.data.labelImage\n      imageName =\n        context.layers.lastAddedData.data.imageName ??\n        context.images.selectedName\n      actorName = imageName ?? context.layers.lastAddedData.data.labelImage.name\n      labelImageName = context.layers.lastAddedData.name\n    } else {\n      imageName = context.layers.lastAddedData.name\n      // find Map key with ImageActorContext with matching image name.  Needed if image loaded after labelImage\n      const [keyName] =\n        Array.from(images.actorContext.entries()).find(\n          ([, { imageName: actorImageName }]) => actorImageName === imageName\n        ) ?? []\n      actorName = keyName ?? imageName\n    }\n\n    images.selectedName = actorName\n    const actorContext =\n      images.actorContext.get(actorName) ?? new ImageActorContext()\n\n    let layerContext\n    if (labelImage) {\n      if (\n        actorContext.image &&\n        labelImage.imageType.dimension !==\n          actorContext.image.imageType.dimension\n      )\n        throw new Error('Label image dimensions do not match Image dimensions')\n\n      actorContext.labelImage = labelImage\n      actorContext.labelImageName = labelImageName\n      layerContext = context.layers.actorContext.get(labelImageName)\n      actorContext.imageName = imageName ?? 'Image'\n    } else {\n      if (\n        actorContext.labelImage &&\n        image.imageType.dimensions !==\n          actorContext.labelImage.imageType.dimensions\n      )\n        throw new Error('Label image dimensions do not match Image dimensions')\n\n      image = context.layers.lastAddedData.data\n      actorContext.image = image\n      layerContext = context.layers.actorContext.get(imageName)\n    }\n    layerContext.imageActorContext = actorContext\n\n    images.actorContext.set(actorName, actorContext)\n\n    if (image === null) {\n      return images\n    }\n\n    const components = image.imageType.components\n\n    // Assign default independentComponents\n    if (actorContext.independentComponents === null) {\n      // If a 2D RGB image\n      if (\n        image.imageType.pixelType === PixelTypes.RGB ||\n        image.imageType.pixelType === PixelTypes.RGBA\n      ) {\n        actorContext.independentComponents = false\n      } else {\n        actorContext.independentComponents = true\n      }\n    }\n\n    // Assign default colorMaps\n    for (let component = 0; component < components; component++) {\n      if (actorContext.colorMaps.has(component)) {\n        continue\n      }\n      let colorMap = 'CT-Chest-Vessels'\n      // If a 2D RGB or RGBA\n      if (components === 2) {\n        switch (component) {\n          case 0:\n            colorMap = 'BkMa'\n            break\n          case 1:\n            colorMap = 'BkCy'\n            break\n        }\n      } else if (actorContext.independentComponents) {\n        if (components === 3) {\n          switch (component) {\n            case 0:\n              colorMap = 'BkRd'\n              break\n            case 1:\n              colorMap = 'BkGn'\n              break\n            case 2:\n              colorMap = 'BkBu'\n              break\n          }\n        } else if (components >= 4) {\n          switch (component) {\n            case 0:\n              colorMap = 'BkRd'\n              break\n            case 1:\n              colorMap = 'BkGn'\n              break\n            case 2:\n              colorMap = 'BkBu'\n              break\n            case 3:\n              colorMap = 'Grayscale'\n              break\n          }\n        }\n      }\n      actorContext.colorMaps.set(component, colorMap)\n    }\n\n    for (let component = 0; component < components; component++) {\n      if (!actorContext.piecewiseFunctionPoints.has(component)) {\n        // Assign default piecewiseFunction\n        const points = context.use2D\n          ? [[0.5, 1]]\n          : [\n              [0, 0],\n              [0.9, 0.9],\n            ]\n        if (context.use2D && components === 1) {\n          // For 2D ImageMapper, if multiple components,\n          // opacity function sets component contribution factor.\n          // If just 1 component, opacity function is irrelevant.\n          points.length = 0\n        }\n        actorContext.piecewiseFunctionPoints.set(component, points)\n      }\n      actorContext.colorRanges.set(component, [0.2, 0.8])\n    }\n\n    // make Maps like this: { 0: true, 1: true, ... n: true}\n    const trueForAll = [...Array(components).keys()].map(c => [c, true])\n    actorContext.colorRangeMinAutoAdjust = new Map([...trueForAll])\n    actorContext.colorRangeMaxAutoAdjust = new Map([...trueForAll])\n    actorContext.colorRangeBoundsAutoAdjust = new Map([...trueForAll])\n    actorContext.piecewiseFunctionPointsAutoAdjust = new Map([...trueForAll])\n\n    return images\n  },\n})\n\nconst assignComponentVisibilities = assign({\n  images: ({ images }, event) => {\n    const actorContext = images.actorContext.get(event.data.name)\n\n    const componentCount = getOutputIntensityComponentCount(actorContext)\n\n    actorContext.componentVisibilities = resize(\n      actorContext.componentVisibilities,\n      componentCount,\n      true\n    )\n\n    return images\n  },\n})\n\nconst sendComponentVisibilitiesUpdated = (c, { data: { name } }) => {\n  c.service.send({\n    type: 'COMPONENT_VISIBILITIES_UPDATED',\n    data: { name },\n  })\n}\n\nconst assignSelectedName = assign({\n  images: (context, event) => {\n    const images = context.images\n    const name = event.data\n    const type = context.layers.layersUIActors.get(name).type\n    if (type === 'image' || type === 'labelImage') {\n      images.selectedName = name\n    }\n    return images\n  },\n})\n\nconst forwardToNamedActor = send((_, e) => e, {\n  to: (c, e) => `layerUIActor-${e.name}`,\n})\n\nconst sendEventToAllActors = actions.pure(\n  ({ layers: { layerUIActors } }, event) =>\n    Array.from(layerUIActors?.values() ?? []).map(actor =>\n      send(event, {\n        to: actor,\n      })\n    )\n)\n\nfunction createLayersUIMachine(options, context) {\n  const { layerUIActor } = options\n\n  return Machine(\n    {\n      id: 'layers',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          always: {\n            target: 'active',\n            actions: ['createLayersInterface'],\n          },\n        },\n        active: {\n          invoke: [\n            {\n              id: 'compareUI',\n              src: 'compareUI',\n            },\n          ],\n          on: {\n            SELECT_LAYER: {\n              assignSelectedName,\n              actions: [\n                send((_, e) => e, {\n                  to: (c, e) => `layerUIActor-${e.data}`,\n                }),\n              ],\n            },\n            TOGGLE_LAYER_VISIBILITY: {\n              actions: send((_, e) => e, {\n                to: (c, e) => `layerUIActor-${e.data}`,\n              }),\n            },\n            ADD_IMAGE: {\n              actions: [\n                spawnLayerRenderingActor(layerUIActor),\n                assignImageContext,\n                assignComponentVisibilities,\n                c =>\n                  c.service.send({\n                    type: 'IMAGE_ASSIGNED',\n                    data: c.images.selectedName,\n                  }),\n                c =>\n                  c.service.send({\n                    type: 'SELECT_LAYER',\n                    data: c.images.selectedName,\n                  }),\n              ],\n            },\n            ADD_LABEL_IMAGE: {\n              actions: [\n                spawnLayerRenderingActor(layerUIActor),\n                assignImageContext,\n                c =>\n                  c.service.send({\n                    type: 'LABEL_IMAGE_ASSIGNED',\n                    data: c.images.selectedName,\n                  }),\n                c =>\n                  c.service.send({\n                    type: 'SELECT_LAYER',\n                    data: c.images.selectedName,\n                  }),\n              ],\n            },\n            START_DATA_UPDATE: { actions: forwardToNamedActor },\n            FINISH_DATA_UPDATE: { actions: forwardToNamedActor },\n            POST_RENDER: { actions: sendEventToAllActors },\n            COMPARE_UPDATED: {\n              actions: [\n                assignComponentVisibilities,\n                sendComponentVisibilitiesUpdated,\n                send((_, e) => e, {\n                  to: (c, e) => `layerUIActor-${e.data.name}`,\n                }),\n                forwardTo('compareUI'),\n              ],\n            },\n          },\n        },\n      },\n    },\n    // need service stub to avoid errors if overridden options does not define\n    { services: { compareUI: () => () => undefined }, ...options }\n  )\n}\n\nexport default createLayersUIMachine\n"
  },
  {
    "path": "src/UI/Main/createMainUIMachine.js",
    "content": "import { Machine, assign } from 'xstate'\n\nconst assignFullscreenEnabled = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.fullscreenEnabled = !main.fullscreenEnabled\n    return main\n  },\n})\n\nconst assignAnnotationsEnabled = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.annotationsEnabled = !main.annotationsEnabled\n    return main\n  },\n})\n\nconst assignRotateEnabled = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.rotateEnabled = !main.rotateEnabled\n    return main\n  },\n})\n\nconst assignAxesEnabled = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.axesEnabled = !main.axesEnabled\n    return main\n  },\n})\n\nconst assignCroppingPlanesEnabled = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.croppingPlanesEnabled = !main.croppingPlanesEnabled\n    return main\n  },\n})\n\nconst assignCroppingPlanes = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.croppingPlanes = event.data\n    return main\n  },\n})\n\nconst assignViewMode = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.viewMode = event.data\n    return main\n  },\n})\n\nconst assignSlicingPlanes = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.slicingPlanes = event.data\n    return main\n  },\n})\n\nconst assignXSlice = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.xSlice = event.data\n    return main\n  },\n})\n\nconst assignYSlice = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.ySlice = event.data\n    return main\n  },\n})\n\nconst assignZSlice = assign({\n  main: (context, event) => {\n    const main = context.main\n    main.zSlice = event.data\n    return main\n  },\n})\n\nfunction createMainUIMachine(options, context) {\n  let initialViewMode = 'volume'\n  switch (context.main.viewMode) {\n    case 'XPlane':\n      initialViewMode = 'xPlane'\n      break\n    case 'YPlane':\n      initialViewMode = 'yPlane'\n      break\n    case 'ZPlane':\n      initialViewMode = 'zPlane'\n      break\n    case 'Volume':\n      initialViewMode = 'volume'\n      break\n    default:\n      throw new Error(`Invalid initial view mode: ${context.main.viewMode}`)\n  }\n\n  return Machine(\n    {\n      id: 'main',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          always: {\n            target: 'active',\n            actions: ['createMainInterface'],\n          },\n        },\n        active: {\n          type: 'parallel',\n          on: {\n            TOGGLE_BACKGROUND_COLOR: {\n              actions: 'toggleBackgroundColor',\n            },\n            SLICING_PLANES_CHANGED: {\n              actions: [assignSlicingPlanes, 'applySlicingPlanes'],\n            },\n            X_SLICE_CHANGED: {\n              actions: [assignXSlice, 'applyXSlice'],\n            },\n            Y_SLICE_CHANGED: {\n              actions: [assignYSlice, 'applyYSlice'],\n            },\n            Z_SLICE_CHANGED: {\n              actions: [assignZSlice, 'applyZSlice'],\n            },\n            CROPPING_PLANES_CHANGED: {\n              actions: assignCroppingPlanes,\n            },\n          },\n          states: {\n            fullscreen: {\n              initial: context.fullscreenEnabled ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  exit: 'toggleFullscreen',\n                  on: {\n                    TOGGLE_FULLSCREEN: {\n                      target: 'disabled',\n                      actions: assignFullscreenEnabled,\n                    },\n                    DISABLE_FULLSCREEN: {\n                      target: 'disabled',\n                      actions: assignFullscreenEnabled,\n                    },\n                  },\n                },\n                disabled: {\n                  exit: 'toggleFullscreen',\n                  on: {\n                    TOGGLE_FULLSCREEN: {\n                      target: 'enabled',\n                      actions: assignFullscreenEnabled,\n                    },\n                  },\n                },\n              },\n            },\n            annotations: {\n              initial: context.annotationsEnabled ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleAnnotations',\n                  on: {\n                    TOGGLE_ANNOTATIONS: {\n                      target: 'disabled',\n                      actions: assignAnnotationsEnabled,\n                    },\n                  },\n                },\n                disabled: {\n                  entry: 'toggleAnnotations',\n                  on: {\n                    TOGGLE_ANNOTATIONS: {\n                      target: 'enabled',\n                      actions: assignAnnotationsEnabled,\n                    },\n                  },\n                },\n              },\n            },\n            rotate: {\n              initial: context.rotateEnabled ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleRotate',\n                  on: {\n                    TOGGLE_ROTATE: {\n                      target: 'disabled',\n                      actions: assignRotateEnabled,\n                    },\n                  },\n                },\n                disabled: {\n                  entry: 'toggleRotate',\n                  on: {\n                    TOGGLE_ROTATE: {\n                      target: 'enabled',\n                      actions: assignRotateEnabled,\n                    },\n                  },\n                },\n              },\n            },\n            axes: {\n              initial: context.axesEnabled ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleAxes',\n                  on: {\n                    TOGGLE_AXES: {\n                      target: 'disabled',\n                      actions: assignAxesEnabled,\n                    },\n                  },\n                },\n                disabled: {\n                  entry: 'toggleAxes',\n                  on: {\n                    TOGGLE_AXES: {\n                      target: 'enabled',\n                      actions: assignAxesEnabled,\n                    },\n                  },\n                },\n              },\n            },\n            croppingPlanes: {\n              initial: context.croppingPlanesEnabled ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleCroppingPlanes',\n                  on: {\n                    TOGGLE_CROPPING_PLANES: {\n                      target: 'disabled',\n                      actions: assignCroppingPlanesEnabled,\n                    },\n                  },\n                },\n                disabled: {\n                  entry: 'toggleCroppingPlanes',\n                  on: {\n                    TOGGLE_CROPPING_PLANES: {\n                      target: 'enabled',\n                      actions: assignCroppingPlanesEnabled,\n                    },\n                  },\n                },\n              },\n            },\n            viewMode: {\n              initial: initialViewMode,\n              states: {\n                xPlane: {\n                  entry: 'viewModeXPlane',\n                },\n                yPlane: {\n                  entry: 'viewModeYPlane',\n                },\n                zPlane: {\n                  entry: 'viewModeZPlane',\n                },\n                volume: {\n                  entry: 'viewModeVolume',\n                },\n              },\n              on: {\n                VIEW_MODE_CHANGED: [\n                  {\n                    target: '.xPlane',\n                    cond: (c, e) => e.data === 'XPlane',\n                    actions: assignViewMode,\n                  },\n                  {\n                    target: '.yPlane',\n                    cond: (c, e) => e.data === 'YPlane',\n                    actions: assignViewMode,\n                  },\n                  {\n                    target: '.zPlane',\n                    cond: (c, e) => e.data === 'ZPlane',\n                    actions: assignViewMode,\n                  },\n                  {\n                    target: '.volume',\n                    cond: (c, e) => e.data === 'Volume',\n                    actions: assignViewMode,\n                  },\n                ],\n              },\n            },\n          },\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createMainUIMachine\n"
  },
  {
    "path": "src/UI/Widgets/createWidgetsUIMachine.js",
    "content": "import { Machine, assign } from 'xstate'\n\nconst assignDistanceEnabled = assign({\n  widgets: (context, event) => {\n    const widgets = context.widgets\n    widgets.distanceEnabled = !widgets.distanceEnabled\n    return widgets\n  },\n})\n\nconst assignDistanceWidgetValue = assign({\n  widgets: (context, event) => {\n    const widgets = context.widgets\n    widgets.distanceValue = event.data\n    return widgets\n  },\n})\n\nfunction createWidgetsUIMachine(options, context) {\n  let initialViewMode = 'volume'\n  switch (context.main.viewMode) {\n    case 'XPlane':\n      initialViewMode = 'xPlane'\n      break\n    case 'YPlane':\n      initialViewMode = 'yPlane'\n      break\n    case 'ZPlane':\n      initialViewMode = 'zPlane'\n      break\n    case 'Volume':\n      initialViewMode = 'volume'\n      break\n    default:\n      throw new Error(`Invalid initial view mode: ${context.main.viewMode}`)\n  }\n\n  return Machine(\n    {\n      id: 'widgets',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          always: {\n            target: 'active',\n            actions: ['createWidgetsInterface'],\n          },\n        },\n        active: {\n          type: 'parallel',\n          on: {\n            DISTANCE_WIDGET_VALUE_CHANGED: {\n              actions: [assignDistanceWidgetValue, 'applyDistanceWidgetValue'],\n            },\n          },\n          states: {\n            distanceWidget: {\n              initial: context.widgets.distanceEnabled ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleDistanceWidget',\n                  on: {\n                    TOGGLE_DISTANCE_WIDGET: {\n                      target: 'disabled',\n                      actions: [assignDistanceEnabled, 'toggleDistanceWidget'],\n                    },\n                  },\n                },\n                disabled: {\n                  entry: 'toggleDistanceWidget',\n                  on: {\n                    TOGGLE_DISTANCE_WIDGET: {\n                      target: 'enabled',\n                      actions: [assignDistanceEnabled, 'toggleDistanceWidget'],\n                    },\n                  },\n                },\n              },\n            },\n            viewMode: {\n              initial: initialViewMode,\n              states: {\n                xPlane: {\n                  entry: 'viewModeXPlane',\n                },\n                yPlane: {\n                  entry: 'viewModeYPlane',\n                },\n                zPlane: {\n                  entry: 'viewModeZPlane',\n                },\n                volume: {\n                  entry: 'viewModeVolume',\n                },\n              },\n              on: {\n                VIEW_MODE_CHANGED: [\n                  {\n                    target: '.xPlane',\n                    cond: (c, e) => e.data === 'XPlane',\n                  },\n                  {\n                    target: '.yPlane',\n                    cond: (c, e) => e.data === 'YPlane',\n                  },\n                  {\n                    target: '.zPlane',\n                    cond: (c, e) => e.data === 'ZPlane',\n                  },\n                  {\n                    target: '.volume',\n                    cond: (c, e) => e.data === 'Volume',\n                  },\n                ],\n              },\n            },\n          },\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createWidgetsUIMachine\n"
  },
  {
    "path": "src/UI/addKeyboardShortcuts.js",
    "content": "import Mousetrap from 'mousetrap'\nimport preventDefaults from '../UserInterface/preventDefaults'\n\nconst MOUSETRAP = new Mousetrap()\n\nconst addKeyboardShortcuts = (container, service) => {\n  container.addEventListener('mouseenter', () => {\n    MOUSETRAP.bind('1', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send({ type: 'VIEW_MODE_CHANGED', data: 'XPlane' })\n    })\n    MOUSETRAP.bind('alt+1', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send({ type: 'VIEW_MODE_CHANGED', data: 'XPlane' })\n    })\n    MOUSETRAP.bind('2', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send({ type: 'VIEW_MODE_CHANGED', data: 'YPlane' })\n    })\n    MOUSETRAP.bind('alt+2', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send({ type: 'VIEW_MODE_CHANGED', data: 'YPlane' })\n    })\n    MOUSETRAP.bind('3', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send({ type: 'VIEW_MODE_CHANGED', data: 'ZPlane' })\n    })\n    MOUSETRAP.bind('alt+3', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send({ type: 'VIEW_MODE_CHANGED', data: 'ZPlane' })\n    })\n    MOUSETRAP.bind('4', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send({ type: 'VIEW_MODE_CHANGED', data: 'Volume' })\n    })\n    MOUSETRAP.bind('alt+4', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send({ type: 'VIEW_MODE_CHANGED', data: 'Volume' })\n    })\n    MOUSETRAP.bind('r', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('RESET_CAMERA')\n    })\n    MOUSETRAP.bind('alt+r', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('RESET_CAMERA')\n    })\n    MOUSETRAP.bind('p', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('RESET_CAMERA')\n    })\n    MOUSETRAP.bind('alt+p', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('RESET_CAMERA')\n    })\n    MOUSETRAP.bind('e', function(event) {\n      preventDefaults(event)\n      service.send('RESET_CROPPING_PLANES')\n    })\n    MOUSETRAP.bind('alt+e', function(event) {\n      preventDefaults(event)\n      service.send('RESET_CROPPING_PLANES')\n    })\n    MOUSETRAP.bind('w', function(event) {\n      preventDefaults(event)\n      service.send('TOGGLE_CROPPING_PLANES')\n    })\n    MOUSETRAP.bind('alt+w', function(event) {\n      preventDefaults(event)\n      service.send('TOGGLE_CROPPING_PLANES')\n    })\n    MOUSETRAP.bind('q', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('TOGGLE_UI_COLLAPSED')\n    })\n    MOUSETRAP.bind('alt+q', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('TOGGLE_UI_COLLAPSED')\n    })\n    MOUSETRAP.bind('f', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('TOGGLE_FULLSCREEN')\n    })\n    MOUSETRAP.bind('alt+f', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('TOGGLE_FULLSCREEN')\n    })\n    //MOUSETRAP.bind('u', function(event /*, combo*/) {\n    //preventDefaults(event)\n    //const toggleFullscreenButton = document.getElementById(\n    //`${viewerDOMId}-toggleFullscreenButton`\n    //)\n    //toggleFullscreenButton.click()\n    //})\n    //MOUSETRAP.bind('alt+u', function(event /*, combo*/) {\n    //preventDefaults(event)\n    //const toggleFullscreenButton = document.getElementById(\n    //`${viewerDOMId}-toggleFullscreenButton`\n    //)\n    //toggleFullscreenButton.click()\n    //})\n    //MOUSETRAP.bind('s', function(event /*, combo*/) {\n    //preventDefaults(event)\n    //const toggleSlicingPlanesButton = document.getElementById(\n    //`${viewerDOMId}-toggleSlicingPlanesButton`\n    //)\n    //toggleSlicingPlanesButton.click()\n    //})\n    //MOUSETRAP.bind('alt+s', function(event /*, combo*/) {\n    //preventDefaults(event)\n    //const toggleSlicingPlanesButton = document.getElementById(\n    //`${viewerDOMId}-toggleSlicingPlanesButton`\n    //)\n    //toggleSlicingPlanesButton.click()\n    //})\n    //MOUSETRAP.bind('o', function(event /*, combo*/) {\n    //preventDefaults(event)\n    //const toggleSlicingPlanesButton = document.getElementById(\n    //`${viewerDOMId}-toggleSlicingPlanesButton`\n    //)\n    //toggleSlicingPlanesButton.click()\n    //})\n    //MOUSETRAP.bind('alt+o', function(event /*, combo*/) {\n    //preventDefaults(event)\n    //const toggleSlicingPlanesButton = document.getElementById(\n    //`${viewerDOMId}-toggleSlicingPlanesButton`\n    //)\n    //toggleSlicingPlanesButton.click()\n    //})\n    MOUSETRAP.bind('p', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('TOGGLE_ROTATE')\n    })\n    MOUSETRAP.bind('alt+p', function(event /*, combo*/) {\n      preventDefaults(event)\n      service.send('TOGGLE_ROTATE')\n    })\n    // MOUSETRAP.bind('c', function(event /*, combo*/) {\n    //   preventDefaults(event)\n    //   const config = context.getConfig()\n    //   const blob = new Blob([JSON.stringify(config)], {\n    //     type: 'text/plain;charset=utf-8',\n    //   })\n    //   saveAs(blob, 'viewerConfig.json')\n    // })\n    // MOUSETRAP.bind('alt+c', function(event /*, combo*/) {\n    //   preventDefaults(event)\n    //   const config = context.getConfig()\n    //   const blob = new Blob([JSON.stringify(config)], {\n    //     type: 'text/plain;charset=utf-8',\n    //   })\n    //   saveAs(blob, 'viewerConfig.json')\n    // })\n  })\n\n  container.addEventListener('mouseleave', () => {\n    MOUSETRAP.unbind('1')\n    MOUSETRAP.unbind('alt+1')\n    MOUSETRAP.unbind('2')\n    MOUSETRAP.unbind('alt+2')\n    MOUSETRAP.unbind('3')\n    MOUSETRAP.unbind('alt+3')\n    MOUSETRAP.unbind('4')\n    MOUSETRAP.unbind('alt+4')\n    MOUSETRAP.unbind('r')\n    MOUSETRAP.unbind('alt+r')\n    MOUSETRAP.unbind('p')\n    MOUSETRAP.unbind('alt+p')\n    MOUSETRAP.unbind('e')\n    MOUSETRAP.unbind('alt+e')\n    MOUSETRAP.unbind('w')\n    MOUSETRAP.unbind('alt+w')\n    MOUSETRAP.unbind('.')\n    MOUSETRAP.unbind('alt+.')\n    MOUSETRAP.unbind('w')\n    MOUSETRAP.unbind('alt+w')\n    MOUSETRAP.unbind(',')\n    MOUSETRAP.unbind('alt+,')\n    MOUSETRAP.unbind(\"'\")\n    MOUSETRAP.unbind(\"alt+'\")\n    MOUSETRAP.unbind('q')\n    MOUSETRAP.unbind('alt+q')\n    MOUSETRAP.unbind('f')\n    MOUSETRAP.unbind('alt+f')\n    MOUSETRAP.unbind('u')\n    MOUSETRAP.unbind('alt+u')\n    MOUSETRAP.unbind('s')\n    MOUSETRAP.unbind('alt+s')\n    MOUSETRAP.unbind('o')\n    MOUSETRAP.unbind('alt+o')\n    MOUSETRAP.unbind('p')\n    MOUSETRAP.unbind('alt+p')\n  })\n}\n\nexport default addKeyboardShortcuts\n"
  },
  {
    "path": "src/UI/createRenderingViewContainers.js",
    "content": "/* Create the containers for the rendering views. */\nfunction createRenderingViewContainers(context) {\n  // Todo: migrate from ViewerStore\n  // context.container = document.createElement('div'),\n  if (!!!context.rootContainer) {\n    throw new Error('rootContainer must be supplied in the context')\n  }\n\n  // Todo: migrate container creation from ViewerStore\n  context.renderingViewContainers.set('volume', context.container)\n}\n\nexport default createRenderingViewContainers\n"
  },
  {
    "path": "src/UI/createUIMachine.js",
    "content": "import { Machine, forwardTo } from 'xstate'\n\nimport createMainUIMachine from './Main/createMainUIMachine'\nimport createLayersUIMachine from './Layers/createLayersUIMachine'\nimport createImagesUIMachine from './Images/createImagesUIMachine'\nimport createWidgetsUIMachine from './Widgets/createWidgetsUIMachine'\n\nfunction createUIMachine(options, context) {\n  const { main, layers, images, widgets } = options\n  const mainMachine = createMainUIMachine(main, context)\n  const layersMachine = createLayersUIMachine(layers, context)\n  const imagesMachine = createImagesUIMachine(images, context)\n  const widgetsMachine = createWidgetsUIMachine(widgets, context)\n  return Machine(\n    {\n      id: 'ui',\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          always: {\n            target: 'active',\n            actions: ['createInterface'],\n          },\n        },\n        active: {\n          type: 'parallel',\n          invoke: [\n            {\n              id: 'main',\n              src: mainMachine,\n            },\n            {\n              id: 'layers',\n              src: layersMachine,\n            },\n            {\n              id: 'images',\n              src: imagesMachine,\n            },\n            {\n              id: 'widgets',\n              src: widgetsMachine,\n            },\n          ],\n          on: {\n            TOGGLE_BACKGROUND_COLOR: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_DARK_MODE: {\n              actions: 'toggleDarkMode',\n            },\n            TOGGLE_FULLSCREEN: {\n              actions: forwardTo('main'),\n            },\n            DISABLE_FULLSCREEN: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_ROTATE: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_ANNOTATIONS: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_AXES: {\n              actions: forwardTo('main'),\n            },\n            TOGGLE_CROPPING_PLANES: {\n              actions: forwardTo('main'),\n            },\n            CROPPING_PLANES_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            VIEW_MODE_CHANGED: {\n              actions: [forwardTo('main'), forwardTo('widgets')],\n            },\n            SLICING_PLANES_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            X_SLICE_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            Y_SLICE_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            Z_SLICE_CHANGED: {\n              actions: forwardTo('main'),\n            },\n            SELECT_LAYER: {\n              actions: forwardTo('layers'),\n            },\n            TOGGLE_LAYER_VISIBILITY: {\n              actions: forwardTo('layers'),\n            },\n            ADD_IMAGE: {\n              actions: forwardTo('layers'),\n            },\n            IMAGE_ASSIGNED: {\n              actions: [forwardTo('images'), forwardTo('widgets')],\n            },\n            RENDERED_IMAGE_ASSIGNED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_RENDERING_ACTIVE: {\n              actions: forwardTo('images'),\n            },\n            ADD_LABEL_IMAGE: {\n              actions: forwardTo('layers'),\n            },\n            LABEL_IMAGE_ASSIGNED: {\n              actions: [forwardTo('images')],\n            },\n            TOGGLE_IMAGE_INTERPOLATION: {\n              actions: forwardTo('images'),\n            },\n            SELECT_IMAGE_COMPONENT: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COMPONENT_VISIBILITY_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_PIECEWISE_FUNCTION_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_PIECEWISE_FUNCTION_GAUSSIANS_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_RANGE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_RANGE_BOUNDS_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_MAP_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_MAP_DEPENDENCIES_UPDATE: {\n              actions: forwardTo('images'),\n            },\n            TOGGLE_IMAGE_SHADOW: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_GRADIENT_OPACITY_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_GRADIENT_OPACITY_SCALE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_VOLUME_SAMPLE_DISTANCE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_BLEND_MODE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_HISTOGRAM_UPDATED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_LOOKUP_TABLE_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_BLEND_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_WEIGHTS_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_LABEL_NAMES_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            LABEL_IMAGE_SELECTED_LABEL_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            TOGGLE_DISTANCE_WIDGET: {\n              actions: forwardTo('widgets'),\n            },\n            DISTANCE_WIDGET_VALUE_CHANGED: {\n              actions: forwardTo('widgets'),\n            },\n            CINEMATIC_CHANGED: {\n              actions: forwardTo('images'),\n            },\n            WINDOW_LEVEL_TOGGLED: {\n              actions: forwardTo('images'),\n            },\n            IMAGE_COLOR_RANGE_RESET: {\n              actions: forwardTo('images'),\n            },\n            START_DATA_UPDATE: { actions: forwardTo('layers') },\n            FINISH_DATA_UPDATE: { actions: forwardTo('layers') },\n            POST_RENDER: { actions: forwardTo('layers') },\n            COMPARE_UPDATED: {\n              actions: forwardTo('layers'),\n            },\n            COMPONENT_VISIBILITIES_UPDATED: {\n              actions: forwardTo('images'),\n            },\n          },\n          states: {\n            // Optional feature of the user interface\n            uiCollapsed: {\n              initial: context.uiCollapsed ? 'enabled' : 'disabled',\n              states: {\n                enabled: {\n                  entry: 'toggleUICollapsed',\n                  on: {\n                    TOGGLE_UI_COLLAPSED: {\n                      target: 'disabled',\n                    },\n                  },\n                },\n                disabled: {\n                  entry: 'toggleUICollapsed',\n                  on: {\n                    TOGGLE_UI_COLLAPSED: {\n                      target: 'enabled',\n                    },\n                  },\n                },\n              },\n            },\n          },\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createUIMachine\n"
  },
  {
    "path": "src/UI/reference-ui/.babelrc",
    "content": "{\n  \"presets\": [\n    [\n      \"@babel/preset-env\",\n      {\n        \"targets\": {\n          \"browsers\": [\"last 2 versions\"]\n        },\n        \"useBuiltIns\": false\n      }\n    ]\n  ],\n  \"plugins\": [\n    \"@babel/plugin-transform-runtime\",\n    [\"@babel/plugin-proposal-decorators\", { \"legacy\": true }],\n    [\"@babel/plugin-proposal-class-properties\", { \"loose\": false }]\n  ]\n}\n"
  },
  {
    "path": "src/UI/reference-ui/package.json",
    "content": "{\n  \"name\": \"itk-viewer-reference-ui\",\n  \"version\": \"11.11.2\",\n  \"description\": \"Reference UI for itk-viewer\",\n  \"module\": \"dist/referenceUIMachineOptions.js\",\n  \"scripts\": {\n    \"build\": \"rollup -c rollup.config.js\",\n    \"dev\": \"rollup -w -c rollup.config.js\",\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Kitware/itk-vtk-viewer.git\"\n  },\n  \"keywords\": [\n    \"vanilla\",\n    \"ui\",\n    \"itk-viewer\"\n  ],\n  \"author\": \"Matt McCormick\",\n  \"license\": \"Apache-2.0\",\n  \"bugs\": {\n    \"url\": \"https://github.com/Kitware/itk-vtk-viewer/issues\"\n  },\n  \"homepage\": \"https://github.com/Kitware/itk-vtk-viewer#readme\",\n  \"devDependencies\": {\n    \"@babel/plugin-proposal-class-properties\": \"^7.18.6\",\n    \"@babel/plugin-proposal-decorators\": \"^7.21.0\",\n    \"@babel/plugin-transform-runtime\": \"^7.17.0\",\n    \"@rollup/plugin-commonjs\": \"^21.0.2\",\n    \"@rollup/plugin-node-resolve\": \"^13.0.0\",\n    \"@rollup/plugin-typescript\": \"^9.0.2\",\n    \"autoprefixer\": \"^10.4.4\",\n    \"postcss\": \"^8.4.12\",\n    \"rollup\": \"^2.70.1\",\n    \"rollup-plugin-ignore\": \"^1.0.10\",\n    \"rollup-plugin-postcss\": \"^4.0.2\",\n    \"rollup-plugin-svgo\": \"^2.0.0\",\n    \"rollup-plugin-terser\": \"^7.0.2\",\n    \"typescript\": \"^5.3.3\"\n  },\n  \"dependencies\": {\n    \"@babel/runtime\": \"^7.17.6\",\n    \"@itk-viewer/icons\": \"^11.14.1\",\n    \"@lit-labs/context\": \"^0.2.0\",\n    \"@material/web\": \"1.0.1\",\n    \"itk-viewer-color-maps\": \"^1.2.0\",\n    \"itk-viewer-transfer-function-editor\": \"^1.6.0\",\n    \"lit\": \"^2.4.0\",\n    \"xstate-lit\": \"^1.3.1\"\n  }\n}\n"
  },
  {
    "path": "src/UI/reference-ui/rollup.config.js",
    "content": "// Configuration for bundling the ReferenceUI and derivatives\nimport autoprefixer from 'autoprefixer'\nimport postcss from 'rollup-plugin-postcss'\nimport svgo from 'rollup-plugin-svgo'\nimport { nodeResolve } from '@rollup/plugin-node-resolve'\nimport commonjs from '@rollup/plugin-commonjs'\nimport { terser } from 'rollup-plugin-terser'\nimport { babel } from '@rollup/plugin-babel'\nimport ignore from 'rollup-plugin-ignore'\nimport typescript from '@rollup/plugin-typescript'\n\nexport default {\n  input: 'src/referenceUIMachineOptions.js',\n  output: [\n    { file: 'dist/referenceUIMachineOptions.js', format: 'es' },\n    {\n      file: 'dist/referenceUIMachineOptions.min.js',\n      format: 'es',\n      plugins: [terser()],\n    },\n  ],\n  plugins: [\n    // ignore crypto module\n    ignore(['crypto']),\n    commonjs({\n      transformMixedEsModules: true,\n    }),\n    typescript(),\n    babel({\n      include: ['src/**'],\n      extensions: ['.js'],\n      exclude: 'node_modules/**',\n      babelHelpers: 'runtime',\n    }),\n    svgo({ raw: true }),\n    postcss({\n      modules: true,\n      plugins: [autoprefixer],\n    }),\n    nodeResolve({\n      preferBuiltins: false,\n      browser: true,\n    }),\n  ],\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyBlendMode.js",
    "content": "function applyBlendMode(context, event) {\n  const name = event.data.name\n  const blendMode = event.data.blendMode\n\n  const blendModeLower = blendMode.toLowerCase()\n  switch (blendModeLower) {\n    case 'composite':\n      context.images.blendModeSelector.value = 0\n      if (!context.use2D) {\n        context.images.volumeRow1.style.display = 'flex'\n      }\n      break\n    case 'maximum':\n      context.images.blendModeSelector.value = 1\n      context.images.volumeRow1.style.display = 'none'\n      break\n    case 'minimum':\n      context.images.blendModeSelector.value = 2\n      context.images.volumeRow1.style.display = 'none'\n      break\n    case 'average':\n      context.images.blendModeSelector.value = 3\n      context.images.volumeRow1.style.display = 'none'\n      break\n    default:\n      throw new Error(`Invalid blend mode: ${blendMode}`)\n  }\n}\n\nexport default applyBlendMode\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyColorMap.js",
    "content": "function applyColorMap(context, { data: { component, name } }) {\n  if (context.images.selectedName !== name) return\n\n  const actorContext = context.images.actorContext.get(name)\n  if (component === actorContext.selectedComponent) {\n    const colorMap = actorContext.colorMaps.get(component)\n    context.images.iconSelector.setSelectedValue(colorMap)\n    const colorTransferFunction = context.images.colorTransferFunctions?.get(\n      component\n    )\n    if (colorTransferFunction) {\n      context.images.transferFunctionWidget.setColorTransferFunction(\n        colorTransferFunction\n      )\n    }\n    if (\n      actorContext.fusedImage &&\n      // When comparing images, getScalars is null first time\n      actorContext.fusedImage.getPointData().getScalars()\n    ) {\n      const range = actorContext.fusedImage\n        .getPointData()\n        .getScalars()\n        .getRange(component)\n\n      context.images.transferFunctionWidget.setRange(range)\n    }\n  }\n}\n\nexport default applyColorMap\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyColorRange.js",
    "content": "function applyColorRange(context, event) {\n  const name = event.data.name\n  const component = event.data.component\n  const actorContext = context.images.actorContext.get(name)\n\n  if (\n    name !== context.images.selectedName ||\n    component !== actorContext.selectedComponent\n  ) {\n    return\n  }\n\n  const colorRange = event.data.range\n\n  const minimumInput = context.images.colorRangeInputRow.children[1].children[0]\n  const maximumInput = context.images.colorRangeInputRow.children[3].children[0]\n\n  if (actorContext.windowLevelEnabled) {\n    minimumInput.value = colorRange[1] - colorRange[0]\n    maximumInput.value = (colorRange[1] + colorRange[0]) / 2\n  } else {\n    minimumInput.value = colorRange[0]\n    maximumInput.value = colorRange[1]\n  }\n\n  let fullRange = colorRange\n  if (actorContext.colorRangeBounds.has(component)) {\n    fullRange = actorContext.colorRangeBounds.get(component)\n  }\n  if (event.data.fullRange) {\n    // use more up to date colorRangeBounds\n    fullRange = event.data.fullRange\n  }\n  const diff = fullRange[1] - fullRange[0]\n\n  const colorRangeNormalized = [\n    (colorRange[0] - fullRange[0]) / diff,\n    (colorRange[1] - fullRange[0]) / diff,\n  ]\n\n  context.images.transferFunctionWidget.setColorRange(colorRangeNormalized)\n}\n\nexport default applyColorRange\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyColorRangeBounds.js",
    "content": "import applyColorRange from './applyColorRange'\n\nfunction applyColorRangeBounds(context, event) {\n  const { name, component } = event.data\n  const actorContext = context.images.actorContext.get(name)\n\n  if (\n    name !== context.images.selectedName ||\n    component !== actorContext.selectedComponent\n  ) {\n    return\n  }\n\n  const range = event.data.range\n\n  const minimumInput = context.images.colorRangeInputRow.children[1].children[0]\n  const maximumInput = context.images.colorRangeInputRow.children[3].children[0]\n\n  const image = actorContext.image\n  if (\n    (image && image.imageType.componentType === 'float') ||\n    image.imageType.componentType === 'double'\n  ) {\n    const step = (range[1] - range[0]) / 1000.0\n    minimumInput.step = step\n    maximumInput.step = step\n  }\n\n  if (actorContext.colorRanges.has(component)) {\n    applyColorRange(context, {\n      data: {\n        name,\n        component,\n        range: actorContext.colorRanges.get(component),\n        fullRange: range,\n      },\n    })\n  }\n}\n\nexport default applyColorRangeBounds\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyComponentVisibility.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nfunction applyComponentVisibility(context, event) {\n  const name = event.data.name\n  if (name !== context.images.selectedName) {\n    return\n  }\n  const actorContext = context.images.actorContext.get(name)\n  const componentSelector = context.images.componentSelector\n\n  actorContext.componentVisibilities.forEach((visibility, compIdx) => {\n    const element = componentSelector.querySelector(\n      `input[data-component-index=\"${compIdx}\"][type=\"checkbox\"]`\n    )\n    element.checked = visibility\n  })\n}\n\nexport default applyComponentVisibility\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyGradientOpacity.js",
    "content": "function applyGradientOpacity(context, event) {\n  const name = event.data.name\n  const gradientOpacity = event.data.gradientOpacity\n\n  context.images.gradientOpacitySlider.value = gradientOpacity\n}\n\nexport default applyGradientOpacity\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyGradientOpacityScale.js",
    "content": "function applyGradientOpacityScale(context, event) {\n  const name = event.data.name\n  const gradientOpacityScale = event.data.gradientOpacityScale\n\n  context.images.gradientOpacityScaleSlider.value = gradientOpacityScale\n}\n\nexport default applyGradientOpacityScale\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyHistogram.js",
    "content": "function applyHistogram(context, event) {\n  const name = event.data.name\n  const component = event.data.component\n  const actorContext = context.images.actorContext.get(name)\n\n  if (\n    name !== context.images.selectedName ||\n    component !== actorContext.selectedComponent\n  ) {\n    return\n  }\n\n  const histogram = event.data.histogram ?? []\n  context.images.transferFunctionWidget.setHistogram(histogram)\n}\n\nexport default applyHistogram\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyImagesContrastSensitiveStyle.js",
    "content": "import applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nfunction applyImagesContrastSensitiveStyle(context) {\n  if (context.images.distanceButtonLabel) {\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      context.images.distanceButtonLabel\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'distanceLabel',\n      context.images.distanceLabel\n    )\n  }\n  if (context.images.shadowButtonLabel) {\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      context.images.shadowButtonLabel\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      context.images.sliderEntryDiv\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      context.images.volumeSampleDistanceDiv\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      context.images.blendModeDiv\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      context.images.labelImageBlendDiv\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      context.images.scaleSelectorIconDiv\n    )\n  }\n}\n\nexport default applyImagesContrastSensitiveStyle\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyLabelImageBlend.js",
    "content": "function applyLabelImageBlend(context, event) {\n  const name = event.data.name\n  const actorContext = context.images.actorContext.get(name)\n  const labelImageBlend = event.data.labelImageBlend\n\n  const slider = context.images.labelImageBlendSlider\n\n  slider.value = labelImageBlend\n\n  const haveImage = !!actorContext.image\n  if (haveImage) {\n    slider.style.display = 'flex'\n  } else {\n    slider.style.display = 'none'\n  }\n}\n\nexport default applyLabelImageBlend\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyLabelImageWeights.js",
    "content": "function applyLabelImageWeights(context, event) {}\n\nexport default applyLabelImageWeights\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyLabelNames.js",
    "content": "function applyLabelNames(context, event) {\n  const name = event.data.name\n  const actorContext = context.images.actorContext.get(name)\n  const labelNames = event.data.labelNames\n\n  const optionsList = []\n  labelNames.forEach((name, label) =>\n    optionsList.push(\n      `<option ${\n        label === actorContext.selectedLabel ? 'selected' : ''\n      } value=\"${label}\">${name}</option>`\n    )\n  )\n\n  optionsList.unshift('<option value=\"all\">All</option>')\n  context.images.labelSelector.innerHTML = optionsList.join('')\n}\n\nexport default applyLabelNames\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyLookupTable.js",
    "content": "function applyLookupTable(context, event) {\n  const name = event.data.name\n  const lut = event.data.lookupTable\n\n  if (name !== context.images.selectedName) {\n    return\n  }\n\n  if (lut !== context.images.labelImageIconSelector.getSelectedValue()) {\n    context.images.labelImageIconSelector.setSelectedValue(lut)\n  }\n}\n\nexport default applyLookupTable\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyPiecewiseFunctionGaussians.js",
    "content": "function applyPiecewiseFunctionGaussians(context, event) {\n  const images = context.images\n  const name = event.data.name\n  const actorContext = context.images.actorContext.get(name)\n  const component = event.data.component\n  const gaussians = event.data.gaussians\n\n  const transferFunctionWidget = context.images.transferFunctionWidget\n  transferFunctionWidget.setGaussians(gaussians)\n}\n\nexport default applyPiecewiseFunctionGaussians\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applySelectedLabel.js",
    "content": "function applySelectedLabel(context, event) {\n  const name = event.data.name\n  const actorContext = context.images.actorContext.get(name)\n\n  const selectedLabel = event.data.selectedLabel\n\n  if (selectedLabel === 'all') {\n    context.images.labelSelector.selectedIndex = 0 // 'All' is first\n  } else {\n    context.images.labelImageWeightSlider.value = actorContext.labelImageWeights.get(\n      selectedLabel\n    )\n    context.images.labelSelector.selectedIndex = parseInt(selectedLabel) + 1 // 'All' is first\n  }\n}\n\nexport default applySelectedLabel\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyVolumeSampleDistance.js",
    "content": "function applyVolumeSampleDistance(context, event) {\n  const name = event.data.name\n  const volumeSampleDistance = event.data.volumeSampleDistance\n\n  context.images.volumeSampleDistanceSlider.value = volumeSampleDistance\n}\n\nexport default applyVolumeSampleDistance\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/applyWindowingReset.js",
    "content": "function applyWindowLevelReset(context, { data }) {\n  const actorContext = context.images.actorContext.get(data.name)\n  const component = actorContext.selectedComponent\n  const bounds = actorContext.colorRangeBounds.get(component)\n\n  const wMax = bounds[1] - bounds[0]\n  const lMin = bounds[0]\n  const level = wMax / 2 + lMin\n  const width = wMax\n\n  const newRange = () => {\n    return [level - width / 2, level + width / 2]\n  }\n\n  context.service.send({\n    type: 'IMAGE_COLOR_RANGE_CHANGED',\n    data: {\n      name: data.name,\n      component,\n      range: newRange(),\n    },\n  })\n}\n\nexport default applyWindowLevelReset\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/cinematic.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport { volumeScatteringIconDataUri } from '@itk-viewer/icons'\n\nconst sliderMap = new Map()\n\nfunction makeSlider(context, label, parameterName, { min, max, step, start }) {\n  const container = document.createElement('div')\n  container.setAttribute('class', style.sliderEntry)\n  container.innerHTML = `\n    <div itk-vtk-tooltip itk-vtk-tooltip-top-screenshot itk-vtk-tooltip-content=\"${label}\" class=\"${style.sliderIcon}\">\n      <img src=\"${volumeScatteringIconDataUri}\" alt=\"${label}\" />\n    </div>\n    <input type=\"range\" min=\"${min}\" max=\"${max}\" step=\"${step}\" value=\"${start}\" \n      class=\"${style.slider}\" />`\n  const slider = container.children[1]\n  slider.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'SET_CINEMATIC_PARAMETERS',\n      data: {\n        name: context.images.selectedName,\n        params: { [parameterName]: Number(slider.value) },\n      },\n    })\n  })\n\n  sliderMap.set(parameterName, slider)\n\n  return container\n}\n\nexport function createCinematicParameters(context, rowParent) {\n  // hidable sliders\n  const row = document.createElement('div')\n\n  const rootContainer = document.createElement('div')\n  rootContainer.setAttribute('class', style.sliderColumn)\n  row.appendChild(rootContainer)\n  rowParent.appendChild(row)\n\n  context.images.volumeUiElements.push(row)\n\n  rootContainer.style.flexDirection = 'column'\n\n  rootContainer.appendChild(\n    makeSlider(context, 'Volume Scattering', 'scatteringBlend', {\n      min: 0,\n      max: 1,\n      step: 1 / 100,\n      start: 0,\n    })\n  )\n}\n\nexport function applyCinematicChanged(context, { actorContext }) {\n  const { cinematicParameters } = actorContext\n  sliderMap.get(\n    'scatteringBlend'\n  ).disabled = !cinematicParameters.isCinematicPossible\n  ;['scatteringBlend'].forEach(param => {\n    sliderMap.get(param).value = cinematicParameters[param]\n  })\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createBlendModeSelector.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { blendModeIconDataUri } from '@itk-viewer/icons'\n\nfunction createBlendModeSelector(context, uiContainer) {\n  const blendModeEntry = document.createElement('div')\n  blendModeEntry.innerHTML = `\n    <div itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Blend mode\"\n      class=\"${style.blendModeButton}\">\n      <img src=\"${blendModeIconDataUri}\" alt=\"blend mode\" />\n    </div>\n    `\n  const blendModeDiv = blendModeEntry.children[0]\n  context.images.blendModeDiv = blendModeDiv\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    blendModeDiv\n  )\n  uiContainer.appendChild(blendModeEntry)\n\n  const blendModeSelector = document.createElement('select')\n  blendModeSelector.setAttribute('class', style.selector)\n  blendModeSelector.id = `${context.id}-colorMapSelector`\n  blendModeSelector.innerHTML = `<option selected value=\"0\">Composite</option>\n    <option value=\"1\">Maximum</option>\n    <option value=\"2\">Minimum</option>\n    <option value=\"3\">Average</option>`\n  blendModeEntry.appendChild(blendModeSelector)\n  context.images.blendModeSelector = blendModeSelector\n\n  blendModeSelector.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    let mode = 'blendmode'\n    switch (parseInt(event.target.value)) {\n      case 0:\n        mode = 'Composite'\n        break\n      case 1:\n        mode = 'Maximum'\n        break\n      case 2:\n        mode = 'Minimum'\n        break\n      case 3:\n        mode = 'Average'\n        break\n    }\n    context.service.send({\n      type: 'IMAGE_BLEND_MODE_CHANGED',\n      data: {\n        name: context.images.selectedName,\n        blendMode: mode,\n      },\n    })\n  })\n\n  uiContainer.appendChild(blendModeSelector)\n}\n\nexport default createBlendModeSelector\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createColorRangeInput.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport createInterpolationButton from './createInterpolationButton'\nimport createColorMapIconSelector from '../createColorMapIconSelector'\nimport createWindowLevelReset from './createWindowLevelReset'\n\nfunction createColorRangeInput(context, imageUIGroup) {\n  const viewerDOMId = context.id\n\n  const colorRangeInputRow = document.createElement('div')\n  colorRangeInputRow.setAttribute('class', style.uiRow)\n  // This row needs background different from normal uiRows, to aid\n  // in the illusion that it's the content portion of a tabbed pane\n  colorRangeInputRow.setAttribute(\n    'style',\n    'background: rgba(127, 127, 127, 0.5);'\n  )\n  context.images.colorRangeInputRow = colorRangeInputRow\n  createInterpolationButton(context, colorRangeInputRow)\n\n  const minimumInput = document.createElement('input')\n  minimumInput.type = 'number'\n  minimumInput.setAttribute('class', style.numberInput)\n  const minimumDiv = document.createElement('div')\n  minimumDiv.setAttribute('itk-vtk-tooltip', '')\n  minimumDiv.setAttribute('itk-vtk-tooltip-top-input', '')\n  minimumDiv.setAttribute('itk-vtk-tooltip-content', 'Color range min')\n  minimumDiv.appendChild(minimumInput)\n  const maximumInput = document.createElement('input')\n  maximumInput.type = 'number'\n  maximumInput.setAttribute('class', style.numberInput)\n  const maximumDiv = document.createElement('div')\n  maximumDiv.setAttribute('itk-vtk-tooltip', '')\n  maximumDiv.setAttribute('itk-vtk-tooltip-top-input', '')\n  maximumDiv.setAttribute('itk-vtk-tooltip-content', 'Color range max')\n  maximumDiv.appendChild(maximumInput)\n\n  minimumInput.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const currentRange = actorContext.colorRanges.get(\n      actorContext.selectedComponent\n    )\n    let newRange = []\n    if (actorContext.windowLevelEnabled) {\n      const level = (currentRange[1] + currentRange[0]) / 2\n      const width = Number(event.target.value)\n      newRange = [level - width / 2, level + width / 2]\n    } else {\n      newRange = [Number(event.target.value), currentRange[1]]\n    }\n    context.service.send({\n      type: 'IMAGE_COLOR_RANGE_CHANGED',\n      data: {\n        name,\n        component: actorContext.selectedComponent,\n        range: newRange,\n      },\n    })\n  })\n  maximumInput.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const currentRange = actorContext.colorRanges.get(\n      actorContext.selectedComponent\n    )\n    let newRange = []\n    if (actorContext.windowLevelEnabled) {\n      const width = currentRange[1] - currentRange[0]\n      const level = Number(event.target.value)\n      newRange = [level - width / 2, level + width / 2]\n    } else {\n      newRange = [currentRange[0], Number(event.target.value)]\n    }\n    context.service.send({\n      type: 'IMAGE_COLOR_RANGE_CHANGED',\n      data: {\n        name,\n        component: actorContext.selectedComponent,\n        range: newRange,\n      },\n    })\n  })\n\n  const colorMapSelector = document.createElement('div')\n  colorMapSelector.id = `${viewerDOMId}-imageColorMapSelector`\n\n  colorRangeInputRow.appendChild(minimumDiv)\n  colorRangeInputRow.appendChild(colorMapSelector)\n  colorRangeInputRow.appendChild(maximumDiv)\n\n  const iconSelector = createColorMapIconSelector(colorMapSelector)\n  context.images.iconSelector = iconSelector\n\n  colorMapSelector.addEventListener('changed', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const componentIndex = actorContext.selectedComponent\n    const colorMap = iconSelector.getSelectedValue()\n    const currentColorMap = actorContext.colorMaps.get(componentIndex)\n    if (currentColorMap !== colorMap) {\n      context.service.send({\n        type: 'IMAGE_COLOR_MAP_CHANGED',\n        data: { name, component: componentIndex, colorMap },\n      })\n    }\n  })\n  context.images.colorMapSelector = colorMapSelector\n\n  createWindowLevelReset(context, colorRangeInputRow)\n\n  imageUIGroup.appendChild(colorRangeInputRow)\n}\n\nexport default createColorRangeInput\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createComponentSelector.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nfunction createComponentSelector(context, imageUIGroup) {\n  const viewerDOMId = context.id\n\n  const componentSelector = document.createElement('div')\n  componentSelector.setAttribute('class', style.selector)\n  componentSelector.id = `${viewerDOMId}-componentSelector`\n  context.images.componentSelector = componentSelector\n\n  const componentRow = document.createElement('div')\n  componentRow.setAttribute('class', style.uiRow)\n  // This row needs custom bottom padding, to aid in the illusion\n  // that it's the tabbed portion of a tabbed pane\n  componentRow.setAttribute('style', 'padding-bottom: 0px;')\n  componentRow.className += ` ${viewerDOMId}-volumeComponents`\n  context.images.componentRow = componentRow\n\n  componentSelector.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedIndex = Number(event.target.dataset.componentIndex)\n    if (event.target.type === 'radio') {\n      context.service.send({\n        type: 'SELECT_IMAGE_COMPONENT',\n        data: { name: context.images.selectedName, component: selectedIndex },\n      })\n    } else if (event.target.type === 'checkbox') {\n      const visibility = event.target.checked\n      context.service.send({\n        type: 'IMAGE_COMPONENT_VISIBILITY_CHANGED',\n        data: {\n          name: context.images.selectedName,\n          component: selectedIndex,\n          visibility,\n        },\n      })\n    }\n  })\n\n  componentRow.appendChild(componentSelector)\n  imageUIGroup.appendChild(componentRow)\n}\n\nexport default createComponentSelector\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createGradientOpacitySlider.js",
    "content": "import macro from '@kitware/vtk.js/macro'\n\nimport style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { gradientIconDataUri } from '@itk-viewer/icons'\n\nfunction createGradientOpacitySlider(context, uiContainer) {\n  const sliderEntry = document.createElement('div')\n  sliderEntry.setAttribute('class', style.sliderEntry)\n  sliderEntry.innerHTML = `\n    <div itk-vtk-tooltip itk-vtk-tooltip-top-fullscreen itk-vtk-tooltip-content=\"Gradient opacity scale\" class=\"${style.gradientOpacitySlider}\">\n      <img src=\"${gradientIconDataUri}\" alt=\"gradient opacity\"/>\n    </div>\n    <div class=\"${style.gradientOpacityScale}\" style=\"display: none;\">\n      <input type=\"range\" min=\"0\" max=\"0.99\" value=\"0.5\" step=\"0.01\" id=\"${context.id}-gradientOpacityScaleSlider\" />\n    </div>\n\n    <input type=\"range\" min=\"0\" max=\"1\" value=\"0.2\" step=\"0.01\" orient=\"vertical\"\n      id=\"${context.id}-gradientOpacitySlider\"\n      class=\"${style.slider}\" />`\n  const sliderEntryDiv = sliderEntry.children[0]\n  const gradientOpacityScaleDiv = sliderEntry.children[1]\n  const gradientOpacityScaleSlider = gradientOpacityScaleDiv.children[0]\n  const gradientOpacitySlider = sliderEntry.children[2]\n  context.images.sliderEntryDiv = sliderEntryDiv\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    sliderEntryDiv\n  )\n  context.images.gradientOpacitySlider = gradientOpacitySlider\n  context.images.gradientOpacityScaleSlider = gradientOpacityScaleSlider\n\n  sliderEntryDiv.addEventListener('click', event => {\n    if (gradientOpacityScaleDiv.style.display === 'none') {\n      gradientOpacityScaleDiv.style.display = 'block'\n    } else {\n      gradientOpacityScaleDiv.style.display = 'none'\n    }\n  })\n\n  gradientOpacitySlider.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'IMAGE_GRADIENT_OPACITY_CHANGED',\n      data: {\n        name: context.images.selectedName,\n        gradientOpacity: Number(gradientOpacitySlider.value),\n      },\n    })\n  })\n\n  gradientOpacityScaleSlider.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'IMAGE_GRADIENT_OPACITY_SCALE_CHANGED',\n      data: {\n        name: context.images.selectedName,\n        gradientOpacityScale: Number(gradientOpacityScaleSlider.value),\n      },\n    })\n  })\n\n  uiContainer.appendChild(sliderEntry)\n}\n\nexport default createGradientOpacitySlider\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createImagesInterface.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport applyGroupVisibility from '../applyGroupVisibility'\n\nimport createComponentSelector from './createComponentSelector'\nimport createColorRangeInput from './createColorRangeInput'\nimport createTransferFunctionWidget from './createTransferFunctionWidget'\nimport createVolumeRenderingInputs from './createVolumeRenderingInputs'\n\nimport createLabelImageColorWidget from './createLabelImageColorWidget'\nimport createLabelImageWeightWidget from './createLabelImageWeightWidget'\n\nfunction createImagesInterface(context) {\n  const imagesUIGroup = document.createElement('div')\n  imagesUIGroup.setAttribute('class', style.uiGroup)\n  context.images.imagesUIGroup = imagesUIGroup\n  context.uiGroups.set('images', imagesUIGroup)\n\n  const componentAndScale = document.createElement('div')\n  imagesUIGroup.appendChild(componentAndScale)\n  componentAndScale.setAttribute('style', 'display: flex;')\n  context.images.componentAndScale = componentAndScale\n\n  createComponentSelector(context, componentAndScale)\n  createColorRangeInput(context, imagesUIGroup)\n  createTransferFunctionWidget(context, imagesUIGroup)\n  createVolumeRenderingInputs(context, imagesUIGroup)\n\n  context.uiContainer.appendChild(imagesUIGroup)\n\n  createLabelImageColorWidget(context)\n  createLabelImageWeightWidget(context)\n\n  applyGroupVisibility(\n    context,\n    ['images', 'labelImages', 'labelImageWeights'],\n    false\n  )\n}\n\nexport default createImagesInterface\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createInterpolationButton.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport { interpolationIconDataUri } from '@itk-viewer/icons'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\nimport toggleInterpolation from './toggleInterpolation'\n\nfunction createInterpolationButton(context, uiRow) {\n  const interpolationButton = document.createElement('div')\n  // Todo: send event to disable interpolation when label maps added\n  //if (context.images.labelMaps.length) {\n  //context.images.interpolationEnabled = false\n  //}\n  // and the \"input\" element needs to get the 'disabled' attribute added\n  interpolationButton.innerHTML = `<input id=\"${context.id}-toggleInterpolationButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-screenshot itk-vtk-tooltip-content=\"Interpolation\" class=\"${style.interpolationButton} ${style.toggleButton}\" for=\"${context.id}-toggleInterpolationButton\"><img src=\"${interpolationIconDataUri}\" alt=\"interpolation\" /></label>`\n  const interpolationButtonInput = interpolationButton.children[0]\n  const interpolationButtonLabel = interpolationButton.children[1]\n  context.images.interpolationButtonLabel = interpolationButtonLabel\n  context.images.interpolationButtonInput = interpolationButtonInput\n\n  toggleInterpolation(context, { data: context.images.selectedName })\n\n  interpolationButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'TOGGLE_IMAGE_INTERPOLATION',\n      data: context.images.selectedName,\n    })\n  })\n\n  uiRow.appendChild(interpolationButton)\n}\n\nexport default createInterpolationButton\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createLabelImageColorWidget.js",
    "content": "import macro from '@kitware/vtk.js/macro'\nimport createCategoricalColorIconSelector from '../createCategoricalColorIconSelector'\n\nimport style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { opacityIconDataUri } from '@itk-viewer/icons'\n\nfunction createLabelImageColorWidget(context) {\n  const viewerDOMId = context.id\n\n  const labelImageColorUIGroup = document.createElement('div')\n  context.images.labelImageColorUIGroup = labelImageColorUIGroup\n  labelImageColorUIGroup.setAttribute('class', style.uiGroup)\n  context.uiGroups.set('labelImages', labelImageColorUIGroup)\n\n  const labelImageWidgetRow = document.createElement('div')\n  labelImageWidgetRow.setAttribute('class', style.uiRow)\n\n  const categoricalColorSelector = document.createElement('div')\n  categoricalColorSelector.id = `${context.id}-lookupTableSelector`\n\n  const iconSelector = createCategoricalColorIconSelector(\n    categoricalColorSelector\n  )\n  context.images.labelImageIconSelector = iconSelector\n\n  categoricalColorSelector.addEventListener('changed', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const name = context.images.selectedName\n    const lut = iconSelector.getSelectedValue()\n    context.service.send({\n      type: 'LABEL_IMAGE_LOOKUP_TABLE_CHANGED',\n      data: { name, lookupTable: lut },\n    })\n  })\n\n  const sliderEntry = document.createElement('div')\n  sliderEntry.setAttribute('class', style.sliderEntry)\n  sliderEntry.innerHTML = `\n  <div itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Label image blend\" class=\"${style.gradientOpacitySlider}\">\n    <img src=\"${opacityIconDataUri}\" alt=\"opacity\"/>\n  </div>\n  <input type=\"range\" min=\"0\" max=\"1\" value=\"0.5\" step=\"0.01\"\n  id=\"${context.id}-labelImageBlendSlider\"\n  class=\"${style.slider}\" />`\n  const labelImageBlendSlider = sliderEntry.querySelector(\n    `#${context.id}-labelImageBlendSlider`\n  )\n  context.images.labelImageBlendSlider = labelImageBlendSlider\n  const sliderEntryDiv = sliderEntry.children[0]\n  context.images.labelImageBlendDiv = sliderEntryDiv\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    sliderEntryDiv\n  )\n  labelImageBlendSlider.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const name = context.images.selectedName\n    context.service.send({\n      type: 'LABEL_IMAGE_BLEND_CHANGED',\n      data: { name, labelImageBlend: Number(labelImageBlendSlider.value) },\n    })\n  })\n\n  labelImageWidgetRow.appendChild(categoricalColorSelector)\n  labelImageWidgetRow.appendChild(sliderEntry)\n\n  labelImageColorUIGroup.appendChild(labelImageWidgetRow)\n  context.uiContainer.appendChild(labelImageColorUIGroup)\n}\n\nexport default createLabelImageColorWidget\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createLabelImageWeightWidget.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nfunction createLabelMapWeightWidget(context) {\n  const labelImageWeightUIGroup = document.createElement('div')\n  context.images.labelImageWeightUIGroup = labelImageWeightUIGroup\n  labelImageWeightUIGroup.setAttribute('class', style.uiGroup)\n  context.uiGroups.set('labelImageWeights', labelImageWeightUIGroup)\n\n  const labelImageWidgetRow = document.createElement('div')\n  labelImageWidgetRow.setAttribute('class', style.uiRow)\n\n  const uniqueLabelSelectorDiv = document.createElement('div')\n  uniqueLabelSelectorDiv.id = `${context.id}-labelImageUniqueLabelSelector`\n\n  const labelSelector = document.createElement('select')\n  labelSelector.setAttribute('class', style.selector)\n  labelSelector.id = `${context.id}-labelSelector`\n  context.images.labelSelector = labelSelector\n\n  context.images.labelSelector = labelSelector\n  uniqueLabelSelectorDiv.appendChild(labelSelector)\n\n  const sliderEntry = document.createElement('div')\n  sliderEntry.setAttribute('class', style.sliderEntry)\n  // <input type=\"range\" min=\"0\" max=\"1\" value=\"${context.images.labelImageWeights[0]}\" step=\"0.05\" id=\"${context.id}-labelImageWeightSlider\" class=\"${style.slider}\" />`\n  sliderEntry.innerHTML = `\n    <input type=\"range\" min=\"0\" max=\"1\" value=\"1.0\" step=\"0.05\" id=\"${context.id}-labelImageWeightSlider\" class=\"${style.slider}\" />`\n  const weightElement = sliderEntry.querySelector(\n    `#${context.id}-labelImageWeightSlider`\n  )\n  context.images.labelImageWeightSlider = weightElement\n\n  labelImageWidgetRow.appendChild(uniqueLabelSelectorDiv)\n  labelImageWidgetRow.appendChild(sliderEntry)\n\n  labelImageWeightUIGroup.appendChild(labelImageWidgetRow)\n  context.uiContainer.appendChild(labelImageWeightUIGroup)\n\n  labelSelector.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'LABEL_IMAGE_SELECTED_LABEL_CHANGED',\n      data: {\n        name: context.images.selectedName,\n        selectedLabel: event.target.value,\n      },\n    })\n  })\n\n  weightElement.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    const labelImageWeights = actorContext.labelImageWeights\n\n    if (actorContext.selectedLabel === 'all') {\n      const weight = Number(weightElement.value)\n      for (const label of labelImageWeights.keys()) {\n        labelImageWeights.set(label, weight)\n      }\n      actorContext.labelImageToggleWeight = weight\n    } else {\n      labelImageWeights.set(\n        parseInt(actorContext.selectedLabel),\n        Number(weightElement.value)\n      )\n    }\n    context.service.send({\n      type: 'LABEL_IMAGE_WEIGHTS_CHANGED',\n      data: { name: context.images.selectedName, labelImageWeights },\n    })\n  })\n}\n\nexport default createLabelMapWeightWidget\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createSampleDistanceSlider.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { sampleDistanceIconDataUri } from '@itk-viewer/icons'\n\nfunction createSampleDistanceSlider(context, uiContainer) {\n  const sliderEntry = document.createElement('div')\n  sliderEntry.setAttribute('class', style.sliderEntry)\n  sliderEntry.innerHTML = `\n    <div itk-vtk-tooltip itk-vtk-tooltip-top-screenshot itk-vtk-tooltip-content=\"Volume sample distance\" class=\"${style.sampleDistanceButton}\">\n      <img src=\"${sampleDistanceIconDataUri}\" alt=\"sample distance\" />\n    </div>\n    <input type=\"range\" min=\"0\" max=\"1\" value=\"0.25\" step=\"0.01\"\n      class=\"${style.slider} ${context.id}-spacing\" />`\n  const spacingElement = sliderEntry.querySelector(`.${context.id}-spacing`)\n  const spacingDiv = sliderEntry.children[0]\n  context.images.volumeSampleDistanceDiv = spacingDiv\n  context.images.volumeSampleDistanceSlider = spacingElement\n  applyContrastSensitiveStyleToElement(context, 'invertibleButton', spacingDiv)\n\n  spacingElement.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'IMAGE_VOLUME_SAMPLE_DISTANCE_CHANGED',\n      data: {\n        name: context.images.selectedName,\n        volumeSampleDistance: Number(spacingElement.value),\n      },\n    })\n  })\n\n  uiContainer.appendChild(sliderEntry)\n}\n\nexport default createSampleDistanceSlider\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createShadowToggle.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { shadowIconDataUri } from '@itk-viewer/icons'\n\nfunction createShadowToggle(context, uiContainer) {\n  const shadowButton = document.createElement('div')\n  shadowButton.innerHTML = `<input id=\"${context.id}-toggleShadowButton\" type=\"checkbox\" class=\"${style.toggleInput}\" checked><label itk-vtk-tooltip itk-vtk-tooltip-top-screenshot itk-vtk-tooltip-content=\"Use shadow\" class=\"${style.shadowButton} ${style.toggleButton}\" for=\"${context.id}-toggleShadowButton\"><img src=\"${shadowIconDataUri}\" alt=\"shadow\" /></label>`\n  const shadowButtonInput = shadowButton.children[0]\n  const shadowButtonLabel = shadowButton.children[1]\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    shadowButtonLabel\n  )\n  context.images.shadowButtonLabel = shadowButtonLabel\n  context.images.shadowButtonInput = shadowButtonInput\n\n  shadowButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'TOGGLE_IMAGE_SHADOW',\n      data: context.images.selectedName,\n    })\n  })\n  uiContainer.appendChild(shadowButton)\n}\n\nexport default createShadowToggle\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createTransferFunctionEditor.js",
    "content": "import { throttle } from './throttle'\nimport { TransferFunctionEditor } from 'itk-viewer-transfer-function-editor'\n\nconst PIECEWISE_UPDATE_DELAY = 200\n\nconst updateContextPiecewiseFunction = (context, points) => {\n  if (!context.images.piecewiseFunctions) return // not ready yet\n\n  const name = context.images.selectedName\n  const actorContext = context.images.actorContext.get(name)\n  const component = actorContext.selectedComponent\n  context.service.send({\n    type: 'IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED',\n    data: {\n      name,\n      component,\n      points,\n      keepAutoAdjusting: false,\n    },\n  })\n}\n\nconst updateContextColorRange = (context, points) => {\n  if (!context.images.piecewiseFunctions) return // not ready yet\n\n  const name = context.images.selectedName\n  const actorContext = context.images.actorContext.get(name)\n  const component = actorContext.selectedComponent\n\n  context.service.send({\n    type: 'IMAGE_COLOR_RANGE_POINTS_CHANGED',\n    data: {\n      name,\n      component,\n      points,\n    },\n  })\n}\n\nconst vtkPiecewiseGaussianWidgetFacade = (tfEditor, context) => {\n  const throttledUpdate = throttle(\n    () => updateContextPiecewiseFunction(context, tfEditor.getPoints()),\n    PIECEWISE_UPDATE_DELAY\n  )\n  tfEditor.eventTarget.addEventListener('updated', throttledUpdate)\n\n  const throttledColorRangeUpdate = throttle(\n    () => updateContextColorRange(context, tfEditor.getColorRange()),\n    PIECEWISE_UPDATE_DELAY\n  )\n  tfEditor.eventTarget.addEventListener('colorRange', throttledColorRangeUpdate)\n\n  return {\n    setColorTransferFunction: tf => {\n      tfEditor.setColorTransferFunction(tf)\n    },\n\n    setPoints(points) {\n      // tfEditor.setPoints recreates them and they loose their \"grabbed\" state\n      // so ignore events coming down triggered by user dragging points\n      const currentPoints = tfEditor.getPoints()\n      const arePointsModified =\n        points.length !== currentPoints.length ||\n        points.some(([newX, newY], idx) => {\n          const [oldX, oldY] = currentPoints[idx]\n          return newX !== oldX || newY !== oldY\n        })\n      if (arePointsModified) tfEditor.setPoints(points)\n    },\n\n    getPoints() {\n      return tfEditor.getPoints()\n    },\n\n    setColorRange: newRange => {\n      const displayedRange = tfEditor.getColorRange()\n      // if same, avoid infinite event loop\n      if (displayedRange.some((v, i) => v !== newRange[i])) {\n        tfEditor.setColorRange(newRange)\n      }\n    },\n\n    setRange: range => {\n      tfEditor.setRange(range)\n    },\n\n    setRangeZoom: newRange => {\n      tfEditor.setViewBox(...newRange)\n    },\n\n    setHistogram: h => tfEditor.setHistogram(h),\n    render: () => undefined,\n\n    getGaussians() {\n      console.warn('getGaussians not implemented, use getPoints')\n      return []\n    },\n\n    setGaussians() {\n      console.warn('setGaussians not implemented, use setPoints')\n    },\n  }\n}\n\nexport const createTransferFunctionEditor = (context, mount) => {\n  const editor = new TransferFunctionEditor(mount)\n\n  return vtkPiecewiseGaussianWidgetFacade(editor, context)\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createTransferFunctionWidget.js",
    "content": "import { createTransferFunctionEditor } from './createTransferFunctionEditor'\nimport style from '../ItkVtkViewer.module.css'\n\nconst createTransferFunctionWidget = (context, imagesUIGroup) => {\n  const piecewiseWidgetContainer = document.createElement('div')\n  piecewiseWidgetContainer.setAttribute('style', 'height: 150px; width: 400px')\n  piecewiseWidgetContainer.setAttribute('class', style.piecewiseWidget)\n\n  const transferFunctionWidgetRow = document.createElement('div')\n  transferFunctionWidgetRow.setAttribute('class', style.uiRow)\n  // This row needs background different from normal uiRows, to aid\n  // in the illusion that it's the content portion of a tabbed pane\n  transferFunctionWidgetRow.setAttribute(\n    'style',\n    'background: rgba(127, 127, 127, 0.5);'\n  )\n  imagesUIGroup.appendChild(transferFunctionWidgetRow)\n  transferFunctionWidgetRow.appendChild(piecewiseWidgetContainer)\n\n  const transferFunctionWidget = createTransferFunctionEditor(\n    context,\n    piecewiseWidgetContainer\n  )\n\n  context.images.transferFunctionWidget = transferFunctionWidget\n}\n\nexport default createTransferFunctionWidget\n\nexport const applyPiecewiseFunctionPointsToEditor = (context, event) => {\n  const { transferFunctionWidget, actorContext } = context.images\n  const { points, component, name } = event.data\n  const imageActorContext = actorContext.get(name)\n  if (component === imageActorContext.selectedComponent) {\n    transferFunctionWidget.setPoints(points)\n  }\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createVolumeRenderingInputs.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport createShadowToggle from './createShadowToggle'\nimport createGradientOpacitySlider from './createGradientOpacitySlider'\nimport createSampleDistanceSlider from './createSampleDistanceSlider'\nimport createBlendModeSelector from './createBlendModeSelector'\nimport { createCinematicParameters } from './cinematic'\nimport createWindowLevelToggle from './createWindowLevelToggle'\n\nfunction createVolumeRenderingInputs(context, imagesUIGroup) {\n  const volumeRow1 = document.createElement('div')\n  volumeRow1.setAttribute('class', style.uiRow)\n  createShadowToggle(context, volumeRow1)\n  createGradientOpacitySlider(context, volumeRow1)\n  createWindowLevelToggle(context, volumeRow1)\n  imagesUIGroup.appendChild(volumeRow1)\n  context.images.volumeRow1 = volumeRow1\n\n  const volumeRow2 = document.createElement('div')\n  volumeRow2.setAttribute('class', style.uiRow)\n  createSampleDistanceSlider(context, volumeRow2)\n  createBlendModeSelector(context, volumeRow2)\n  imagesUIGroup.appendChild(volumeRow2)\n\n  context.images.volumeUiElements = [volumeRow1, volumeRow2]\n\n  createCinematicParameters(context, imagesUIGroup)\n}\n\nexport default createVolumeRenderingInputs\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createWindowLevelReset.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { resetImageIconDataUri } from '@itk-viewer/icons'\n\nfunction createWindowLevelReset(context, uiContainer) {\n  const windowLevelResetButton = document.createElement('div')\n  windowLevelResetButton.innerHTML = `\n    <div itk-vtk-tooltip itk-vtk-tooltip-left itk-vtk-tooltip-content=\"Reset range to ROI\" class=\"${style.windowLevelButton}\">\n      <img src=\"${resetImageIconDataUri}\" alt=\"gradient opacity\"/>\n    </div>\n  `\n  const windowLevelResetButtonInput = windowLevelResetButton.children[0]\n  const windowLevelResetButtonLabel = windowLevelResetButton.children[1]\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    windowLevelResetButtonLabel\n  )\n  context.images.windowLevelResetButtonLabel = windowLevelResetButtonLabel\n  context.images.windowLevelResetButtonInput = windowLevelResetButtonInput\n\n  windowLevelResetButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'IMAGE_COLOR_RANGE_RESET',\n      data: {\n        name: context.images.selectedName,\n      },\n    })\n  })\n  uiContainer.appendChild(windowLevelResetButton)\n}\n\nexport default createWindowLevelReset\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/createWindowLevelToggle.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { windowingIconDataUri } from '@itk-viewer/icons'\n\nfunction createWindowLevelToggle(context, uiContainer) {\n  const windowLevelToggle = document.createElement('div')\n  windowLevelToggle.innerHTML = `<input id=\"${context.id}-windowLevelToggle\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-left itk-vtk-tooltip-content=\"Toggle window/level interactor\" class=\"${style.windowLevelButton} ${style.toggleButton}\" for=\"${context.id}-windowLevelToggle\"><img src=\"${windowingIconDataUri}\" alt=\"Window/Level\" /></label>`\n  const windowLevelToggleInput = windowLevelToggle.children[0]\n  const windowLevelToggleLabel = windowLevelToggle.children[1]\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    windowLevelToggleLabel\n  )\n  context.images.windowLevelToggleLabel = windowLevelToggleLabel\n  context.images.windowLevelToggleInput = windowLevelToggleInput\n\n  windowLevelToggle.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const name = context.images.selectedName\n    const actorContext = context.images.actorContext.get(name)\n    context.service.send({\n      type: 'WINDOW_LEVEL_TOGGLED',\n      data: {\n        name,\n        component: actorContext.selectedComponent,\n      },\n    })\n  })\n  uiContainer.appendChild(windowLevelToggle)\n}\n\nexport default createWindowLevelToggle\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/imagesUIMachineOptions.js",
    "content": "import createImagesInterface from './createImagesInterface'\nimport updateImageInterface from './updateImageInterface'\nimport updateLabelImageInterface from './updateLabelImageInterface'\nimport updateRenderedImageInterface from './updateRenderedImageInterface'\nimport selectImageComponent from './selectImageComponent'\nimport toggleInterpolation from './toggleInterpolation'\nimport applyComponentVisibility from './applyComponentVisibility'\nimport applyColorRange from './applyColorRange'\nimport applyColorRangeBounds from './applyColorRangeBounds'\nimport applyColorMap from './applyColorMap'\nimport applyPiecewiseFunctionGaussians from './applyPiecewiseFunctionGaussians'\nimport toggleShadow from './toggleShadow'\nimport applyGradientOpacity from './applyGradientOpacity'\nimport applyGradientOpacityScale from './applyGradientOpacityScale'\nimport applyVolumeSampleDistance from './applyVolumeSampleDistance'\nimport applyBlendMode from './applyBlendMode'\nimport applyHistogram from './applyHistogram'\nimport applyLookupTable from './applyLookupTable'\nimport applyLabelImageBlend from './applyLabelImageBlend'\nimport applyLabelImageWeights from './applyLabelImageWeights'\nimport applyLabelNames from './applyLabelNames'\nimport applySelectedLabel from './applySelectedLabel'\nimport scaleSelector from './scaleSelector'\nimport { applyPiecewiseFunctionPointsToEditor } from './createTransferFunctionWidget'\nimport { applyCinematicChanged } from './cinematic'\nimport toggleWindowLevel from './toggleWindowLevel'\nimport applyWindowLevelReset from './applyWindowingReset'\n\nconst imagesUIMachineOptions = {\n  actions: {\n    createImagesInterface,\n    updateImageInterface,\n    updateLabelImageInterface,\n    updateRenderedImageInterface,\n\n    selectImageComponent,\n\n    toggleInterpolation,\n\n    applyComponentVisibility,\n    applyColorRange,\n    applyColorRangeBounds,\n    applyColorMap,\n    applyPiecewiseFunctionGaussians,\n    applyPiecewiseFunctionPointsToEditor,\n    toggleWindowLevel,\n    applyWindowLevelReset,\n\n    toggleShadow,\n    applyGradientOpacity,\n    applyGradientOpacityScale,\n    applyVolumeSampleDistance,\n    applyBlendMode,\n    applyCinematicChanged,\n\n    applyHistogram,\n\n    applyLookupTable,\n    applyLabelImageBlend,\n    applyLabelImageWeights,\n    applyLabelNames,\n    applySelectedLabel,\n  },\n  services: {\n    scaleSelector,\n  },\n}\n\nexport default imagesUIMachineOptions\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/scaleSelector.js",
    "content": "import applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\nimport style from '../ItkVtkViewer.module.css'\nimport { scaleSelectIconDataUri } from '@itk-viewer/icons'\n\nfunction applyScaleCount(input, scaleCount) {\n  input.innerHTML = '' // clear old options\n  const autoPickOption = document.createElement('option')\n  autoPickOption.value = 'Framerate-pick'\n  autoPickOption.innerHTML = 'Framerate-pick'\n  input.appendChild(autoPickOption)\n  ;[...Array(scaleCount).keys()].reverse().forEach(i => {\n    const option = document.createElement('option')\n    option.value = i\n    option.innerHTML = i\n    input.appendChild(option)\n  })\n}\n\nconst scaleSelector = (context, event) => (send, onReceive) => {\n  const scaleSelectorDiv = document.createElement('div')\n  scaleSelectorDiv.setAttribute(\n    'style',\n    'display: flex; align-self: center; height: 25px; margin-right: 5px'\n  )\n  context.images.componentAndScale.appendChild(scaleSelectorDiv)\n\n  scaleSelectorDiv.innerHTML = `\n    <div itk-vtk-tooltip itk-vtk-tooltip-top-screenshot itk-vtk-tooltip-content=\"Resolution Scale\"\n      class=\"${style.blendModeButton}\">\n      <img src=\"${scaleSelectIconDataUri}\" alt=\"Resolution Scale\" />\n    </div>\n    `\n  const scaleSelectorIcon = scaleSelectorDiv.children[0]\n  context.images.scaleSelectorIconDiv = scaleSelectorIcon // stash for applyImagesContrastSensitiveStyle\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    scaleSelectorIcon\n  )\n\n  const scaleSelector = document.createElement('select')\n  scaleSelectorDiv.appendChild(scaleSelector)\n  scaleSelector.setAttribute('style', 'max-width: 3.2ch')\n  scaleSelector.setAttribute('class', style.selector)\n\n  scaleSelector.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n\n    const imageActor = context.images.imageRenderingActors.get(\n      context.images.selectedName\n    )\n    if (event.target.value === 'Framerate-pick') {\n      imageActor.send('ADJUST_SCALE_FOR_FRAMERATE')\n    } else {\n      imageActor.send('SET_IMAGE_SCALE', {\n        targetScale: parseInt(event.target.value),\n      })\n    }\n  })\n\n  function onImageAssigned(name) {\n    const imageActorContext = context.images.actorContext.get(name)\n    const image = imageActorContext.image ?? imageActorContext.labelImage\n    const scaleCount = image.scaleInfo.length\n    if (scaleCount > 1) {\n      scaleSelectorDiv.style.display = 'flex'\n      applyScaleCount(scaleSelector, scaleCount)\n    } else {\n      scaleSelectorDiv.style.display = 'none'\n    }\n  }\n\n  onImageAssigned(event.data)\n\n  onReceive(event => {\n    const { type } = event\n    if (type === 'IMAGE_ASSIGNED') {\n      onImageAssigned(event.data)\n    } else if (type === 'RENDERED_IMAGE_ASSIGNED') {\n      scaleSelector.value = event.loadedScale\n    } else if (type === 'IMAGE_RENDERING_ACTIVE') {\n      // set scale number after ADJUST_SCALE_FOR_FRAMERATE even if no scale change\n      scaleSelector.value = context.images.actorContext.get(\n        event.data.name\n      ).loadedScale\n    }\n  })\n}\n\nexport default scaleSelector\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/selectImageComponent.js",
    "content": "import applyColorRangeBounds from './applyColorRangeBounds'\nimport applyColorRange from './applyColorRange'\nimport applyColorMap from './applyColorMap'\nimport applyHistogram from './applyHistogram'\n\nfunction selectImageComponent(context, event) {\n  context.images.componentSelector.value = event.data\n\n  const name = event.data.name\n  const actorContext = context.images.actorContext.get(name)\n  const component = event.data.component\n\n  const transferFunctionWidget = context.images.transferFunctionWidget\n\n  if (actorContext.colorRanges.has(component)) {\n    const range = actorContext.colorRanges.get(component)\n    applyColorRange(context, {\n      data: {\n        name,\n        component,\n        range,\n      },\n    })\n  }\n\n  const piecewiseFunctionPoints = actorContext.piecewiseFunctionPoints.get(\n    component\n  )\n  if (transferFunctionWidget && piecewiseFunctionPoints) {\n    transferFunctionWidget.setPoints(piecewiseFunctionPoints)\n  }\n\n  if (actorContext.colorRangeBounds.has(component)) {\n    applyColorRangeBounds(context, {\n      data: {\n        name,\n        component,\n        range: actorContext.colorRangeBounds.get(component),\n      },\n    })\n  }\n\n  if (actorContext.colorMaps.has(component)) {\n    applyColorMap(context, {\n      data: {\n        name,\n        component,\n        colorMap: actorContext.colorMaps.get(component),\n      },\n    })\n    context.images.iconSelector.setSelectedValue(\n      actorContext.colorMaps.get(component)\n    )\n  }\n\n  const histogram = actorContext.histograms.get(component)\n  if (histogram) {\n    applyHistogram(context, {\n      data: {\n        name,\n        component,\n        histogram,\n      },\n    })\n  } else {\n    context.service.send({\n      type: 'UPDATE_IMAGE_HISTOGRAM',\n      data: { name, component },\n    })\n  }\n}\n\nexport default selectImageComponent\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/throttle.js",
    "content": "// from https://stackoverflow.com/a/27078401\n\n// Trailing call functionality is desired.\n// Returns a function, that, when invoked, will only be triggered at most once\n// during a given window of time. Normally, the throttled function will run\n// as much as it can, without ever going more than once per `wait` duration;\n// but if you'd like to disable the execution on the leading edge, pass\n// `{leading: false}`. To disable execution on the trailing edge, ditto.\nexport function throttle(func, wait, options) {\n  var context, args, result\n  var timeout = null\n  var previous = 0\n  if (!options) options = {}\n  var later = function() {\n    previous = options.leading === false ? 0 : Date.now()\n    timeout = null\n    result = func.apply(context, args)\n    if (!timeout) context = args = null\n  }\n  return function() {\n    var now = Date.now()\n    if (!previous && options.leading === false) previous = now\n    var remaining = wait - (now - previous)\n    context = this\n    args = arguments\n    if (remaining <= 0 || remaining > wait) {\n      if (timeout) {\n        clearTimeout(timeout)\n        timeout = null\n      }\n      previous = now\n      result = func.apply(context, args)\n      if (!timeout) context = args = null\n    } else if (!timeout && options.trailing !== false) {\n      timeout = setTimeout(later, remaining)\n    }\n    return result\n  }\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/toggleInterpolation.js",
    "content": "function toggleInterpolation(context, event) {\n  const name = event.data\n  const actorContext = context.images.actorContext.get(name)\n  const interpolation = actorContext.interpolationEnabled\n\n  context.images.interpolationButtonInput.checked = interpolation\n}\n\nexport default toggleInterpolation\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/toggleShadow.js",
    "content": "function toggleShadow(context, event) {\n  const name = event.data\n  const actorContext = context.images.actorContext.get(name)\n  const shadow = actorContext.shadowEnabled\n\n  context.images.shadowButtonInput.checked = shadow\n}\n\nexport default toggleShadow\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/toggleUseShadow.js",
    "content": "function toggleUseShadow(context, event) {\n  const name = event.data\n\n  const actorContext = context.images.actorContext.get(name)\n\n  const useShadow = actorContext.useShadow\n\n  context.images.useShadowButtonInput.checked = useShadow\n\n  context.imageUI.representationProxy.setUseShadow(useShadow)\n  context.service.send('RENDER')\n}\n\nexport default toggleUseShadow\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/toggleWindowLevel.js",
    "content": "const MIN_WINDOW = 1e-8\n\nfunction toggleWindowLevel(context, event) {\n  const name = event.data.name\n  const actorContext = context.images.actorContext.get(name)\n  const wl = actorContext.windowLevelEnabled\n  const colorRange = actorContext.colorRanges.get(\n    actorContext.selectedComponent\n  )\n  const fullRange = actorContext.colorRangeBounds.get(\n    actorContext.selectedComponent\n  )\n\n  context.images.windowLevelToggleInput.checked = wl\n\n  const minimumTooltip = context.images.colorRangeInputRow.children[1]\n  const maximumTooltip = context.images.colorRangeInputRow.children[3]\n\n  const minimumInput = minimumTooltip.children[0]\n  const maximumInput = maximumTooltip.children[0]\n\n  if (wl) {\n    minimumTooltip.setAttribute('itk-vtk-tooltip-content', 'Window width')\n    maximumTooltip.setAttribute('itk-vtk-tooltip-content', 'Window level')\n\n    minimumInput.value = colorRange[1] - colorRange[0]\n    maximumInput.value = (colorRange[1] + colorRange[0]) / 2\n\n    minimumInput.min = MIN_WINDOW\n    minimumInput.max = (fullRange[1] - fullRange[0]) * 2\n    maximumInput.min = fullRange[0] - fullRange[0]\n    maximumInput.max = fullRange[1] + fullRange[1]\n\n    const step = 10 ** Math.ceil(Math.log((fullRange[1] - fullRange[0]) / 1000))\n    minimumInput.step = step\n    maximumInput.step = step\n  } else {\n    minimumTooltip.setAttribute('itk-vtk-tooltip-content', 'Color range min')\n    maximumTooltip.setAttribute('itk-vtk-tooltip-content', 'Color range max')\n\n    minimumInput.value = colorRange[0]\n    maximumInput.value = colorRange[1]\n\n    minimumInput.min = fullRange[0]\n    minimumInput.max = fullRange[1]\n    maximumInput.min = fullRange[0]\n    maximumInput.max = fullRange[1]\n\n    const step = (fullRange[1] - fullRange[0]) / 1000.0\n    minimumInput.step = step\n    maximumInput.step = step\n  }\n}\n\nexport default toggleWindowLevel\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/updateAvailableComponents.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nfunction updateAvailableComponents(context) {\n  const name = context.images.selectedName\n  const actorContext = context.images.actorContext.get(name)\n  const image = actorContext.image\n\n  if (image) {\n    const components = actorContext.componentVisibilities.length\n    if (components > 1 && actorContext.independentComponents) {\n      context.images.componentRow.style.display = 'flex'\n    } else {\n      context.images.componentRow.style.display = 'none'\n    }\n\n    context.images.componentSelector.innerHTML = new Array(components)\n      .fill(undefined)\n      .map((_, ii) => ii)\n      .map(\n        (idx, component) =>\n          `<input name=\"tabs\" type=\"radio\" id=\"tab-${component}\" ${\n            idx === 0 ? 'checked=\"checked\"' : ''\n          } class=\"${\n            style.componentTab\n          }\" data-component-index=\"${component}\"/><label for=\"tab-${component}\" class=\"${\n            style.compTabLabel\n          }\">&nbsp;${component}&nbsp;<input type=\"checkbox\" ${\n            actorContext.componentVisibilities[idx] ? 'checked=\"checked\"' : ''\n          } class=\"${\n            style.componentVisibility\n          }\" data-component-index=\"${component}\"></label>`\n      )\n      .join('')\n    context.images.componentSelector.value = actorContext.selectedComponent\n  }\n}\n\nexport default updateAvailableComponents\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/updateImageInterface.js",
    "content": "import updateAvailableComponents from './updateAvailableComponents'\nimport toggleInterpolation from './toggleInterpolation'\nimport applyColorRangeBounds from './applyColorRangeBounds'\nimport applyColorRange from './applyColorRange'\nimport applyColorMap from './applyColorMap'\nimport toggleShadow from './toggleShadow'\nimport applyGradientOpacity from './applyGradientOpacity'\nimport applyGradientOpacityScale from './applyGradientOpacityScale'\nimport applyVolumeSampleDistance from './applyVolumeSampleDistance'\nimport applyBlendMode from './applyBlendMode'\n\nfunction updateImageInterface(context) {\n  updateAvailableComponents(context)\n\n  const name = context.images.selectedName\n  const actorContext = context.images.actorContext.get(name)\n  const image = actorContext.image\n  const component = actorContext.selectedComponent\n\n  // If not a 2D RGB image\n  if (actorContext.independentComponents) {\n    context.images.colorRangeInputRow.style.display = 'flex'\n    context.images.colorMapSelector.style.display = 'block'\n  } else {\n    context.images.colorRangeInputRow.style.display = 'none'\n    context.images.colorMapSelector.style.display = 'none'\n  }\n\n  if (image) {\n    if (image.imageType.dimension === 3) {\n      context.images.volumeUiElements.forEach(e => (e.style.display = 'flex'))\n      if (context.main.xPlaneRow) {\n        context.main.xPlaneRow.style.display = 'flex'\n        context.main.yPlaneRow.style.display = 'flex'\n        context.main.zPlaneRow.style.display = 'flex'\n      }\n    } else {\n      context.images.volumeUiElements.forEach(e => (e.style.display = 'none'))\n      if (context.main.xPlaneRow) {\n        context.main.xPlaneRow.style.display = 'none'\n        context.main.yPlaneRow.style.display = 'none'\n        context.main.zPlaneRow.style.display = 'none'\n      }\n    }\n\n    toggleInterpolation(context, { data: name })\n\n    if (actorContext.colorRanges.has(component)) {\n      applyColorRange(context, {\n        data: {\n          name,\n          component,\n          range: actorContext.colorRanges.get(component),\n        },\n      })\n    }\n\n    if (actorContext.colorRangeBounds.has(component)) {\n      applyColorRangeBounds(context, {\n        data: {\n          name,\n          component,\n          range: actorContext.colorRangeBounds.get(component),\n        },\n      })\n    }\n\n    if (actorContext.colorMaps.has(component)) {\n      const colorMap = actorContext.colorMaps.get(component)\n      applyColorMap(context, {\n        data: {\n          name,\n          component,\n          colorMap,\n        },\n      })\n      context.images.iconSelector.setSelectedValue(colorMap)\n    }\n\n    toggleShadow(context, { data: name })\n    applyGradientOpacity(context, {\n      data: { name, gradientOpacity: actorContext.gradientOpacity },\n    })\n    applyGradientOpacityScale(context, {\n      data: { name, gradientOpacityScale: actorContext.gradientOpacityScale },\n    })\n    applyVolumeSampleDistance(context, {\n      data: { name, volumeSampleDistance: actorContext.volumeSampleDistance },\n    })\n    applyBlendMode(context, {\n      data: { name, blendMode: actorContext.blendMode },\n    })\n  }\n}\n\nexport default updateImageInterface\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/updateLabelImageInterface.js",
    "content": "import applyLookupTable from './applyLookupTable'\nimport applyLabelImageBlend from './applyLabelImageBlend'\nfunction updateLabelImageInterface(context) {\n  const name = context.images.selectedName\n  const actorContext = context.images.actorContext.get(name)\n  const labelImage = actorContext.labelImage\n\n  if (labelImage) {\n    applyLookupTable(context, {\n      data: { name, lookupTable: actorContext.lookupTable },\n    })\n    applyLabelImageBlend(context, {\n      data: { name, labelImageBlend: actorContext.labelImageBlend },\n    })\n  }\n}\n\nexport default updateLabelImageInterface\n"
  },
  {
    "path": "src/UI/reference-ui/src/Images/updateRenderedImageInterface.js",
    "content": "function updateRenderedImageInterface(context, event) {\n  const name = event.data\n  const actorContext = context.images.actorContext.get(name)\n  const { transferFunctionWidget } = context.images\n\n  if (!transferFunctionWidget) {\n    console.warn('No transfer function widget')\n    return\n  }\n\n  const points = actorContext.piecewiseFunctionPoints.get(\n    actorContext.selectedComponent\n  )\n  // no points if just label image\n  if (points) {\n    transferFunctionWidget.setPoints(points)\n  }\n}\n\nexport default updateRenderedImageInterface\n"
  },
  {
    "path": "src/UI/reference-ui/src/ItkVtkViewer.module.css",
    "content": ".loading {\n  border: 16px solid #f3f3f3; /* Light grey */\n  border-top: 16px solid #3498db; /* Blue */\n  border-radius: 50%;\n  width: 120px;\n  height: 120px;\n  position: absolute;\n  left: calc(50% - 60px);\n  top: calc(50% - 60px);\n  animation: spin 2s linear infinite;\n  box-sizing: border-box;\n}\n\n@keyframes spin {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n.viewContainer {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  right: 0;\n  display: flex;\n  flex-direction: column;\n  background: rgba(128, 128, 128, 0.8);\n}\n\n.viewport {\n  position: relative;\n  flex: 1;\n  min-height: 0;\n}\n\n.uiContainer {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1000;\n\n  height: fit-content;\n  max-height: 100%;\n\n  display: flex;\n\n  padding: 6px 0 0 6px;\n  border: 0px;\n  box-sizing: border-box;\n\n  --md-navigation-drawer-container-shape-start-end: 0;\n  --md-navigation-drawer-container-shape-end-end: 0;\n  --md-navigation-drawer-container-color: rgba(128, 128, 128, 0.5);\n}\n\n.drawer {\n  overflow: hidden auto;\n}\n\n.floater {\n  position: absolute;\n  z-index: 3000;\n}\n\n.uiGroup {\n  background: rgba(128, 128, 128, 0.5);\n  border-radius: 4px;\n  margin: 2px;\n}\n\n.uiRow {\n  display: flex;\n  flex-direction: row;\n  flex: 1;\n  align-items: center;\n  justify-content: space-between;\n  padding: 5px;\n}\n\n.mainUIRow {\n  composes: uiRow;\n  justify-content: space-around;\n  max-width: 420px;\n}\n\n.planeUIRow {\n  composes: uiRow;\n  background: rgba(128, 128, 128, 0.5);\n}\n\n.layers {\n  flex-wrap: wrap;\n}\n\n.progress {\n  color: white;\n  font-size: 200%;\n  height: 100vh;\n  width: 100vw;\n  text-align: center;\n  vertical-align: middle;\n  line-height: 100vh;\n}\n\n.piecewiseWidget {\n  flex: 1;\n  background: rgba(255, 255, 255, 0.2);\n  border-radius: 3px;\n  z-index: 1000;\n}\n\n.logo {\n  position: absolute;\n  top: 5px;\n  right: 5px;\n  height: 2em;\n  width: 2em;\n  cursor: pointer;\n  z-index: 100;\n}\n\n.fpsMonitor {\n  position: absolute;\n  top: 5px;\n  right: 5px;\n  border-radius: 5px;\n  background: rgba(255, 255, 255, 0.6);\n  cursor: pointer;\n  z-index: 101;\n}\n\n[itk-vtk-tooltip] {\n  position: relative;\n}\n[itk-vtk-tooltip]::before {\n  content: attr(itk-vtk-tooltip-content);\n  visibility: hidden;\n  position: absolute;\n  top: 50%;\n  right: calc(100% + 16px);\n  width: 400%;\n  padding: 4px 6px;\n  text-align: center;\n  text-transform: none;\n  font-size: 0.9em;\n  font-family: monospace;\n  border-radius: 3px;\n  background: rgba(0.9, 0.9, 0.9, 0.95);\n  color: white;\n  opacity: 0;\n  transform: translate(15px, -50%);\n  transition-property: all;\n  transition-duration: 0.3s;\n  transition-timing-function: ease-in-out;\n  transition-delay: 0.8s;\n  z-index: 3000;\n}\n\n[itk-vtk-tooltip]:hover::before {\n  opacity: 1;\n  visibility: visible;\n  transform: translate(0, -50%);\n}\n\n[itk-vtk-tooltip-bottom]::before {\n  top: calc(100% + 16px);\n  left: 50%;\n  right: initial;\n  transform: translate(-50%, -15px);\n}\n[itk-vtk-tooltip-bottom]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-right]::before {\n  top: 50%;\n  left: calc(100% + 16px);\n  right: initial;\n  transform: translate(-15px, -50%);\n}\n[itk-vtk-tooltip-right]:hover::before {\n  transform: translate(0, -50%);\n}\n[itk-vtk-tooltip-left]::before {\n  top: -50%;\n  right: 50%;\n  left: initial;\n}\n\n[itk-vtk-tooltip-top-screenshot]::before {\n  top: initial;\n  left: 260%;\n  right: initial;\n  bottom: calc(100% + 8px);\n  transform: translate(-50%, 15px);\n}\n[itk-vtk-tooltip-top-screenshot]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top-annotations]::before {\n  top: initial;\n  left: 160%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n}\n[itk-vtk-tooltip-top-annotations]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top-axes]::before {\n  top: initial;\n  left: 160%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n}\n[itk-vtk-tooltip-top-axes]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top-fullscreen]::before {\n  top: initial;\n  left: 120%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n  width: 400%;\n}\n[itk-vtk-tooltip-top-fullscreen]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top]::before {\n  top: initial;\n  left: 60%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n}\n[itk-vtk-tooltip-top]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top-fullscreen]::before {\n  top: initial;\n  left: 120%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n  width: 400%;\n}\n[itk-vtk-tooltip-top-input]::before {\n  top: initial;\n  right: initial;\n  bottom: 25%;\n  transform: translate(-50%, 15px);\n  width: fit-content;\n}\n\n.layerEntryCommon {\n  flex: 1;\n  display: flex;\n  flex-direction: row;\n  align-items: stretch;\n  justify-content: space-between;\n  border-style: solid;\n  border-width: 2px;\n}\n\n.layerEntryBrightBG {\n  border-color: #666;\n}\n\n.layerEntryDarkBG {\n  border-color: #aaa;\n}\n\n.layerLabelCommon {\n  border: none;\n  background: transparent;\n  font-size: 1.2em;\n  z-index: 1000;\n\n  flex: 1;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  text-align: center;\n}\n\n.layerLabelBrightBG {\n  color: black;\n}\n\n.layerLabelDarkBG {\n  color: white;\n}\n\n.visibleButton {\n  flex-basis: 2.5em;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.visibleButton img {\n  height: 1.2em;\n  width: 1.2em;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n}\n\n.noFlexBasis {\n  flex-basis: auto;\n}\n\n.layerIcon {\n  display: inline-block;\n}\n\n.layerIcon img {\n  height: 1.2em;\n  width: 1.2em;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 8px;\n  padding-right: 6px;\n}\n\n.iconGroup {\n  display: inline-block;\n}\n\n.ldsRing {\n  display: inline-block;\n  position: relative;\n  width: 20px;\n  height: 20px;\n  margin-top: 4px;\n}\n.ldsRing div {\n  box-sizing: border-box;\n  display: block;\n  position: absolute;\n  width: 1em;\n  height: 1em;\n  margin: 0;\n  border: 0.15em solid #000;\n  border-radius: 50%;\n  animation: ldsRing 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;\n  border-color: #000 transparent transparent transparent;\n}\n.ldsRing div:nth-child(1) {\n  animation-delay: -0.45s;\n}\n.ldsRing div:nth-child(2) {\n  animation-delay: -0.3s;\n}\n.ldsRing div:nth-child(3) {\n  animation-delay: -0.15s;\n}\n@keyframes ldsRing {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n.tooltipButtonBrightBG::before {\n}\n\n.tooltipButtonDarkBG::before {\n  filter: invert(100%);\n  -webkit-filter: invert(100%);\n}\n\n.invertibleButtonBrightBG {\n}\n\n.invertibleButtonDarkBG {\n  filter: invert(100%);\n  -webkit-filter: invert(100%);\n}\n\n.screenshotButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.screenshotButton img {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.annotationsButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.annotationsButton img {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.axesButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.axesButton img {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.fullscreenButton {\n  flex: 1;\n  width: 8m;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.fullscreenButton img {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.interpolationButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-right: 4px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.interpolationButton img {\n  width: 1.2em;\n  margin-top: 4px;\n}\n\n.cropButton {\n  flex: 1;\n  height: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.cropButton img {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.resetCropButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.resetCropButton img {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.distanceEntry {\n  flex: 1;\n  display: flex;\n  flex-direction: row;\n  align-items: self-start;\n}\n\n.distanceButton {\n  flex: 1;\n  height: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.distanceButton img {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.distanceLabelCommon {\n  border: none;\n  background: transparent;\n  font-size: 1.2em;\n  margin-right: 10px;\n  z-index: 1000;\n}\n\n.distanceLabelBrightBG {\n  color: black;\n}\n\n.distanceLabelDarkBG {\n  color: white;\n}\n\n.distanceInput {\n  background: transparent;\n  color: white;\n  font-size: 1em;\n  width: 80px;\n}\n\n.resetCameraButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.resetCameraButton img {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.bgColorButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.bgColorButton img {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.viewModeButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.viewModeButton img {\n  width: 1.3em;\n  height: 1.3em;\n}\n\n.shadowButton {\n  width: 8mm;\n  padding: 4px;\n  padding-left: 0px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.shadowButton img {\n  width: 1.3em;\n  height: 1.3em;\n}\n\n.viewPlanesButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 0px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.viewPlanesButton img {\n  width: 1.3em;\n  height: 1.3em;\n}\n\n.toggleInput {\n  margin: 0px;\n  width: 0;\n  opacity: 0;\n  box-sizing: content-box;\n}\n\n.toggleButton {\n  cursor: pointer;\n  border-radius: 0.2em;\n  opacity: 0.45;\n}\n\ninput:checked.toggleInput + label {\n  opacity: 1;\n}\n\n.numberInput {\n  color: white;\n  background: transparent;\n  font-size: 1em;\n  padding-left: 2px;\n  width: 70px;\n}\n\n.selector {\n  display: flex;\n  direction: row;\n  font-size: 1.2em;\n  z-index: 1000;\n}\n\n.componentTab {\n  position: absolute;\n  opacity: 0;\n  pointer-events: none;\n}\n\n.disableInterface {\n  pointer-events: none;\n  opacity: 0.5;\n}\n\n.componentTab + .compTabLabel {\n  background: rgba(40, 40, 40, 0.5);\n  padding: 5px;\n  margin-right: 2px;\n  border-radius: 5px 5px 0px 0px;\n  color: #777;\n}\n\n.componentTab:hover + .compTabLabel {\n  background: rgba(90, 90, 90, 0.5);\n}\n\n.componentTab:checked + .compTabLabel {\n  background: rgba(127, 127, 127, 0.5);\n  color: #fff;\n}\n\n.componentVisibility {\n  position: relative;\n  top: -2px;\n  margin-left: 10px;\n}\n\nselect {\n  -moz-appearance: none;\n}\n\nselect option {\n  color: black;\n}\n\nselect:focus {\n  outline: none;\n  border: none;\n}\n\n.sampleDistanceButton {\n  width: 8mm;\n  padding: 4px;\n  padding-left: 6px;\n  z-index: 1000;\n}\n\n.sampleDistanceButton img {\n  width: 1.2em;\n  height: 1.2em;\n}\n\n.sliderColumn {\n  display: flex;\n  flex-direction: column;\n  flex: 1;\n  padding: 0 5px;\n}\n\n.sliderIcon {\n  width: 1.8em;\n  margin-right: 10px;\n  z-index: 1000;\n}\n\n.blendModeButton {\n  width: 8mm;\n  padding: 4px;\n  padding-left: 8px;\n  padding-right: 0px;\n  z-index: 1000;\n}\n\n.blendModeButton img {\n  width: 1.2em;\n  height: 1.2em;\n}\n\n.gradientOpacitySlider {\n  width: 8mm;\n  padding: 4px;\n  padding-left: 6px;\n  padding-right: 0px;\n  z-index: 1000;\n}\n\n.gradientOpacitySlider img {\n  width: 1.2em;\n  height: 1.2em;\n}\n\n.sliderEntry {\n  flex: 1;\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n}\n\n.slider {\n  flex: 1;\n  min-height: 1rem;\n}\n\n.planeLabel {\n  padding-left: 6px;\n  padding: 2px;\n  display: block;\n  font-size: 1.1em;\n  font-family: monospace;\n  color: black;\n  border-width: 2px;\n  border-radius: 10%;\n}\n\n.xPlaneLabel {\n  composes: planeLabel;\n  background-color: #ef5350;\n}\n\n.yPlaneLabel {\n  composes: planeLabel;\n  background-color: #fdd835;\n}\n\n.zPlaneLabel {\n  composes: planeLabel;\n  background-color: #4caf50;\n}\n\n.gradientOpacityScale {\n  z-index: 1100;\n  position: relative;\n}\n\n.gradientOpacityScale input {\n  position: absolute;\n  bottom: 20px;\n  left: -24px;\n  width: 12px;\n  writing-mode: bt-lr;\n  -webkit-appearance: slider-vertical;\n}\n\n.bigFileDrop {\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n  background-color: white;\n  background-image: url('./dropBG.jpg');\n  background-repeat: no-repeat;\n  background-position: center;\n  background-size: contain;\n  border-radius: 10px;\n  width: 50px;\n  padding: calc(50vh - 2em) calc(50vw - 25px - 2em);\n}\n\n.fullscreenContainer {\n  position: absolute;\n  width: 100vw;\n  height: 100vh;\n  top: 0;\n  left: 0;\n  overflow: hidden;\n  background: black;\n  margin: 0;\n  padding: 0;\n}\n\n.collapseButton {\n  position: absolute;\n  top: 0;\n  right: -48px;\n}\n\n.windowLevelButton {\n  width: 8mm;\n  padding: 4px;\n  padding-left: 0px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.windowLevelButton img {\n  width: 1.3em;\n  height: 1.3em;\n}\n\n.inputLabel {\n  line-height: 1.7;\n}\n\n.saveDialog label {\n  display: flex;\n  align-items: center;\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/addLayerUIRow.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nfunction addLayerUIRow(context) {\n  const layersUIRow = document.createElement('div')\n  layersUIRow.setAttribute('class', style.layersUIRow)\n  context.layers.layersUIGroup.appendChild(layersUIRow)\n}\n\nexport default addLayerUIRow\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/applyLayersContrastSensitiveStyle.js",
    "content": "import applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nfunction applyLayersContrastSensitiveStyle(context) {\n  context.layers.uiLayers.forEach(layerEntry => {\n    applyContrastSensitiveStyleToElement(context, 'layerEntry', layerEntry)\n    const visibleButton = layerEntry.children[0]\n    const visibleLabel = visibleButton.children[1]\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      visibleLabel\n    )\n    const invisibleButton = layerEntry.children[1]\n    const invisibleLabel = invisibleButton.children[1]\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      invisibleLabel\n    )\n    const layerLabel = layerEntry.children[2]\n    applyContrastSensitiveStyleToElement(context, 'layerLabel', layerLabel)\n    const iconElement = layerEntry.children[3]\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      iconElement\n    )\n  })\n}\n\nexport default applyLayersContrastSensitiveStyle\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/compareUI.js",
    "content": "import {\n  playIconDataUri,\n  pauseIconDataUri,\n  rotateIconDataUri,\n} from '@itk-viewer/icons'\nimport style from '../ItkVtkViewer.module.css'\nimport { makeHtml } from '../utils'\n\nexport const compareUI = context => (send, onReceive) => {\n  const root = document.createElement('div')\n  root.setAttribute(\n    'style',\n    'align-self: center; align-content: center; margin-left: 4px; margin-right: 4px'\n  )\n  const parent = context.layers.compareContainer\n  parent.appendChild(root)\n\n  const checkerboardUi = makeHtml(`\n    <div style=\"display: flex; justify-content: space-between;\">\n      <label class=\"${style.inputLabel}\">Checkerboard Pattern X</label>\n      <input id=\"x-pattern\" type=\"number\" class=\"${style.selector} ${style.numberInput}\" style=\"max-width: 3.2ch\" />\n      <label class=\"${style.inputLabel}\">Y</label>\n      <input type=\"number\" class=\"${style.selector} ${style.numberInput}\" style=\"max-width: 3.2ch\" />\n      <label class=\"${style.inputLabel}\">Z</label>\n      <input type=\"number\" class=\"${style.selector} ${style.numberInput}\" style=\"max-width: 3.2ch\" />\n    </div>\n  `)\n  root.appendChild(checkerboardUi)\n\n  const swapButtonId = `${context.id}-swapImageOrder`\n  const playImageMixButtonId = `${context.id}-image-mix-play`\n  const playImageMixImgId = `${context.id}-image-mix-play-img`\n  const imageMixRoot = makeHtml(`\n    <div style=\"display: flex; justify-content: space-between;\">\n      <label class=\"${style.inputLabel}\">Image Mix</label>\n      <input id=\"${playImageMixButtonId}\" type=\"checkbox\" class=\"${style.toggleInput}\">\n        <label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"animate\" class=\"${style.visibleButton} ${style.noFlexBasis} ${style.toggleButton}\" for=\"${playImageMixButtonId}\">\n          <img src=\"${playIconDataUri}\" id=\"${playImageMixImgId}\" alt=\"animate\" />\n        </label>\n      </input>\n      <input type=\"range\" min=\"0\" max=\"1\" step=\".01\" value=\".5\" \n        class=\"${style.slider}\" />\n      <input type=\"checkbox\" id=\"${swapButtonId}\" class=\"${style.toggleInput}\">\n        <label for=\"${swapButtonId}\" itk-vtk-tooltip itk-vtk-tooltip-left-fullscreen itk-vtk-tooltip-content=\"Swap image\" class=\"${style.rotateButton} ${style.toggleButton}\">\n          <img src=\"${rotateIconDataUri}\" alt=\"rotate\"/>\n        </label>\n      </input>\n    </div>\n  `)\n  root.appendChild(imageMixRoot)\n\n  const [xPattern, yPattern, zPattern] = checkerboardUi.querySelectorAll(\n    'input'\n  )\n\n  const [\n    animateImageMix,\n    imageMixSlider,\n    swapOrder,\n  ] = imageMixRoot.querySelectorAll('input')\n  const animateImageImg = imageMixRoot.querySelector(`#${playImageMixImgId}`)\n\n  const update = () => {\n    const name = context.images.selectedName\n    const imageContext = context.images.actorContext.get(name)\n    const { compare = undefined } = imageContext ?? {}\n    const { method = undefined, checkerboard } = compare ?? {}\n\n    if (method && method !== 'disabled') root.style.display = 'block'\n    else root.style.display = 'none'\n\n    if (checkerboard) {\n      checkerboardUi.style.display = 'flex'\n    } else {\n      checkerboardUi.style.display = 'none'\n    }\n\n    const [x, y, z] = compare?.pattern ?? []\n    xPattern.value = x\n    yPattern.value = y\n    zPattern.value = z\n    swapOrder.checked = !!compare?.swapImageOrder ?? false\n\n    imageMixSlider.value = compare?.imageMix ?? 0.5\n\n    animateImageImg.src = imageContext?.imageMixAnimation\n      ? pauseIconDataUri\n      : playIconDataUri\n  }\n\n  update()\n\n  const updateCompare = options => {\n    const name = context.images.selectedName\n    const imageContext = context.images.actorContext.get(name)\n    const { compare } = imageContext\n    context.service.send({\n      type: 'COMPARE_IMAGES',\n      data: {\n        name,\n        fixedImageName: compare.fixedImageName,\n        options: { ...options },\n      },\n    })\n  }\n\n  const parsePattern = value => Math.max(1, parseInt(value))\n\n  xPattern.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n\n    const [, ...yz] =\n      context.images.actorContext.get(context.images.selectedName).compare\n        .pattern ?? []\n\n    const x = parsePattern(event.target.value)\n    updateCompare({ pattern: [x, ...yz] })\n  })\n\n  yPattern.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n\n    const [x, , z] =\n      context.images.actorContext.get(context.images.selectedName).compare\n        .pattern ?? []\n\n    const y = parsePattern(event.target.value)\n    updateCompare({ pattern: [x, y, z] })\n  })\n\n  zPattern.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n\n    const [x, y] =\n      context.images.actorContext.get(context.images.selectedName).compare\n        .pattern ?? []\n\n    const z = parsePattern(event.target.value)\n    updateCompare({ pattern: [x, y, z] })\n  })\n\n  animateImageMix.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n\n    const name = context.images.selectedName\n    context.service.send({\n      type: 'ANIMATE_IMAGE_MIX',\n      data: {\n        name,\n        play: event.target.checked,\n      },\n    })\n  })\n\n  imageMixSlider.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n\n    updateCompare({ imageMix: event.target.value })\n  })\n\n  swapOrder.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n\n    updateCompare({ swapImageOrder: event.target.checked })\n  })\n\n  onReceive(event => {\n    const { type } = event\n    if (type === 'COMPARE_UPDATED') {\n      update()\n    }\n  })\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/createLayerInterface.js",
    "content": "import '@material/web/dialog/dialog.js'\nimport '@material/web/button/text-button.js'\nimport '@material/web/radio/radio.js'\nimport {\n  invisibleIconDataUri,\n  boundingBoxIconDataUri,\n  downloadIconDataUri,\n  visibleIconDataUri,\n} from '@itk-viewer/icons'\nimport style from '../ItkVtkViewer.module.css'\n\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\nimport { makeHtml } from '../utils'\nimport './layerIcon.js'\nimport { extensions } from './extensionToImageIo.js'\n\nlet dialog\n\nfunction createLayerEntry(context, name, layer) {\n  const layerEntry = document.createElement('div')\n  layerEntry.setAttribute('class', style.layerEntryCommon)\n  layerEntry.style.borderWidth = '3px'\n  applyContrastSensitiveStyleToElement(context, 'layerEntry', layerEntry)\n\n  const visibleButton = document.createElement('div')\n  visibleButton.innerHTML = `<input id=\"${context.id}-visibleButton\" type=\"checkbox\" checked class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Visibility\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-visibleButton\"><img src=\"${visibleIconDataUri}\" alt=\"visible\"/></label>`\n  const visibleLabel = visibleButton.children[1]\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    visibleLabel\n  )\n  layerEntry.appendChild(visibleButton)\n  const invisibleButton = document.createElement('div')\n  invisibleButton.innerHTML = `<input id=\"${context.id}-invisibleButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Visibility\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-invisibleButton\"><img src=\"${invisibleIconDataUri} alt=\"invisible\"\"/></label>`\n  const invisibleLabel = invisibleButton.children[1]\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    invisibleLabel\n  )\n  layerEntry.appendChild(invisibleButton)\n\n  if (layer.visible) {\n    visibleButton.style.display = 'flex'\n    invisibleButton.style.display = 'none'\n  } else {\n    visibleButton.style.display = 'none'\n    invisibleButton.style.display = 'flex'\n  }\n\n  visibleButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({ type: 'TOGGLE_LAYER_VISIBILITY', data: name })\n    visibleButton.checked = true\n  })\n  invisibleButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({ type: 'TOGGLE_LAYER_VISIBILITY', data: name })\n    invisibleButton.checked = false\n  })\n\n  const layerLabel = document.createElement('label')\n  layerLabel.setAttribute('class', `${style.layerLabelCommon}`)\n  applyContrastSensitiveStyleToElement(context, 'layerLabel', layerLabel)\n  layerLabel.innerText = name\n  layerEntry.appendChild(layerLabel)\n\n  const imageIcons = document.createElement('div')\n  imageIcons.style.display = 'flex'\n  imageIcons.setAttribute('class', `${style.iconGroup}`)\n  layerEntry.appendChild(imageIcons)\n\n  const spinner = document.createElement('div')\n  spinner.setAttribute('class', `${style.ldsRing}`)\n  spinner.innerHTML = '<div></div><div></div><div></div><div></div>'\n  imageIcons.appendChild(spinner)\n\n  layer.spinner = spinner\n\n  const layerBBoxButton = document.createElement('div')\n  layerBBoxButton.innerHTML = `<input id=\"${context.id}-layerBBoxButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Bounding Box\" class=\"${style.toggleButton}\" for=\"${context.id}-layerBBoxButton\"><img src=\"${boundingBoxIconDataUri}\" alt=\"bbox\"/></label>`\n  const layerBBoxButtonInput = layerBBoxButton.children[0]\n  const layerBBoxLabel = layerBBoxButton.children[1]\n  layerBBoxButton.style.height = '23px'\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    layerBBoxLabel\n  )\n  imageIcons.appendChild(layerBBoxButton)\n  layerBBoxButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'TOGGLE_LAYER_BBOX',\n      data: {\n        name: context.images.selectedName,\n        layerName: name,\n      },\n    })\n    const actorContext = context.layers.actorContext.get(name)\n    layerBBoxButtonInput.checked = actorContext.bbox\n  })\n\n  // There can only be one dialog in app?  OK/Cancel buttons don't work if multiple layers...\n  if (!dialog) {\n    dialog = makeHtml(`\n    <md-dialog class=\"${style.saveDialog}\">\n      <div slot=\"headline\">Save file format</div>\n      <form id=\"save-form\" slot=\"content\" method=\"dialog\">\n        ${extensions\n          .map(\n            (extension, i) =>\n              `<label>\n                <md-radio name=\"format\" value=\"${extension}\" ${\n                i === 0 ? 'checked' : ''\n              } touch-target=\"wrapper\"></md-radio>\n                <span aria-hidden=\"true\">${extension}</span>\n              </label>`\n          )\n          .join('')}\n      </form>\n      <div slot=\"actions\">\n        <md-text-button form=\"save-form\" value=\"cancel\">Cancel</md-text-button>\n        <md-text-button form=\"save-form\" autofocus value=\"ok\">OK</md-text-button>\n      </div>\n    </md-dialog>\n  `)\n    dialog.addEventListener('close', () => {\n      const okClicked = dialog.returnValue === 'ok'\n\n      if (okClicked) {\n        const radios = document.querySelectorAll('md-radio[name=format]')\n        const format = Array.from(radios).find(radio => radio.checked).value\n        context.service.send({\n          type: 'DOWNLOAD_IMAGE',\n          data: {\n            name: context.images.selectedName,\n            format,\n          },\n        })\n      }\n    })\n    imageIcons.appendChild(dialog)\n  }\n\n  const downloadImage = document.createElement('div')\n  downloadImage.innerHTML = `\n  <input type=\"checkbox\" checked id=${context.id}-download-image\" class=\"${style.toggleInput}\" />\n  <label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Save ROI\" class=\"${style.toggleButton}\" for=\"${context.id}-download-image\">\n    <img style=\"height: 23px\" src=\"${downloadIconDataUri}\" />\n  </label>\n  `\n  const downloadImageLabel = downloadImage.children[1]\n  downloadImage.style.height = '23px'\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    downloadImageLabel\n  )\n  imageIcons.appendChild(downloadImage)\n  downloadImage.addEventListener('click', event => {\n    event.stopPropagation()\n    dialog.show()\n  })\n\n  const icon = makeHtml(`<layer-icon class=\"${style.layerIcon}\"></layer-icon>`)\n  icon.layer = layer\n  icon.name = name\n  imageIcons.appendChild(icon)\n\n  layerEntry.addEventListener('click', event => {\n    event.preventDefault()\n    context.service.send({ type: 'SELECT_LAYER', data: name })\n  })\n\n  return layerEntry\n}\n\nfunction createLayerInterface(context) {\n  const name = context.layers.lastAddedData.name\n  const layer = context.layers.actorContext.get(name)\n\n  const layerEntry = createLayerEntry(context, name, layer)\n  context.layers.layersUIGroup.appendChild(layerEntry)\n\n  context.layers.uiLayers.set(name, layerEntry)\n}\n\nexport default createLayerInterface\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/createLayersInterface.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport { makeHtml } from '../utils'\n\nfunction createLayersInterface(context) {\n  const layersUIGroup = makeHtml(`\n    <div class=\"${style.uiGroup} ${style.uiRow} ${style.layers}\"></div>\n  `)\n  context.layers.layersUIGroup = layersUIGroup\n  context.uiGroups.set('layers', layersUIGroup)\n  context.uiContainer.appendChild(layersUIGroup)\n\n  // layer name -> layerEntry map\n  context.layers.uiLayers = new Map()\n\n  const compareContainer = document.createElement('div')\n  compareContainer.setAttribute('class', style.uiGroup)\n  context.uiContainer.appendChild(compareContainer)\n  context.layers.compareContainer = compareContainer\n}\n\nexport default createLayersInterface\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/dataUpdateIndicator.js",
    "content": "export function startDataUpdate({ actorContext: { spinner } }) {\n  spinner.style.visibility = 'visible'\n}\n\nexport function finishDataUpdate({ actorContext: { spinner } }) {\n  spinner.style.visibility = 'hidden'\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/extensionToImageIo.js",
    "content": "// from itk-wasm/packages/image-io/typescript/src/extension-to-image-io.ts\n// Commented out formats failed roundtrip test\nconst extensionToImageIo = new Map([\n  // ['bmp', 'bmp'],\n\n  // ['dcm', 'gdcm'],\n\n  // ['gipl', 'gipl'],\n  // ['gipl.gz', 'gipl'],\n\n  ['hdf5', 'hdf5'],\n\n  // ['jpg', 'jpeg'],\n  // ['jpeg', 'jpeg'],\n\n  // ['iwi', 'wasm'],\n  ['iwi.cbor', 'wasm'],\n  // ['iwi.cbor.zst', 'wasmZstd'],\n\n  // ['lsm', 'lsm'],\n\n  // ['mnc', 'mnc'],\n  // ['mnc.gz', 'mnc'],\n  // ['mnc2', 'mnc'],\n\n  // ['mgh', 'mgh'],\n  // ['mgz', 'mgh'],\n  // ['mgh.gz', 'mgh'],\n\n  ['mha', 'meta'],\n  // ['mhd', 'meta'],\n\n  // ['mrc', 'mrc'],\n\n  // ['nia', 'nifti'],\n  ['nii', 'nifti'],\n  ['nii.gz', 'nifti'],\n  // ['hdr', 'nifti'],\n\n  ['nrrd', 'nrrd'],\n  // ['nhdr', 'nrrd'],\n\n  // ['png', 'png'],\n\n  // ['pic', 'bioRad'],\n\n  ['tif', 'tiff'],\n  // ['tiff', 'tiff'],\n\n  ['vtk', 'vtk'],\n\n  // ['isq', 'scanco'],\n  // ['aim', 'scanco'],\n\n  // ['fdf', 'fdf'],\n])\n\nexport const extensions = Array.from(extensionToImageIo.keys())\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/layerIcon.ts",
    "content": "import { LitElement, html, css } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { compareArrays, connectState } from 'xstate-lit/dist/select-state.js'\nimport {\n  imageIconDataUri,\n  labelsIconDataUri,\n  toggleIconDataUri,\n} from '@itk-viewer/icons'\nimport { viewerContext } from '../context'\n\nimport './layerSettings.js'\n\n@customElement('layer-icon')\nclass LayerIcon extends LitElement {\n  @property()\n  layer: { type: string } = { type: 'image' }\n\n  @property()\n  name: string = ''\n\n  @state()\n  private settingsOpen = true\n\n  otherImages = connectState(\n    viewerContext,\n    this,\n    (state: any) =>\n      [...state.context.layers.actorContext.keys()].filter(\n        key =>\n          key !== this.name &&\n          state.context.images.actorContext.get(this.name)?.labelImage?.name !==\n            key\n      ),\n    compareArrays\n  )\n\n  selectedName = connectState(\n    viewerContext,\n    this,\n    (state: any) => state.context.images.selectedName\n  )\n\n  getIcon() {\n    if (this.layer.type === 'image') {\n      if (\n        this.name === this.selectedName.value &&\n        this.otherImages.value &&\n        this.otherImages.value.length > 0\n      )\n        return { icon: toggleIconDataUri, alt: 'settings' }\n      return { icon: imageIconDataUri, alt: 'image' }\n    }\n    if (this.layer.type === 'labelImage')\n      return { icon: labelsIconDataUri, alt: 'labels' }\n    throw new Error(`Unsupported layer type: ${this.layer.type}`)\n  }\n\n  render() {\n    const { icon, alt } = this.getIcon()\n    const settingsPossible = alt === 'settings'\n    return html`\n      <div>\n        <layer-settings\n          .name=${this.name}\n          .otherImages=${this.otherImages.value}\n          .enable=${settingsPossible}\n        >\n          <img src=\"${icon}\" alt=\"${alt}\" class=\"icon\" />\n        </layer-settings>\n      </div>\n    `\n  }\n\n  static styles = css`\n    .icon {\n      height: 1.2em;\n      width: 1.2em;\n      padding-top: 2px;\n      padding-bottom: 2px;\n      padding-left: 8px;\n      padding-right: 6px;\n    }\n  `\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/layerSettings.ts",
    "content": "import { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { ref, createRef, Ref } from 'lit/directives/ref.js'\nimport { map } from 'lit/directives/map.js'\nimport { ContextConsumer } from '@lit-labs/context'\nimport '@material/web/menu/menu.js'\nimport { MdMenu } from '@material/web/menu/menu.js'\nimport '@material/web/menu/menu-item.js'\nimport { makeHtml } from '../utils'\nimport style from '../ItkVtkViewer.module.css'\nimport { viewerContext } from '../context'\n\n@customElement('layer-settings')\nclass LayerSettings extends LitElement {\n  @property()\n  name: string = ''\n\n  @property()\n  otherImages: Array<string> = []\n\n  @property()\n  enable: boolean = true\n\n  menuRef: Ref<MdMenu> = createRef()\n  anchorRef: Ref<HTMLElement> = createRef()\n  // avoid overflow: hidden on parents clipping menu\n  floatingAnchor = makeHtml(`<div class=\"${style.floater}\"></div>`)\n\n  stateService = new ContextConsumer(this, viewerContext, undefined, true)\n\n  connectedCallback() {\n    super.connectedCallback()\n    document.body.appendChild(this.floatingAnchor)\n  }\n\n  disconnectedCallback() {\n    super.disconnectedCallback()\n    document.body.removeChild(this.floatingAnchor)\n  }\n\n  showMenu() {\n    if (!this.enable) return\n    const { top = 0, left = 0 } =\n      this.anchorRef.value?.getBoundingClientRect() ?? {}\n    this.floatingAnchor.style.top = `${top}px`\n    this.floatingAnchor.style.left = `${left}px`\n    if (this.menuRef.value) {\n      this.floatingAnchor.appendChild(this.menuRef.value)\n      this.menuRef.value.anchorElement = this.floatingAnchor\n      this.menuRef.value.show()\n    }\n  }\n\n  compareWith(name: string, method: string) {\n    this.stateService.value?.service.send({\n      type: 'COMPARE_IMAGES',\n      data: {\n        name: this.name,\n        fixedImageName: name,\n        options: { method },\n      },\n    })\n  }\n\n  stopComparing() {\n    this.stateService.value?.service.send({\n      type: 'COMPARE_IMAGES',\n      data: {\n        name: this.name,\n        options: { method: 'disabled' },\n      },\n    })\n  }\n\n  render() {\n    return html`\n      <div\n        @click=${() => {\n          this.showMenu()\n          this.render()\n        }}\n        class=${this.enable ? 'clickable' : ''}\n      >\n        <slot></slot>\n        <div ${ref(this.anchorRef)} style=\"position:relative; z-index: 4000;\">\n          <md-menu ${ref(this.menuRef)} style=\"min-width: 280px;\">\n            ${map(\n              this.otherImages,\n              name =>\n                html`\n                  <md-menu-item\n                    @click=${() => this.compareWith(name, 'checkerboard')}\n                  >\n                    <div slot=\"headline\">\n                      \"Checkerboard compare with ${name}\"\n                    </div>\n                  </md-menu-item>\n                  <md-menu-item\n                    @click=${() => this.compareWith(name, 'green-magenta')}\n                  >\n                    <div slot=\"headline\">\n                      \"Green-Magenta compare with ${name}\"\n                    </div>\n                  </md-menu-item>\n                  <md-menu-item\n                    @click=${() => this.compareWith(name, 'cyan-red')}\n                  >\n                    <div slot=\"headline\">\n                      \"Cyan-Red compare with ${name}\"\n                    </div>\n                  </md-menu-item>\n                  <md-menu-item\n                    @click=${() => this.compareWith(name, 'cyan-magenta')}\n                  >\n                    <div slot=\"headline\">\n                      \"Cyan-Magenta compare with ${name}\"\n                    </div>\n                  </md-menu-item>\n                  <md-menu-item @click=${() => this.compareWith(name, 'blend')}>\n                    <div slot=\"headline\">\n                      \"Blend compare with ${name}\"\n                    </div>\n                  </md-menu-item>\n                `\n            )}\n            <md-menu-item @click=${this.stopComparing}>\n              <div slot=\"headline\">\n                \"Stop comparing\"\n              </div>\n            </md-menu-item>\n          </md-menu>\n        </div>\n      </div>\n    `\n  }\n\n  static styles = css`\n    .clickable {\n      cursor: pointer;\n    }\n  `\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/layersUIMachineOptions.js",
    "content": "import createLayersInterface from './createLayersInterface'\nimport createLayerInterface from './createLayerInterface'\nimport toggleLayerVisibility from './toggleLayerVisibility'\nimport selectLayer from './selectLayer'\nimport { startDataUpdate, finishDataUpdate } from './dataUpdateIndicator'\nimport { compareUI } from './compareUI'\n\nconst layersUIMachineOptions = {\n  layerUIActor: {\n    actions: {\n      createLayerInterface,\n      selectLayer,\n      toggleLayerVisibility,\n      startDataUpdate,\n      finishDataUpdate,\n    },\n  },\n\n  actions: {\n    createLayersInterface,\n  },\n\n  services: {\n    compareUI,\n  },\n}\n\nexport default layersUIMachineOptions\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/selectLayer.js",
    "content": "import applyGroupVisibility from '../applyGroupVisibility'\n\nconst selectedBorderWidth = '3px'\nconst unselectedBorderWidth = '2px'\n\nfunction selectLayer(context, event) {\n  const name = event.data\n  const actorContext = context.layers.actorContext.get(name)\n\n  const layerEntry = context.layers.uiLayers.get(name)\n  layerEntry.style.borderWidth = selectedBorderWidth\n\n  const type = actorContext.type\n  context.layers.actorContext.forEach((ac, layerName) => {\n    if (layerName !== name && ac.type === type) {\n      const entry = context.layers.uiLayers.get(layerName)\n      entry.style.borderWidth = unselectedBorderWidth\n    }\n  })\n\n  if (!actorContext.visible) {\n    context.service.send({\n      type: 'TOGGLE_LAYER_VISIBILITY',\n      data: name,\n    })\n  }\n\n  if (!context.uiCollapsed) {\n    const { imageActorContext } = actorContext\n    switch (type) {\n      case 'image':\n        applyGroupVisibility(context, ['images'], true)\n        if (imageActorContext.labelImageName) {\n          applyGroupVisibility(\n            context,\n            ['labelImages', 'labelImageWeights'],\n            true\n          )\n        }\n        break\n      case 'labelImage':\n        if (actorContext.imageName) {\n          applyGroupVisibility(context, ['images'], true)\n        }\n        applyGroupVisibility(\n          context,\n          ['labelImages', 'labelImageWeights'],\n          true\n        )\n        break\n      default:\n        console.error(`Unsupported layer type: ${type}`)\n    }\n  }\n}\n\nexport default selectLayer\n"
  },
  {
    "path": "src/UI/reference-ui/src/Layers/toggleLayerVisibility.js",
    "content": "import applyGroupVisibility from '../applyGroupVisibility'\n\nfunction toggleLayerVisibility(context, event) {\n  const layers = context.layers\n  const name = event.data\n  const actorContext = layers.actorContext.get(name)\n  const visible = actorContext.visible\n\n  const layerEntry = context.layers.uiLayers.get(name)\n  const visibleButton = layerEntry.children[0]\n  const invisibleButton = layerEntry.children[1]\n  if (visible) {\n    visibleButton.style.display = 'flex'\n    invisibleButton.style.display = 'none'\n  } else {\n    visibleButton.style.display = 'none'\n    invisibleButton.style.display = 'flex'\n    switch (actorContext.type) {\n      case 'image':\n        applyGroupVisibility(context, ['images'], false)\n        break\n      case 'labelImage':\n        applyGroupVisibility(\n          context,\n          ['labelImages', 'labelImageWeights'],\n          false\n        )\n        break\n      default:\n        console.error(`Unsupported layer type: ${type}`)\n    }\n  }\n}\n\nexport default toggleLayerVisibility\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/applyMainContrastSensitiveStyle.js",
    "content": "import applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nfunction applyMainContrastSensitiveStyle(context) {\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    context.main.collapseUIButton\n  )\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    context.main.screenshotButton\n  )\n  if (context.main.fullscreenButton) {\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      context.main.fullscreenButton\n    )\n  }\n  if (context.main.rotateButtonLabel) {\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      context.main.rotateButtonLabel\n    )\n  }\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    context.main.annotationsButtonLabel\n  )\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    context.main.axesButtonLabel\n  )\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    context.main.cropButtonLabel\n  )\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    context.main.resetCropButtonLabel\n  )\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    context.main.bgColorButtonLabel\n  )\n  if (!context.use2D) {\n    applyContrastSensitiveStyleToElement(\n      context,\n      'tooltipButton',\n      context.main.xPlaneButtonLabel\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'tooltipButton',\n      context.main.yPlaneButtonLabel\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'tooltipButton',\n      context.main.zPlaneButtonLabel\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'tooltipButton',\n      context.main.volumeButtonLabel\n    )\n    applyContrastSensitiveStyleToElement(\n      context,\n      'tooltipButton',\n      context.main.viewPlanesButtonLabel\n    )\n  }\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    context.main.resetCameraButtonLabel\n  )\n}\n\nexport default applyMainContrastSensitiveStyle\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/applySlicingPlanes.js",
    "content": "function applySlicingPlanes(context, event) {\n  const slicingPlanes = event.data\n  const main = context.main\n\n  if (context.use2D) {\n    if (main.viewPlanesButton) {\n      main.viewPlanesButton.style.display = 'none'\n    }\n    return\n  }\n\n  if (\n    !slicingPlanes.x.visibile &&\n    !slicingPlanes.y.visible &&\n    !slicingPlanes.z.visible\n  ) {\n    if (main.viewPlanesButtonInput) {\n      main.viewPlanesButtonInput.checked = false\n    }\n  } else {\n    if (main.viewPlanesButtonInput) {\n      main.viewPlanesButtonInput.checked = true\n    }\n  }\n\n  if (!main.planeUIGroup) {\n    return\n  }\n\n  main.xSliceElement.min = slicingPlanes.x.min\n  main.xSliceElement.max = slicingPlanes.x.max\n  main.xSliceElement.step = slicingPlanes.x.step\n\n  main.ySliceElement.min = slicingPlanes.y.min\n  main.ySliceElement.max = slicingPlanes.y.max\n  main.ySliceElement.step = slicingPlanes.y.step\n\n  main.zSliceElement.min = slicingPlanes.z.min\n  main.zSliceElement.max = slicingPlanes.z.max\n  main.zSliceElement.step = slicingPlanes.z.step\n\n  if (main.viewMode === 'Volume') {\n    main.xPlaneVisibleButton.style.display = slicingPlanes.x.visible\n      ? 'flex'\n      : 'none'\n    main.xPlaneInvisibleButton.style.display = slicingPlanes.x.visible\n      ? 'none'\n      : 'flex'\n    main.yPlaneVisibleButton.style.display = slicingPlanes.y.visible\n      ? 'flex'\n      : 'none'\n    main.yPlaneInvisibleButton.style.display = slicingPlanes.y.visible\n      ? 'none'\n      : 'flex'\n    main.zPlaneVisibleButton.style.display = slicingPlanes.z.visible\n      ? 'flex'\n      : 'none'\n    main.zPlaneInvisibleButton.style.display = slicingPlanes.z.visible\n      ? 'none'\n      : 'flex'\n  }\n\n  main.xPlanePauseButton.style.display = slicingPlanes.x.scroll\n    ? 'flex'\n    : 'none'\n  main.xPlanePlayButton.style.display = slicingPlanes.x.scroll ? 'none' : 'flex'\n  main.yPlanePauseButton.style.display = slicingPlanes.y.scroll\n    ? 'flex'\n    : 'none'\n  main.yPlanePlayButton.style.display = slicingPlanes.y.scroll ? 'none' : 'flex'\n  main.zPlanePauseButton.style.display = slicingPlanes.z.scroll\n    ? 'flex'\n    : 'none'\n  main.zPlanePlayButton.style.display = slicingPlanes.z.scroll ? 'none' : 'flex'\n}\n\nexport default applySlicingPlanes\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/applyXSlice.js",
    "content": "function applyXSlice(context, event) {\n  const position = event.data\n\n  const xPlaneLabel = context.main.xPlaneLabel\n  if (!xPlaneLabel) {\n    return\n  }\n\n  const numberOfValueChars = 6\n  const valueString = String(position).substring(0, numberOfValueChars)\n  const padLength =\n    valueString.length < numberOfValueChars\n      ? numberOfValueChars - valueString.length\n      : 0\n  const pad = '&nbsp;'.repeat(padLength)\n  xPlaneLabel.innerHTML = `X: ${pad}${valueString}`\n  context.main.xSliceElement.value = position\n}\n\nexport default applyXSlice\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/applyYSlice.js",
    "content": "function applyYSlice(context, event) {\n  const position = event.data\n\n  const yPlaneLabel = context.main.yPlaneLabel\n  if (!yPlaneLabel) {\n    return\n  }\n\n  const numberOfValueChars = 6\n  const valueString = String(position).substring(0, numberOfValueChars)\n  const padLength =\n    valueString.length < numberOfValueChars\n      ? numberOfValueChars - valueString.length\n      : 0\n  const pad = '&nbsp;'.repeat(padLength)\n  yPlaneLabel.innerHTML = `Y: ${pad}${valueString}`\n  context.main.ySliceElement.value = position\n}\n\nexport default applyYSlice\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/applyZSlice.js",
    "content": "function applyZSlice(context, event) {\n  const position = event.data\n\n  const zPlaneLabel = context.main.zPlaneLabel\n  if (!zPlaneLabel) {\n    return\n  }\n\n  const numberOfValueChars = 6\n  const valueString = String(position).substring(0, numberOfValueChars)\n  const padLength =\n    valueString.length < numberOfValueChars\n      ? numberOfValueChars - valueString.length\n      : 0\n  const pad = '&nbsp;'.repeat(padLength)\n  zPlaneLabel.innerHTML = `Z: ${pad}${valueString}`\n  context.main.zSliceElement.value = position\n}\n\nexport default applyZSlice\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createAnnotationsButton.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport { annotationsIconDataUri } from '@itk-viewer/icons'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\nimport toggleAnnotations from './toggleAnnotations'\n\nfunction createAnnotationsButton(context, mainUIRow) {\n  const annotationsButton = document.createElement('div')\n  annotationsButton.innerHTML = `<input id=\"${context.id}-toggleAnnotationsButton\" type=\"checkbox\" class=\"${style.toggleInput}\" checked><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Annotations\" class=\"${style.annotationsButton} ${style.toggleButton}\" for=\"${context.id}-toggleAnnotationsButton\"><img src=\"${annotationsIconDataUri}\" alt=\"annotations\"/></label>`\n  const annotationsButtonInput = annotationsButton.children[0]\n  const annotationsButtonLabel = annotationsButton.children[1]\n  context.main.annotationsButtonLabel = annotationsButtonLabel\n  context.main.annotationsButtonInput = annotationsButtonInput\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    annotationsButtonLabel\n  )\n\n  toggleAnnotations(context)\n\n  annotationsButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('TOGGLE_ANNOTATIONS')\n  })\n\n  mainUIRow.appendChild(annotationsButton)\n}\n\nexport default createAnnotationsButton\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createAxesButton.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport { axesIconDataUri } from '@itk-viewer/icons'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\nimport toggleAxes from './toggleAxes'\n\nfunction createAxesButton(context, mainUIRow) {\n  const axesButton = document.createElement('div')\n  axesButton.innerHTML = `<input id=\"${context.id}-toggleAxesButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-axes itk-vtk-tooltip-content=\"Axes\" class=\"${style.axesButton} ${style.toggleButton}\" for=\"${context.id}-toggleAxesButton\"><img src=\"${axesIconDataUri}\" alt=\"axes\"/></label>`\n  const axesButtonInput = axesButton.children[0]\n  const axesButtonLabel = axesButton.children[1]\n  context.main.axesButtonLabel = axesButtonLabel\n  context.main.axesButtonInput = axesButtonInput\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    axesButtonLabel\n  )\n\n  toggleAxes(context)\n\n  axesButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('TOGGLE_AXES')\n  })\n\n  mainUIRow.appendChild(axesButton)\n}\n\nexport default createAxesButton\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createBackgroundColorButton.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport { selectColorIconDataUri } from '@itk-viewer/icons'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nfunction createBackgroundColorButton(context, mainUIRow) {\n  const viewerDOMId = context.id\n  const bgColorButton = document.createElement('div')\n  bgColorButton.innerHTML = `<input id=\"${viewerDOMId}-bgColorButton\" type=\"checkbox\" class=\"${style.toggleInput}\" checked><label itk-vtk-tooltip itk-vtk-tooltip-left itk-vtk-tooltip-content=\"Toggle Background Color\" class=\"${style.bgColorButton} ${style.toggleButton}\" for=\"${viewerDOMId}-bgColorButton\"><img src=\"${selectColorIconDataUri}\" alt=\"select color\" /></label>`\n  const bgColorButtonInput = bgColorButton.children[0]\n  const bgColorButtonLabel = bgColorButton.children[1]\n  context.main.bgColorButtonLabel = bgColorButtonLabel\n  context.main.bgColorButtonInput = bgColorButtonInput\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    bgColorButtonLabel\n  )\n\n  bgColorButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('TOGGLE_BACKGROUND_COLOR')\n  })\n  bgColorButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('TOGGLE_BACKGROUND_COLOR')\n  })\n  mainUIRow.appendChild(bgColorButton)\n}\n\nexport default createBackgroundColorButton\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createCroppingButtons.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { cropIconDataUri, resetCropIconDataUri } from '@itk-viewer/icons'\nimport toggleCroppingPlanes from './toggleCroppingPlanes'\n\nfunction createCroppingButtons(context, mainUIRow) {\n  const viewerDOMId = context.id\n\n  const cropButton = document.createElement('div')\n  cropButton.innerHTML = `<input id=\"${viewerDOMId}-toggleCroppingPlanesButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Cropping planes [w]\" class=\"${style.cropButton} ${style.toggleButton}\" for=\"${viewerDOMId}-toggleCroppingPlanesButton\"><img src=\"${cropIconDataUri}\" alt=\"crop\"/></label>`\n  const cropButtonInput = cropButton.children[0]\n  const cropButtonLabel = cropButton.children[1]\n\n  context.main.cropButtonLabel = cropButtonLabel\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    cropButtonLabel\n  )\n\n  context.main.cropButtonInput = cropButtonInput\n  toggleCroppingPlanes(context)\n\n  cropButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('TOGGLE_CROPPING_PLANES')\n  })\n  mainUIRow.appendChild(cropButton)\n\n  const resetCropButton = document.createElement('div')\n  resetCropButton.innerHTML = `<input id=\"${viewerDOMId}-resetCroppingPlanesButton\" type=\"checkbox\" class=\"${style.toggleInput}\" checked><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Reset cropping planes [e]\" class=\"${style.resetCropButton} ${style.toggleButton}\" for=\"${viewerDOMId}-resetCroppingPlanesButton\"><img src=\"${resetCropIconDataUri}\" alt=\"reset crop\"/></label>`\n  const resetCropButtonLabel = resetCropButton.children[1]\n\n  context.main.resetCropButtonLabel = resetCropButtonLabel\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    resetCropButtonLabel\n  )\n\n  resetCropButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('RESET_CROPPING_PLANES')\n    context.service.send('CROPPING_PLANES_CHANGED_BY_USER')\n  })\n  resetCropButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('RESET_CROPPING_PLANES')\n    context.service.send('CROPPING_PLANES_CHANGED_BY_USER')\n  })\n  mainUIRow.appendChild(resetCropButton)\n}\n\nexport default createCroppingButtons\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createFullscreenButton.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport { fullscreenIconDataUri } from '@itk-viewer/icons'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\nimport fullscreenMethods from './fullscreenMethods'\n\nfunction createFullscreenButton(context, mainUIRow) {\n  if (fullscreenMethods) {\n    const fullscreenButton = document.createElement('div')\n    fullscreenButton.innerHTML = `<input id=\"${context.id}-toggleFullscreenButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Fullscreen [f]\" class=\"${style.fullscreenButton} ${style.toggleButton}\" for=\"${context.id}-toggleFullscreenButton\"><img src=\"${fullscreenIconDataUri}\" alt=\"fullscreen\"/></label>`\n    const fullscreenButtonInput = fullscreenButton.children[0]\n    const fullscreenButtonLabel = fullscreenButton.children[1]\n    applyContrastSensitiveStyleToElement(\n      context,\n      'invertibleButton',\n      fullscreenButton\n    )\n\n    const container = context.rootContainer\n    const oldWidth = container.style.width\n    const oldHeight = container.style.height\n    context.main.rootContainerOldWidth = container.style.width\n    context.main.rootContainerOldHeight = container.style.height\n\n    fullscreenButton.addEventListener('change', event => {\n      event.preventDefault()\n      event.stopPropagation()\n      context.service.send('TOGGLE_FULLSCREEN')\n    })\n\n    document.addEventListener(fullscreenMethods[2], event => {\n      if (!document[fullscreenMethods[3]]) {\n        context.service.send('DISABLE_FULLSCREEN')\n      }\n    })\n\n    context.main.fullscreenButton = fullscreenButton\n    mainUIRow.appendChild(fullscreenButton)\n  }\n}\n\nexport default createFullscreenButton\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createMainInterface.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport createScreenshotButton from './createScreenshotButton'\nimport createFullscreenButton from './createFullscreenButton'\nimport createRotateButton from './createRotateButton'\nimport createAnnotationsButton from './createAnnotationsButton'\nimport createAxesButton from './createAxesButton'\nimport createViewPlanesToggle from './createViewPlanesToggle'\nimport createPlaneSliders from './createPlaneSliders'\nimport createBackgroundColorButton from './createBackgroundColorButton'\nimport createCroppingButtons from './createCroppingButtons'\nimport createViewModeButtons from './createViewModeButtons'\nimport createResetCameraButton from './createResetCameraButton'\n\nfunction createMainInterface(context) {\n  const mainUIGroup = document.createElement('div')\n  mainUIGroup.setAttribute('class', style.uiGroup)\n  context.uiGroups.set('main', mainUIGroup)\n\n  const mainUIRow1 = document.createElement('div')\n  mainUIRow1.setAttribute('class', style.mainUIRow)\n  mainUIGroup.appendChild(mainUIRow1)\n\n  createScreenshotButton(context, mainUIRow1)\n  createFullscreenButton(context, mainUIRow1)\n  if (!context.use2D) {\n    createRotateButton(context, mainUIRow1)\n  }\n  createAnnotationsButton(context, mainUIRow1)\n  createAxesButton(context, mainUIRow1)\n  createViewPlanesToggle(context, mainUIRow1)\n  createPlaneSliders(context)\n\n  createBackgroundColorButton(context, mainUIRow1)\n  const mainUIRow2 = document.createElement('div')\n  mainUIRow2.setAttribute('class', style.mainUIRow)\n\n  if (context.use2D) {\n    createViewModeButtons(context, mainUIRow2)\n    createCroppingButtons(context, mainUIRow1)\n    createResetCameraButton(context, mainUIRow1)\n  } else {\n    createViewModeButtons(context, mainUIRow2)\n    createCroppingButtons(context, mainUIRow2)\n    createResetCameraButton(context, mainUIRow2)\n    mainUIGroup.appendChild(mainUIRow2)\n  }\n\n  context.uiContainer.appendChild(mainUIGroup)\n}\n\nexport default createMainInterface\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createPlaneSliders.js",
    "content": "import macro from '@kitware/vtk.js/macro'\nimport style from '../ItkVtkViewer.module.css'\n\nimport {\n  visibleIconDataUri,\n  invisibleIconDataUri,\n  pauseIconDataUri,\n  playIconDataUri,\n} from '@itk-viewer/icons'\n\nfunction createPlaneSliders(context) {\n  const planeUIGroup = document.createElement('div')\n  planeUIGroup.setAttribute('class', style.uiGroup)\n\n  const numberOfValueChars = 6\n  const viewerDOMId = context.id\n\n  const xPlaneRow = document.createElement('div')\n  xPlaneRow.setAttribute('class', style.planeUIRow)\n  xPlaneRow.className += ` ${viewerDOMId}-x-plane-row`\n  context.main.xPlaneRow = xPlaneRow\n\n  const xPlaneVisibleButton = document.createElement('div')\n  xPlaneVisibleButton.innerHTML = `<input id=\"${context.id}-xPlaneVisibleButton\" type=\"checkbox\" checked class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"X plane visibility\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-xPlaneVisibleButton\"><img src=\"${visibleIconDataUri}\" alt=\"visible\" /></label>`\n  const xPlaneVisibleButtonInput = xPlaneVisibleButton.children[0]\n  const xPlaneVisibleLabel = xPlaneVisibleButton.children[1]\n  xPlaneRow.appendChild(xPlaneVisibleButton)\n  context.main.xPlaneVisibleButton = xPlaneVisibleButton\n\n  const xPlaneInvisibleButton = document.createElement('div')\n  xPlaneVisibleButton.setAttribute('class', style.visibleButton)\n  xPlaneInvisibleButton.setAttribute('class', style.visibleButton)\n  xPlaneInvisibleButton.innerHTML = `<input id=\"${context.id}-invisibleButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"X plane visibility\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-xPlaneInvisibleButton\"><img src=\"${invisibleIconDataUri}\" alt=\"invisible\" /></label>`\n  const xPlaneInvisibleButtonInput = xPlaneInvisibleButton.children[0]\n  const xPlaneInvisibleLabel = xPlaneInvisibleButton.children[1]\n  xPlaneRow.appendChild(xPlaneInvisibleButton)\n  context.main.xPlaneInvisibleButton = xPlaneInvisibleButton\n\n  if (context.main.viewMode === 'Volume') {\n    if (context.main.slicingPlanes.x.visible) {\n      xPlaneVisibleButton.style.display = 'flex'\n      xPlaneInvisibleButton.style.display = 'none'\n    } else {\n      xPlaneVisibleButton.style.display = 'none'\n      xPlaneInvisibleButton.style.display = 'flex'\n    }\n  } else {\n    xPlaneVisibleButton.style.display = 'none'\n    xPlaneInvisibleButton.style.display = 'none'\n  }\n\n  xPlaneVisibleButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.x.visible = false\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    xPlaneVisibleButton.checked = true\n  })\n  xPlaneInvisibleButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.x.visible = true\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    xPlaneInvisibleButton.checked = false\n  })\n\n  const xPlanePauseButton = document.createElement('div')\n  xPlanePauseButton.innerHTML = `<input id=\"${context.id}-xPlanePauseButton\" type=\"checkbox\" checked class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"X plane pause scroll\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-xPlanePauseButton\"><img src=\"${pauseIconDataUri}\" alt=\"pause\" /></label>`\n  const xPlanePauseButtonInput = xPlanePauseButton.children[0]\n  const xPlanePauseLabel = xPlanePauseButton.children[1]\n  xPlaneRow.appendChild(xPlanePauseButton)\n  context.main.xPlanePauseButton = xPlanePauseButton\n\n  const xPlanePlayButton = document.createElement('div')\n  xPlanePauseButton.setAttribute('class', style.visibleButton)\n  xPlanePlayButton.setAttribute('class', style.visibleButton)\n  xPlanePlayButton.innerHTML = `<input id=\"${context.id}-xPlanePlayButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"X plane play scroll\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-xPlanePlayButton\"><img src=\"${playIconDataUri}\" alt=\"play\"/></label>`\n  const xPlanePlayButtonInput = xPlanePlayButton.children[0]\n  const xPlanePlayLabel = xPlanePlayButton.children[1]\n  xPlaneRow.appendChild(xPlanePlayButton)\n  context.main.xPlanePlayButton = xPlanePlayButton\n\n  if (context.main.slicingPlanes.x.scroll) {\n    xPlanePauseButton.style.display = 'flex'\n    xPlanePlayButton.style.display = 'none'\n  } else {\n    xPlanePauseButton.style.display = 'none'\n    xPlanePlayButton.style.display = 'flex'\n  }\n\n  xPlanePauseButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.x.scroll = false\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    xPlanePauseButton.checked = true\n  })\n  xPlanePlayButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.x.scroll = true\n    slicingPlanes.x.visible = true\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    xPlanePlayButton.checked = false\n  })\n\n  const xSliderEntry = document.createElement('div')\n  xSliderEntry.setAttribute('class', style.sliderEntry)\n  xSliderEntry.innerHTML = `\n    <label id=\"${viewerDOMId}-xSliceLabel\" class=\"${style.xPlaneLabel}\">X:</label><input type=\"range\" min=\"0.0\" max=\"1.0\" value=\"0.5\" step=\"0.1\"\n      id=\"${viewerDOMId}-xSlice\" class=\"${style.slider}\" />`\n  const xPlaneLabel = xSliderEntry.querySelector(`#${viewerDOMId}-xSliceLabel`)\n  context.main.xPlaneLabel = xPlaneLabel\n\n  const xSliceElement = xSliderEntry.querySelector(`#${viewerDOMId}-xSlice`)\n  xSliceElement.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'X_SLICE_CHANGED',\n      data: Number(xSliceElement.value),\n    })\n  })\n  context.main.xSliceElement = xSliceElement\n\n  xPlaneRow.appendChild(xSliderEntry)\n  planeUIGroup.appendChild(xPlaneRow)\n\n  const yPlaneRow = document.createElement('div')\n  yPlaneRow.setAttribute('class', style.planeUIRow)\n  yPlaneRow.className += ` ${viewerDOMId}-y-plane-row`\n  context.main.yPlaneRow = yPlaneRow\n\n  const yPlaneVisibleButton = document.createElement('div')\n  yPlaneVisibleButton.setAttribute('class', style.visibleButton)\n  yPlaneVisibleButton.innerHTML = `<input id=\"${context.id}-yPlaneVisibleButton\" type=\"checkbox\" checked class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Y plane visibility\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-yPlaneVisibleButton\"><img src=\"${visibleIconDataUri}\" alt=\"visible\"/></label>`\n  const yPlaneVisibleButtonInput = yPlaneVisibleButton.children[0]\n  const yPlaneVisibleLabel = yPlaneVisibleButton.children[1]\n  yPlaneRow.appendChild(yPlaneVisibleButton)\n  context.main.yPlaneVisibleButton = yPlaneVisibleButton\n\n  const yPlaneInvisibleButton = document.createElement('div')\n  yPlaneInvisibleButton.setAttribute('class', style.visibleButton)\n  yPlaneInvisibleButton.innerHTML = `<input id=\"${context.id}-invisibleButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Y plane visibility\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-yPlaneInvisibleButton\"><img src=\"${invisibleIconDataUri}\" alt=\"invisible\" /></label>`\n  const yPlaneInvisibleButtonInput = yPlaneInvisibleButton.children[0]\n  const yPlaneInvisibleLabel = yPlaneInvisibleButton.children[1]\n  yPlaneRow.appendChild(yPlaneInvisibleButton)\n  context.main.yPlaneInvisibleButton = yPlaneInvisibleButton\n\n  if (context.main.viewMode === 'Volume') {\n    if (context.main.slicingPlanes.y.visible) {\n      yPlaneVisibleButton.style.display = 'flex'\n      yPlaneInvisibleButton.style.display = 'none'\n    } else {\n      yPlaneVisibleButton.style.display = 'none'\n      yPlaneInvisibleButton.style.display = 'flex'\n    }\n  } else {\n    yPlaneVisibleButton.style.display = 'none'\n    yPlaneInvisibleButton.style.display = 'none'\n  }\n\n  yPlaneVisibleButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.y.visible = false\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    yPlaneVisibleButton.checked = true\n  })\n  yPlaneInvisibleButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.y.visible = true\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    yPlaneInvisibleButton.checked = false\n  })\n\n  const yPlanePauseButton = document.createElement('div')\n  yPlanePauseButton.innerHTML = `<input id=\"${context.id}-yPlanePauseButton\" type=\"checkbox\" checked class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Y plane pause scroll\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-yPlanePauseButton\"><img src=\"${pauseIconDataUri}\" alt=\"pause\" /></label>`\n  const yPlanePauseButtonInput = yPlanePauseButton.children[0]\n  const yPlanePauseLabel = yPlanePauseButton.children[1]\n  yPlaneRow.appendChild(yPlanePauseButton)\n  context.main.yPlanePauseButton = yPlanePauseButton\n\n  const yPlanePlayButton = document.createElement('div')\n  yPlanePauseButton.setAttribute('class', style.visibleButton)\n  yPlanePlayButton.setAttribute('class', style.visibleButton)\n  yPlanePlayButton.innerHTML = `<input id=\"${context.id}-yPlanePlayButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Y plane play scroll\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-yPlanePlayButton\"><img src=\"${playIconDataUri}\" alt=\"play\"/></label>`\n  const yPlanePlayButtonInput = yPlanePlayButton.children[0]\n  const yPlanePlayLabel = yPlanePlayButton.children[1]\n  yPlaneRow.appendChild(yPlanePlayButton)\n  context.main.yPlanePlayButton = yPlanePlayButton\n\n  if (context.main.slicingPlanes.y.scroll) {\n    yPlanePauseButton.style.display = 'flex'\n    yPlanePlayButton.style.display = 'none'\n  } else {\n    yPlanePauseButton.style.display = 'none'\n    yPlanePlayButton.style.display = 'flex'\n  }\n\n  yPlanePauseButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.y.scroll = false\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    yPlanePauseButton.checked = true\n  })\n  yPlanePlayButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.y.scroll = true\n    slicingPlanes.y.visible = true\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    yPlanePlayButton.checked = false\n  })\n\n  const ySliderEntry = document.createElement('div')\n  ySliderEntry.setAttribute('class', style.sliderEntry)\n  ySliderEntry.innerHTML = `\n    <label id=\"${viewerDOMId}-ySliceLabel\" class=\"${style.yPlaneLabel}\">Y:</label><input type=\"range\" min=\"0.0\" max=\"1.0\" value=\"0.5\" step=\"0.1\"\n      id=\"${viewerDOMId}-ySlice\" class=\"${style.slider}\" />`\n  const yPlaneLabel = ySliderEntry.querySelector(`#${viewerDOMId}-ySliceLabel`)\n  context.main.yPlaneLabel = yPlaneLabel\n\n  const ySliceElement = ySliderEntry.querySelector(`#${viewerDOMId}-ySlice`)\n  ySliceElement.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'Y_SLICE_CHANGED',\n      data: Number(ySliceElement.value),\n    })\n  })\n  context.main.ySliceElement = ySliceElement\n\n  yPlaneRow.appendChild(ySliderEntry)\n  planeUIGroup.appendChild(yPlaneRow)\n\n  const zPlaneRow = document.createElement('div')\n  zPlaneRow.setAttribute('class', style.planeUIRow)\n  zPlaneRow.className += ` ${viewerDOMId}-z-plane-row`\n  context.main.zPlaneRow = zPlaneRow\n\n  const zPlaneVisibleButton = document.createElement('div')\n  zPlaneVisibleButton.setAttribute('class', style.visibleButton)\n  zPlaneVisibleButton.innerHTML = `<input id=\"${context.id}-zPlaneVisibleButton\" type=\"checkbox\" checked class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Z plane visibility\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-zPlaneVisibleButton\"><img src=\"${visibleIconDataUri}\" alt=\"visible\" /></label>`\n  const zPlaneVisibleButtonInput = zPlaneVisibleButton.children[0]\n  const zPlaneVisibleLabel = zPlaneVisibleButton.children[1]\n  zPlaneRow.appendChild(zPlaneVisibleButton)\n  context.main.zPlaneVisibleButton = zPlaneVisibleButton\n\n  const zPlaneInvisibleButton = document.createElement('div')\n  zPlaneInvisibleButton.setAttribute('class', style.visibleButton)\n  zPlaneInvisibleButton.innerHTML = `<input id=\"${context.id}-invisibleButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Z plane visibility\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-zPlaneInvisibleButton\"><img src=\"${invisibleIconDataUri}\" alt=\"invisible\" /></label>`\n  const zPlaneInvisibleButtonInput = zPlaneInvisibleButton.children[0]\n  const zPlaneInvisibleLabel = zPlaneInvisibleButton.children[1]\n  zPlaneRow.appendChild(zPlaneInvisibleButton)\n  context.main.zPlaneInvisibleButton = zPlaneInvisibleButton\n\n  if (context.main.viewMode === 'Volume') {\n    if (context.main.slicingPlanes.z.visible) {\n      zPlaneVisibleButton.style.display = 'flex'\n      zPlaneInvisibleButton.style.display = 'none'\n    } else {\n      zPlaneVisibleButton.style.display = 'none'\n      zPlaneInvisibleButton.style.display = 'flex'\n    }\n  } else {\n    zPlaneVisibleButton.style.display = 'none'\n    zPlaneInvisibleButton.style.display = 'none'\n  }\n\n  zPlaneVisibleButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.z.visible = false\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    zPlaneVisibleButton.checked = true\n  })\n  zPlaneInvisibleButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.z.visible = true\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    zPlaneInvisibleButton.checked = false\n  })\n\n  const zPlanePauseButton = document.createElement('div')\n  zPlanePauseButton.innerHTML = `<input id=\"${context.id}-zPlanePauseButton\" type=\"checkbox\" checked class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Z plane pause scroll\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-zPlanePauseButton\"><img src=\"${pauseIconDataUri}\" alt=\"pause\" /></label>`\n  const zPlanePauseButtonInput = zPlanePauseButton.children[0]\n  const zPlanePauseLabel = zPlanePauseButton.children[1]\n  zPlaneRow.appendChild(zPlanePauseButton)\n  context.main.zPlanePauseButton = zPlanePauseButton\n\n  const zPlanePlayButton = document.createElement('div')\n  zPlanePauseButton.setAttribute('class', style.visibleButton)\n  zPlanePlayButton.setAttribute('class', style.visibleButton)\n  zPlanePlayButton.innerHTML = `<input id=\"${context.id}-zPlanePlayButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Z plane play scroll\" class=\"${style.visibleButton} ${style.toggleButton}\" for=\"${context.id}-zPlanePlayButton\"><img src=\"${playIconDataUri}\" alt=\"play\" /></label>`\n  const zPlanePlayButtonInput = zPlanePlayButton.children[0]\n  const zPlanePlayLabel = zPlanePlayButton.children[1]\n  zPlaneRow.appendChild(zPlanePlayButton)\n  context.main.zPlanePlayButton = zPlanePlayButton\n\n  if (context.main.slicingPlanes.z.scroll) {\n    zPlanePauseButton.style.display = 'flex'\n    zPlanePlayButton.style.display = 'none'\n  } else {\n    zPlanePauseButton.style.display = 'none'\n    zPlanePlayButton.style.display = 'flex'\n  }\n\n  zPlanePauseButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.z.scroll = false\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    zPlanePauseButton.checked = true\n  })\n  zPlanePlayButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    slicingPlanes.z.scroll = true\n    slicingPlanes.z.visible = true\n    context.service.send({\n      type: 'SLICING_PLANES_CHANGED',\n      data: slicingPlanes,\n    })\n    zPlanePlayButton.checked = false\n  })\n\n  const zSliderEntry = document.createElement('div')\n  zSliderEntry.setAttribute('class', style.sliderEntry)\n  zSliderEntry.innerHTML = `\n    <label id=\"${viewerDOMId}-zSliceLabel\" class=\"${style.zPlaneLabel}\">Z:</label><input type=\"range\" min=\"0.0\" max=\"1.0\" value=\"0.5\" step=\"0.1\"\n      id=\"${viewerDOMId}-zSlice\" class=\"${style.slider}\" />`\n  const zPlaneLabel = zSliderEntry.querySelector(`#${viewerDOMId}-zSliceLabel`)\n  context.main.zPlaneLabel = zPlaneLabel\n\n  const zSliceElement = zSliderEntry.querySelector(`#${viewerDOMId}-zSlice`)\n  zSliceElement.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({\n      type: 'Z_SLICE_CHANGED',\n      data: Number(zSliceElement.value),\n    })\n  })\n  context.main.zSliceElement = zSliceElement\n\n  zPlaneRow.appendChild(zSliderEntry)\n  planeUIGroup.appendChild(zPlaneRow)\n\n  const viewContainer = context.viewContainers.get('volume')\n  viewContainer.appendChild(planeUIGroup)\n\n  if (context.use2D || context.uiCollapsed) {\n    planeUIGroup.style.display = 'none'\n  }\n  context.main.planeUIGroup = planeUIGroup\n}\n\nexport default createPlaneSliders\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createResetCameraButton.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport { resetCameraIconDataUri } from '@itk-viewer/icons'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nfunction createResetCameraButton(context, mainUIRow) {\n  const viewerDOMId = context.id\n  const resetCameraButton = document.createElement('div')\n  resetCameraButton.innerHTML = `<input id=\"${viewerDOMId}-resetCameraButton\" type=\"checkbox\" class=\"${style.toggleInput}\" checked><label itk-vtk-tooltip itk-vtk-tooltip-left itk-vtk-tooltip-content=\"Reset camera [r]\" class=\"${style.resetCameraButton} ${style.toggleButton}\" for=\"${viewerDOMId}-resetCameraButton\"><img src=\"${resetCameraIconDataUri}\" alt=\"reset camera\" /></label>`\n  const resetCameraButtonLabel = resetCameraButton.children[1]\n  context.main.resetCameraButtonLabel = resetCameraButtonLabel\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    resetCameraButtonLabel\n  )\n\n  resetCameraButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('RESET_CAMERA')\n  })\n  resetCameraButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('RESET_CAMERA')\n  })\n  mainUIRow.appendChild(resetCameraButton)\n}\n\nexport default createResetCameraButton\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createRotateButton.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport { rotateIconDataUri } from '@itk-viewer/icons'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\nimport toggleRotate from './toggleRotate'\n\nfunction createRotateButton(context, mainUIRow) {\n  const rotateButton = document.createElement('div')\n  rotateButton.innerHTML = `<input id=\"${context.id}-toggleRotateButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-fullscreen itk-vtk-tooltip-content=\"Spin in 3D [p]\" class=\"${style.rotateButton} ${style.toggleButton}\" for=\"${context.id}-toggleRotateButton\"><img src=\"${rotateIconDataUri}\" alt=\"rotate\"/></label>`\n  const rotateButtonInput = rotateButton.children[0]\n  const rotateButtonLabel = rotateButton.children[1]\n  context.main.rotateButtonLabel = rotateButtonLabel\n  context.main.rotateButtonInput = rotateButtonInput\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    rotateButtonLabel\n  )\n\n  toggleRotate(context)\n  rotateButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('TOGGLE_ROTATE')\n  })\n\n  mainUIRow.appendChild(rotateButton)\n}\n\nexport default createRotateButton\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createScreenshotButton.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport { screenshotIconDataUri } from '@itk-viewer/icons'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nfunction createScreenshotButton(context, mainUIRow) {\n  const screenshotButton = document.createElement('div')\n  screenshotButton.innerHTML = `<input id=\"${context.id}-screenshotButton\" type=\"checkbox\" checked class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-annotations itk-vtk-tooltip-content=\"Screenshot\" class=\"${style.screenshotButton} ${style.toggleButton}\" for=\"${context.id}-screenshotButton\"><img src=\"${screenshotIconDataUri}\" alt=\"screenshot\" /></label>`\n  const screenshotButtonInput = screenshotButton.children[0]\n  const screenshotLabel = screenshotButton.children[1]\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    screenshotLabel\n  )\n\n  screenshotButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('TAKE_SCREENSHOT')\n    screenshotButton.checked = true\n  })\n  context.main.screenshotButton = screenshotButton\n  mainUIRow.appendChild(screenshotButton)\n}\n\nexport default createScreenshotButton\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createViewModeButtons.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport {\n  volumeIconDataUri,\n  redPlaneIconDataUri,\n  yellowPlaneIconDataUri,\n  greenPlaneIconDataUri,\n} from '@itk-viewer/icons'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nfunction createViewModeButtons(context, mainRow) {\n  const viewerDOMId = context.id\n\n  const xPlaneButton = document.createElement('div')\n  context.main.xPlaneButton = xPlaneButton\n  xPlaneButton.innerHTML = `<input id=\"${viewerDOMId}-xPlaneButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"X plane [1]\" class=\"${style.viewModeButton} ${style.toggleButton}\" for=\"${viewerDOMId}-xPlaneButton\"><img src=\"${redPlaneIconDataUri}\" alt=\"x plane\"/></label>`\n  const xPlaneButtonLabel = xPlaneButton.children[1]\n  context.main.xPlaneButtonLabel = xPlaneButtonLabel\n  applyContrastSensitiveStyleToElement(\n    context,\n    'tooltipButton',\n    xPlaneButtonLabel\n  )\n  xPlaneButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({ type: 'VIEW_MODE_CHANGED', data: 'XPlane' })\n  })\n  mainRow.appendChild(xPlaneButton)\n\n  const yPlaneButton = document.createElement('div')\n  context.main.yPlaneButton = yPlaneButton\n  yPlaneButton.innerHTML = `<input id=\"${viewerDOMId}-yPlaneButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Y plane [2]\" class=\"${style.viewModeButton} ${style.toggleButton}\" for=\"${viewerDOMId}-yPlaneButton\"><img src=\"${yellowPlaneIconDataUri}\" alt=\"y plane\" /></label>`\n  const yPlaneButtonLabel = yPlaneButton.children[1]\n  context.main.yPlaneButtonLabel = yPlaneButtonLabel\n  applyContrastSensitiveStyleToElement(\n    context,\n    'tooltipButton',\n    yPlaneButtonLabel\n  )\n  yPlaneButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({ type: 'VIEW_MODE_CHANGED', data: 'YPlane' })\n  })\n  mainRow.appendChild(yPlaneButton)\n\n  const zPlaneButton = document.createElement('div')\n  context.main.zPlaneButton = zPlaneButton\n  zPlaneButton.innerHTML = `<input id=\"${viewerDOMId}-zPlaneButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Z plane [3]\" class=\"${style.viewModeButton} ${style.toggleButton}\" for=\"${viewerDOMId}-zPlaneButton\"><img src=\"${greenPlaneIconDataUri}\" alt=\"z plane\" /></label>`\n  const zPlaneButtonLabel = zPlaneButton.children[1]\n  context.main.zPlaneButtonLabel = zPlaneButtonLabel\n  applyContrastSensitiveStyleToElement(\n    context,\n    'tooltipButton',\n    zPlaneButtonLabel\n  )\n  zPlaneButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({ type: 'VIEW_MODE_CHANGED', data: 'ZPlane' })\n  })\n  mainRow.appendChild(zPlaneButton)\n\n  const volumeButton = document.createElement('div')\n  context.main.volumeButton = volumeButton\n  volumeButton.innerHTML = `<input id=\"${viewerDOMId}-volumeButton\" type=\"checkbox\" class=\"${style.toggleInput}\" checked><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Volume [4]\" class=\"${style.viewModeButton} ${style.toggleButton}\" for=\"${viewerDOMId}-volumeButton\"><img src=\"${volumeIconDataUri}\" alt=\"volume\" /></label>`\n  const volumeButtonLabel = volumeButton.children[1]\n  context.main.volumeButtonLabel = volumeButtonLabel\n  applyContrastSensitiveStyleToElement(\n    context,\n    'tooltipButton',\n    volumeButtonLabel\n  )\n  volumeButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send({ type: 'VIEW_MODE_CHANGED', data: 'Volume' })\n  })\n  mainRow.appendChild(volumeButton)\n}\n\nexport default createViewModeButtons\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/createViewPlanesToggle.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { viewPlanesIconDataUri } from '@itk-viewer/icons'\n\nfunction createViewPlanesToggle(context, volumeRow) {\n  const viewerDOMId = context.id\n\n  const viewPlanesButton = document.createElement('div')\n  viewPlanesButton.innerHTML = `<input id=\"${viewerDOMId}-toggleSlicingPlanesButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top-axes itk-vtk-tooltip-content=\"View planes [s]\" class=\"${style.viewPlanesButton} ${style.toggleButton}\" for=\"${viewerDOMId}-toggleSlicingPlanesButton\"><img src=\"${viewPlanesIconDataUri}\" alt=\"view planes\" /></label>`\n  const viewPlanesButtonInput = viewPlanesButton.children[0]\n  const viewPlanesButtonLabel = viewPlanesButton.children[1]\n  context.main.viewPlanesButton = viewPlanesButton\n  context.main.viewPlanesButtonLabel = viewPlanesButtonLabel\n  context.main.viewPlanesButtonInput = viewPlanesButtonInput\n  applyContrastSensitiveStyleToElement(\n    context,\n    'tooltipButton',\n    viewPlanesButtonLabel\n  )\n\n  viewPlanesButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const slicingPlanes = context.main.slicingPlanes\n    if (\n      !slicingPlanes.x.visibile &&\n      !slicingPlanes.y.visible &&\n      !slicingPlanes.z.visible\n    ) {\n      slicingPlanes.x.visible = true\n      slicingPlanes.y.visible = true\n      slicingPlanes.z.visible = true\n      context.service.send({\n        type: 'SLICING_PLANES_CHANGED',\n        data: slicingPlanes,\n      })\n    } else {\n      slicingPlanes.x.visible = false\n      slicingPlanes.y.visible = false\n      slicingPlanes.z.visible = false\n      context.service.send({\n        type: 'SLICING_PLANES_CHANGED',\n        data: slicingPlanes,\n      })\n    }\n  })\n  volumeRow.appendChild(viewPlanesButton)\n}\n\nexport default createViewPlanesToggle\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/fullscreenMethods.js",
    "content": "const fullscreenMethods = []\nwindow.addEventListener('load', () => {\n  const body = document.querySelector('body')\n  // https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API\n  ;[\n    ['requestFullscreen', 'exitFullscreen', 'fullscreenchange', 'fullscreen'],\n    [\n      'mozRequestFullScreen',\n      'mozCancelFullScreen',\n      'mozfullscreenchange',\n      'mozFullScreen',\n    ],\n    [\n      'msRequestFullscreen',\n      'msExitFullscreen',\n      'MSFullscreenChange',\n      'msFullscreenEnabled',\n    ],\n    [\n      'webkitRequestFullscreen',\n      'webkitExitFullscreen',\n      'webkitfullscreenchange',\n      'webkitIsFullScreen',\n    ],\n  ].forEach(methods => {\n    if (body[methods[0]] && fullscreenMethods.length === 0) {\n      fullscreenMethods.splice(methods, methods.length, ...methods)\n    }\n  })\n})\n\nexport default fullscreenMethods\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/mainUIMachineOptions.js",
    "content": "import createMainInterface from './createMainInterface'\nimport toggleFullscreen from './toggleFullscreen'\nimport toggleRotate from './toggleRotate'\nimport toggleAnnotations from './toggleAnnotations'\nimport toggleAxes from './toggleAxes'\nimport toggleBackgroundColor from './toggleBackgroundColor'\nimport toggleCroppingPlanes from './toggleCroppingPlanes'\nimport viewModeXPlane from './viewModeXPlane'\nimport viewModeYPlane from './viewModeYPlane'\nimport viewModeZPlane from './viewModeZPlane'\nimport viewModeVolume from './viewModeVolume'\nimport applySlicingPlanes from './applySlicingPlanes'\nimport applyXSlice from './applyXSlice'\nimport applyYSlice from './applyYSlice'\nimport applyZSlice from './applyZSlice'\n\nconst mainUIMachineOptions = {\n  actions: {\n    createMainInterface,\n\n    toggleAnnotations,\n\n    toggleFullscreen,\n\n    toggleRotate,\n\n    toggleAxes,\n\n    toggleBackgroundColor,\n\n    toggleCroppingPlanes,\n\n    viewModeXPlane,\n    viewModeYPlane,\n    viewModeZPlane,\n    viewModeVolume,\n\n    applySlicingPlanes,\n    applyXSlice,\n    applyYSlice,\n    applyZSlice,\n  },\n}\n\nexport default mainUIMachineOptions\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/resetCrop.js",
    "content": ""
  },
  {
    "path": "src/UI/reference-ui/src/Main/toggleAnnotations.js",
    "content": "function toggleAnnotations(context) {\n  if (context.main.annotationsButtonInput) {\n    context.main.annotationsButtonInput.checked =\n      context.main.annotationsEnabled\n  }\n}\n\nexport default toggleAnnotations\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/toggleAxes.js",
    "content": "function toggleAxes(context) {\n  if (context.main.axesButtonInput) {\n    context.main.axesButtonInput.checked = context.main.axesEnabled\n  }\n}\n\nexport default toggleAxes\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/toggleBackgroundColor.js",
    "content": "function toggleBackgroundColor(context) {\n  context.main.selectedBackgroundColor =\n    (context.main.selectedBackgroundColor + 1) %\n    context.main.backgroundColors.length\n  context.main.backgroundColor =\n    context.main.backgroundColors[context.main.selectedBackgroundColor]\n}\n\nexport default toggleBackgroundColor\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/toggleCrop.js",
    "content": ""
  },
  {
    "path": "src/UI/reference-ui/src/Main/toggleCroppingPlanes.js",
    "content": "function toggleCroppingPlanes(context) {\n  if (context.main.cropButtonInput) {\n    context.main.cropButtonInput.checked = context.main.croppingPlanesEnabled\n  }\n}\n\nexport default toggleCroppingPlanes\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/toggleFullscreen.js",
    "content": "import fullscreenMethods from './fullscreenMethods'\n\nfunction toggleFullscreen(context, event, actionMeta) {\n  const fullscreenEnabled = context.main.fullscreenEnabled\n  const fullscreenButtonInput = context.main.fullscreenButton.children[0]\n  fullscreenButtonInput.checked = fullscreenEnabled\n\n  // Triggered by operating system events, e.g. pressing Esc while in\n  // Fullscreen or F11 when not in fullscreen\n  if (fullscreenEnabled === document[fullscreenMethods[3]]) {\n    return\n  }\n\n  const container = context.rootContainer\n  const oldWidth = context.main.rootContainerOldWidth\n  const oldHeight = context.main.rootContainerOldHeight\n\n  if (fullscreenEnabled) {\n    context.main.rootContainerOldWidth = container.style.width\n    context.main.rootContainerOldHeight = container.style.height\n    container.style.width = '100vw'\n    container.style.height = '100vh'\n    context.rootContainer[fullscreenMethods[0]]()\n  } else {\n    container.style.width = oldWidth\n    container.style.height = oldHeight\n    document[fullscreenMethods[1]]()\n  }\n}\n\nexport default toggleFullscreen\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/toggleRotate.js",
    "content": "function toggleRotate(context) {\n  if (context.main.rotateButtonInput) {\n    context.main.rotateButtonInput.checked = context.main.rotateEnabled\n  }\n}\n\nexport default toggleRotate\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/viewModeVolume.js",
    "content": "function viewModeVolume(context) {\n  const main = context.main\n\n  if (main.xPlaneButton) {\n    main.xPlaneButton.checked = false\n  }\n  if (main.yPlaneButton) {\n    main.yPlaneButton.checked = false\n  }\n  if (main.zPlaneButton) {\n    main.zPlaneButton.checked = false\n  }\n  if (main.volumeButton) {\n    main.volumeButton.checked = true\n  }\n\n  if (!main.planeUIGroup) {\n    return\n  }\n  const slicingPlanes = main.slicingPlanes\n  main.xPlaneVisibleButton.style.display = slicingPlanes.x.visible\n    ? 'flex'\n    : 'none'\n  main.xPlaneInvisibleButton.style.display = slicingPlanes.x.visible\n    ? 'none'\n    : 'flex'\n  main.yPlaneVisibleButton.style.display = slicingPlanes.y.visible\n    ? 'flex'\n    : 'none'\n  main.yPlaneInvisibleButton.style.display = slicingPlanes.y.visible\n    ? 'none'\n    : 'flex'\n  main.zPlaneVisibleButton.style.display = slicingPlanes.z.visible\n    ? 'flex'\n    : 'none'\n  main.zPlaneInvisibleButton.style.display = slicingPlanes.z.visible\n    ? 'none'\n    : 'flex'\n\n  if (context.uiCollapsed) {\n    main.planeUIGroup.style.display = 'none'\n  } else {\n    main.planeUIGroup.style.display = 'block'\n    main.xPlaneRow.style.display = 'flex'\n    main.yPlaneRow.style.display = 'flex'\n    main.zPlaneRow.style.display = 'flex'\n  }\n}\n\nexport default viewModeVolume\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/viewModeXPlane.js",
    "content": "function viewModeXPlane(context) {\n  const main = context.main\n\n  if (main.xPlaneButton) {\n    main.xPlaneButton.checked = true\n  }\n  if (main.yPlaneButton) {\n    main.yPlaneButton.checked = false\n  }\n  if (main.zPlaneButton) {\n    main.zPlaneButton.checked = false\n  }\n  if (main.volumeButton) {\n    main.volumeButton.checked = false\n  }\n\n  if (!main.planeUIGroup) {\n    return\n  }\n  if (!context.use2D) {\n    main.xPlaneVisibleButton.style.display = 'none'\n    main.xPlaneInvisibleButton.style.display = 'none'\n\n    main.yPlaneVisibleButton.style.display = 'none'\n    main.yPlaneInvisibleButton.style.display = 'none'\n\n    main.zPlaneVisibleButton.style.display = 'none'\n    main.zPlaneInvisibleButton.style.display = 'none'\n  }\n  main.planeUIGroup.style.display = 'block'\n  main.xPlaneRow.style.display = 'flex'\n  main.yPlaneRow.style.display = 'none'\n  main.zPlaneRow.style.display = 'none'\n}\n\nexport default viewModeXPlane\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/viewModeYPlane.js",
    "content": "function viewModeYPlane(context) {\n  const main = context.main\n\n  if (main.xPlaneButton) {\n    main.xPlaneButton.checked = false\n  }\n  if (main.yPlaneButton) {\n    main.yPlaneButton.checked = true\n  }\n  if (main.zPlaneButton) {\n    main.zPlaneButton.checked = false\n  }\n  if (main.volumeButton) {\n    main.volumeButton.checked = false\n  }\n\n  if (!main.planeUIGroup) {\n    return\n  }\n  if (!context.use2D) {\n    main.xPlaneVisibleButton.style.display = 'none'\n    main.xPlaneInvisibleButton.style.display = 'none'\n\n    main.yPlaneVisibleButton.style.display = 'none'\n    main.yPlaneInvisibleButton.style.display = 'none'\n\n    main.zPlaneVisibleButton.style.display = 'none'\n    main.zPlaneInvisibleButton.style.display = 'none'\n  }\n  main.planeUIGroup.style.display = 'block'\n  main.xPlaneRow.style.display = 'none'\n  main.yPlaneRow.style.display = 'flex'\n  main.zPlaneRow.style.display = 'none'\n}\n\nexport default viewModeYPlane\n"
  },
  {
    "path": "src/UI/reference-ui/src/Main/viewModeZPlane.js",
    "content": "function viewModeZPlane(context) {\n  const main = context.main\n\n  if (main.xPlaneButton) {\n    main.xPlaneButton.checked = false\n  }\n  if (main.yPlaneButton) {\n    main.yPlaneButton.checked = false\n  }\n  if (main.zPlaneButton) {\n    main.zPlaneButton.checked = true\n  }\n  if (main.volumeButton) {\n    main.volumeButton.checked = false\n  }\n\n  if (!main.planeUIGroup) {\n    return\n  }\n  if (!context.use2D) {\n    main.xPlaneVisibleButton.style.display = 'none'\n    main.xPlaneInvisibleButton.style.display = 'none'\n\n    main.yPlaneVisibleButton.style.display = 'none'\n    main.yPlaneInvisibleButton.style.display = 'none'\n\n    main.zPlaneVisibleButton.style.display = 'none'\n    main.zPlaneInvisibleButton.style.display = 'none'\n  }\n  main.planeUIGroup.style.display = 'block'\n  main.xPlaneRow.style.display = 'none'\n  main.yPlaneRow.style.display = 'none'\n  main.zPlaneRow.style.display = 'flex'\n}\n\nexport default viewModeZPlane\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/applyDistanceWidgetValue.js",
    "content": "function applyDistanceWidgetValue(context, event) {\n  context.widgets.distanceValueElement.setAttribute('value', `${event.data}`)\n}\n\nexport default applyDistanceWidgetValue\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/applyWidgetsContrastSensitiveStyle.js",
    "content": "import applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nfunction applyMainContrastSensitiveStyle(context) {\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    context.widgets.distanceButtonLabel\n  )\n  applyContrastSensitiveStyleToElement(\n    context,\n    'distanceLabel',\n    context.widgets.distanceLabel\n  )\n}\n\nexport default applyMainContrastSensitiveStyle\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/createDistanceWidget.js",
    "content": "import style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyleToElement from '../applyContrastSensitiveStyleToElement'\n\nimport { lengthToolIconDataUri } from '@itk-viewer/icons'\n\nfunction createDistanceWidget(context, widgetsUIGroup) {\n  const viewerDOMId = context.id\n\n  // Put distance tools in their own row\n  const distanceRulerRow = document.createElement('div')\n  distanceRulerRow.setAttribute('class', style.uiRow)\n  distanceRulerRow.style.display = context.use2D ? 'flex' : 'none'\n  if (context.main.viewMode === 'Volume' && !context.use2D) {\n    distanceRulerRow.style.display = 'none'\n  } else {\n    distanceRulerRow.style.display = 'flex'\n  }\n\n  const distanceEntry = document.createElement('div')\n  distanceEntry.setAttribute('class', style.distanceEntry)\n\n  const distanceButton = document.createElement('span')\n  distanceButton.innerHTML = `<input id=\"${viewerDOMId}-toggleDistanceButton\" type=\"checkbox\" class=\"${style.toggleInput}\" checked><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Length\" class=\"${style.distanceButton} ${style.toggleButton}\" for=\"${viewerDOMId}-toggleDistanceButton\"><img src=\"${lengthToolIconDataUri}\" alt=\"distance\"/></label>`\n  context.widgets.distanceButtonInput = distanceButton.children[0]\n  context.widgets.distanceButtonInput.checked = context.widgets.distanceEnabled\n  const distanceButtonLabel = distanceButton.children[1]\n  context.widgets.distanceButtonLabel = distanceButtonLabel\n  applyContrastSensitiveStyleToElement(\n    context,\n    'invertibleButton',\n    distanceButtonLabel\n  )\n\n  distanceButton.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    context.service.send('TOGGLE_DISTANCE_WIDGET')\n  })\n\n  distanceEntry.appendChild(distanceButton)\n\n  const distanceLabel = document.createElement('label')\n  distanceLabel.setAttribute('class', `${style.distanceLabelCommon}`)\n  context.widgets.distanceLabel = distanceLabel\n  applyContrastSensitiveStyleToElement(context, 'distanceLabel', distanceLabel)\n  distanceLabel.setAttribute('for', `${viewerDOMId}-distanceValue`)\n  distanceLabel.id = `${viewerDOMId}-distanceLabel`\n  distanceLabel.innerText = 'Length:'\n  distanceEntry.appendChild(distanceLabel)\n\n  const distanceValue = document.createElement('input')\n  distanceValue.type = 'text'\n  distanceValue.setAttribute('class', style.distanceInput)\n  distanceValue.id = `${viewerDOMId}-distanceValue`\n  distanceValue.setAttribute('name', 'length')\n  distanceValue.setAttribute('value', context.widgets.distanceValue.toString())\n  distanceValue.setAttribute('disabled', true)\n  context.widgets.distanceValueElement = distanceValue\n  distanceEntry.appendChild(distanceValue)\n\n  context.widgets.distanceRulerRow = distanceRulerRow\n  distanceRulerRow.appendChild(distanceEntry)\n\n  widgetsUIGroup.appendChild(distanceRulerRow)\n}\n\nexport default createDistanceWidget\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/createWidgetsInterface.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport createDistanceWidget from './createDistanceWidget'\n\nfunction createWidgetsInterface(context) {\n  const widgetsUIGroup = document.createElement('div')\n  widgetsUIGroup.setAttribute('class', style.uiGroup)\n  context.widgets.widgetsUIGroup = widgetsUIGroup\n  context.uiGroups.set('widgets', widgetsUIGroup)\n\n  createDistanceWidget(context, widgetsUIGroup)\n\n  context.uiContainer.appendChild(widgetsUIGroup)\n}\n\nexport default createWidgetsInterface\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/toggleDistanceWidget.js",
    "content": "function toggleDistanceWidget(context) {\n  context.widgets.distanceButtonInput.checked = context.widgets.distanceEnabled\n}\n\nexport default toggleDistanceWidget\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/viewModeVolume.js",
    "content": "function viewModeVolume(context) {\n  // Disable if in volume mode\n  if (context.widgets.distanceEnabled) {\n    context.service.send('TOGGLE_DISTANCE_WIDGET')\n  }\n  context.widgets.distanceRulerRow.style.display = 'none'\n}\n\nexport default viewModeVolume\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/viewModeXPlane.js",
    "content": "function viewModeXPlane(context) {\n  context.widgets.distanceRulerRow.style.display = 'flex'\n}\n\nexport default viewModeXPlane\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/viewModeYPlane.js",
    "content": "function viewModeYPlane(context) {\n  context.widgets.distanceRulerRow.style.display = 'flex'\n}\n\nexport default viewModeYPlane\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/viewModeZPlane.js",
    "content": "function viewModeZPlane(context) {\n  context.widgets.distanceRulerRow.style.display = 'flex'\n}\n\nexport default viewModeZPlane\n"
  },
  {
    "path": "src/UI/reference-ui/src/Widgets/widgetsUIMachineOptions.js",
    "content": "import createWidgetsInterface from './createWidgetsInterface'\nimport viewModeXPlane from './viewModeXPlane'\nimport viewModeYPlane from './viewModeYPlane'\nimport viewModeZPlane from './viewModeZPlane'\nimport viewModeVolume from './viewModeVolume'\nimport toggleDistanceWidget from './toggleDistanceWidget'\nimport applyDistanceWidgetValue from './applyDistanceWidgetValue'\n\nconst widgetsUIMachineOptions = {\n  actions: {\n    createWidgetsInterface,\n\n    viewModeXPlane,\n    viewModeYPlane,\n    viewModeZPlane,\n    viewModeVolume,\n\n    toggleDistanceWidget,\n    applyDistanceWidgetValue,\n  },\n}\n\nexport default widgetsUIMachineOptions\n"
  },
  {
    "path": "src/UI/reference-ui/src/applyCategoricalColorToColorTransferFunction.js",
    "content": "import { CategoricalColors } from 'itk-viewer-color-maps'\n\nfunction applyCategoricalColorToColorTransferFunction(\n  colorTransferFunction,\n  labels,\n  presetName\n) {\n  const numberOfLabels = labels.length\n\n  if (!CategoricalColors.has(presetName)) {\n    console.error(\n      `Categorical color ${presetName} requested but it is not available`\n    )\n  }\n  const colors = CategoricalColors.get(presetName).IndexedColors\n  const rgbPoints = new Array(numberOfLabels)\n  // Assume background\n  const haveBackground = labels[0] === 0 ? true : false\n  let startIndex = 0\n  if (haveBackground) {\n    startIndex = 1\n    rgbPoints[0] = [labels[0], 0.0, 0.0, 0.0, 0.5, 1.0]\n  }\n  for (let labelIndex = startIndex; labelIndex < numberOfLabels; labelIndex++) {\n    const index = (labelIndex - startIndex) * 3\n    const color = colors.slice(index, index + 3)\n    rgbPoints[labelIndex] = [\n      labels[labelIndex],\n      color[0],\n      color[1],\n      color[2],\n      0.5,\n      1.0,\n    ]\n  }\n\n  colorTransferFunction.removeAllPoints()\n  rgbPoints.forEach(point => {\n    colorTransferFunction.addRGBPointLong(...point)\n  })\n  colorTransferFunction.setMappingRange(labels[0], labels[numberOfLabels - 1])\n}\n\nexport default applyCategoricalColorToColorTransferFunction\n"
  },
  {
    "path": "src/UI/reference-ui/src/applyContrastSensitiveStyleToElement.js",
    "content": "import style from './ItkVtkViewer.module.css'\n\nfunction applyContrastSensitiveStyleToElement(context, cssClass, element) {\n  if (element) {\n    const uiDarkMode = context.uiDarkMode\n    const addPostFix = uiDarkMode ? 'DarkBG' : 'BrightBG'\n    const removePostFix = !uiDarkMode ? 'DarkBG' : 'BrightBG'\n    const removeClass = style[`${cssClass}${removePostFix}`]\n    if (element.classList.contains(removeClass)) {\n      element.classList.remove(removeClass)\n    }\n    element.classList.add(style[`${cssClass}${addPostFix}`])\n  }\n}\n\nexport default applyContrastSensitiveStyleToElement\n"
  },
  {
    "path": "src/UI/reference-ui/src/applyGroupVisibility.js",
    "content": "function applyGroupVisibility(context, groupNames, visible) {\n  for (let idx = 0; idx < groupNames.length; idx++) {\n    if (!context.uiGroups.has(groupNames[idx])) {\n      continue\n    }\n    const uiGroup = context.uiGroups.get(groupNames[idx])\n    if (visible) {\n      uiGroup.style.display = 'block'\n    } else {\n      uiGroup.style.display = 'none'\n    }\n  }\n}\n\nexport default applyGroupVisibility\n"
  },
  {
    "path": "src/UI/reference-ui/src/collapse-ui.ts",
    "content": "import { LitElement, html, css } from 'lit'\nimport { customElement } from 'lit/decorators.js'\nimport '@material/web/iconbutton/icon-button.js'\nimport '@material/web/icon/icon.js'\nimport { toggleIconDataUri } from '@itk-viewer/icons'\nimport { connectState } from 'xstate-lit/dist/select-state'\n\nimport { viewerContext } from './context'\n\n@customElement('collapse-ui')\nclass CollapseUi extends LitElement {\n  service = connectState(\n    viewerContext,\n    this,\n    (state: any) => state.context.service\n  )\n\n  static styles = css`\n    .icon {\n      width: 100%;\n    }\n  `\n\n  render() {\n    return html`\n      <md-icon-button @click=${this.toggleUi}>\n        <img src=\"${toggleIconDataUri}\" alt=\"toggle\" class=\"icon\" />\n      </md-icon-button>\n    `\n  }\n\n  toggleUi() {\n    this.service.value.send('TOGGLE_UI_COLLAPSED')\n  }\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/context.ts",
    "content": "// \"Inject\" XState context into components with DOM events\nimport { createContext } from '@lit-labs/context'\nexport type ViewerContext = { service: any }\nexport const viewerContext = createContext<ViewerContext>('viewer-context')\n\ntype AppContext = any\n\nexport let appContext: AppContext\n\nexport const setContext = (context: AppContext) => {\n  appContext = context\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/createCategoricalColorIconSelector.js",
    "content": "import { IconSelect } from '@thewtex/iconselect.js/lib/control/iconselect'\nimport { CategoricalColorIcons } from 'itk-viewer-color-maps'\n\nfunction createCategoricalColorIconSelector(categoricalColorSelectorDiv) {\n  const rows = 4\n  const cols = 2\n  const iconSelectParameters = {\n    selectedIconWidth: 140,\n    selectedIconHeight: 22,\n    selectedBoxPadding: 1,\n    iconsWidth: 60,\n    iconsHeight: 22,\n    boxIconSpace: 1,\n    vectoralIconNumber: cols,\n    horizontalIconNumber: rows,\n  }\n  const iconSelect = new IconSelect(\n    `${categoricalColorSelectorDiv.id}`,\n    categoricalColorSelectorDiv,\n    iconSelectParameters\n  )\n  categoricalColorSelectorDiv.style.width = '154px'\n  const icons = new Array(rows * cols)\n  let count = 0\n  for (let [key, value] of CategoricalColorIcons.entries()) {\n    const index = Math.floor(count % rows) * cols + Math.floor(count / rows)\n    icons[index] = { iconFilePath: value, iconValue: key }\n    count++\n  }\n  iconSelect.refresh(icons)\n\n  return iconSelect\n}\n\nexport default createCategoricalColorIconSelector\n"
  },
  {
    "path": "src/UI/reference-ui/src/createColorMapIconSelector.js",
    "content": "import { IconSelect } from '@thewtex/iconselect.js/lib/control/iconselect'\nimport { ColorMapIcons, CategoricalColorIcons } from 'itk-viewer-color-maps'\n\nfunction createColorMapIconSelector(colorMapSelectorDiv) {\n  const rows = 20\n  const cols = 4\n  const iconSelectParameters = {\n    selectedIconWidth: 140,\n    selectedIconHeight: 22,\n    selectedBoxPadding: 1,\n    iconsWidth: 80,\n    iconsHeight: 22,\n    boxIconSpace: 1,\n    vectoralIconNumber: cols,\n    horizontalIconNumber: rows,\n  }\n  const iconSelect = new IconSelect(\n    `${colorMapSelectorDiv.id}`,\n    colorMapSelectorDiv,\n    iconSelectParameters\n  )\n  colorMapSelectorDiv.style.width = '154px'\n  // put above lower down label map color selector\n  colorMapSelectorDiv.style.zIndex = '2001'\n\n  const filteredIcons = new Map(\n    Array.from(ColorMapIcons.entries()).concat(\n      Array.from(CategoricalColorIcons.entries()).filter(\n        ([name]) => !name.startsWith('modulate')\n      )\n    )\n  )\n\n  const icons = new Array(Math.min(rows * cols, filteredIcons.size))\n  let count = 0\n  for (let [key, value] of filteredIcons.entries()) {\n    const index = Math.floor(count % rows) * cols + Math.floor(count / rows)\n    icons[index] = { iconFilePath: value, iconValue: key }\n    count++\n  }\n  iconSelect.refresh(icons)\n\n  // keeps popout from getting clipped outside of sidebar width\n  const box = colorMapSelectorDiv.querySelector('.icon-select .box')\n  box.style.left = '-87px'\n  box.style.top = '100%'\n  box.style.width = '333px' // avoids asymmetric whitespace on right side of popout\n\n  return iconSelect\n}\n\nexport default createColorMapIconSelector\n"
  },
  {
    "path": "src/UI/reference-ui/src/createInterface.js",
    "content": "import style from './ItkVtkViewer.module.css'\nimport '@material/web/labs/navigationdrawer/navigation-drawer.js'\nimport './serviceContext'\nimport './collapse-ui'\nimport { setContext } from './context'\nimport { makeHtml } from './utils'\nimport { updateDrawer } from './toggleUICollapsed'\n\nfunction createInterface(context) {\n  setContext(context)\n  context.viewContainers = new Map()\n\n  const viewContainer = document.createElement('div')\n  viewContainer.className = `${style.viewContainer}`\n  context.viewContainers.set('volume', viewContainer)\n\n  const serviceContextProvider = document.createElement('service-context')\n  serviceContextProvider.appendChild(viewContainer)\n  context.rootContainer.appendChild(serviceContextProvider)\n\n  const viewport = document.createElement('div')\n  viewContainer.appendChild(viewport)\n  viewport.setAttribute('class', style.viewport)\n\n  const container3d = context.renderingViewContainers.get('volume')\n  viewport.appendChild(container3d)\n  container3d.style.height = '100%'\n\n  // if somehow already set (by non reference-ui from config obj?)\n  if (!context.uiContainer) {\n    context.uiContainer = document.createElement('div')\n  }\n\n  const sidebar = makeHtml(`\n    <div class='${style.uiContainer}'>\n      <md-navigation-drawer type=\"dismissible\" id='drawer' class='${style.drawer}'></md-navigation-drawer>\n      <collapse-ui class='${style.collapseButton}'/>\n    </div>\n  `)\n  viewport.appendChild(sidebar)\n\n  const drawer = sidebar.querySelector('#drawer')\n  context.drawer = drawer\n  drawer.appendChild(context.uiContainer)\n  context.uiContainer.style.width = 'var(--_container-width)'\n\n  setTimeout(() => {\n    // hack to keep scroll bar from squishing uiContainer, because uiContainer width does not get reduces with scroll bar.\n    drawer.shadowRoot.children[0].style.overflow = 'visible'\n    // sets hacked width of drawer based on context.uiCollapsed\n    updateDrawer(context)\n  }, 0)\n\n  if (!context.uiGroups) {\n    // String to UI group element\n    context.uiGroups = new Map()\n  }\n}\n\nexport default createInterface\n"
  },
  {
    "path": "src/UI/reference-ui/src/referenceUIMachineOptions.js",
    "content": "import mainUIMachineOptions from './Main/mainUIMachineOptions'\nimport layersUIMachineOptions from './Layers/layersUIMachineOptions'\nimport imagesUIMachineOptions from './Images/imagesUIMachineOptions'\nimport widgetsUIMachineOptions from './Widgets/widgetsUIMachineOptions'\n\nimport toggleDarkMode from './toggleDarkMode'\nimport createInterface from './createInterface'\nimport toggleUICollapsed from './toggleUICollapsed'\n\nconst referenceUIMachineOptions = {\n  main: mainUIMachineOptions,\n\n  layers: layersUIMachineOptions,\n\n  images: imagesUIMachineOptions,\n\n  widgets: widgetsUIMachineOptions,\n\n  actions: {\n    toggleDarkMode,\n\n    createInterface,\n\n    toggleUICollapsed,\n  },\n}\n\nexport default referenceUIMachineOptions\n"
  },
  {
    "path": "src/UI/reference-ui/src/serviceContext.ts",
    "content": "import { LitElement, html, css } from 'lit'\nimport { customElement } from 'lit/decorators.js'\nimport { ContextProvider } from '@lit-labs/context'\nimport { appContext, viewerContext } from './context'\n\n@customElement('service-context')\nexport class ServiceContext extends LitElement {\n  // @ts-ignore\n  private provider = new ContextProvider(this, viewerContext, {\n    service: appContext.service,\n  })\n  render() {\n    return html`\n      <slot></slot>\n    `\n  }\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'service-context': ServiceContext\n  }\n}\n"
  },
  {
    "path": "src/UI/reference-ui/src/shims.d.ts",
    "content": "declare module '*'\n"
  },
  {
    "path": "src/UI/reference-ui/src/toggleDarkMode.js",
    "content": "import applyMainContrastSensitiveStyle from './Main/applyMainContrastSensitiveStyle'\nimport applyLayersContrastSensitiveStyle from './Layers/applyLayersContrastSensitiveStyle'\nimport applyImagesContrastSensitiveStyle from './Images/applyImagesContrastSensitiveStyle'\nimport applyWidgetsContrastSensitiveStyle from './Widgets/applyWidgetsContrastSensitiveStyle'\n\nfunction toggleDarkMode(context) {\n  applyMainContrastSensitiveStyle(context)\n  applyLayersContrastSensitiveStyle(context)\n  applyImagesContrastSensitiveStyle(context)\n  applyWidgetsContrastSensitiveStyle(context)\n}\n\nexport default toggleDarkMode\n"
  },
  {
    "path": "src/UI/reference-ui/src/toggleUICollapsed.js",
    "content": "export function updateDrawer(context) {\n  context.drawer.opened = !context.uiCollapsed\n\n  const drawerChild = context.drawer.shadowRoot.children[0]\n  if (drawerChild)\n    drawerChild.style.width = context.drawer.opened\n      ? 'var(--_container-width)'\n      : ''\n}\n\nfunction toggleUICollapsed(context, event, actionMeta) {\n  if (!context.uiContainer) {\n    return\n  }\n  if (actionMeta) {\n    context.uiCollapsed =\n      actionMeta.state.value.active.uiCollapsed === 'enabled'\n  }\n\n  updateDrawer(context)\n\n  if (!context.uiCollapsed && context.images.selectedName) {\n    context.service.send({\n      type: 'SELECT_LAYER',\n      data: context.images.selectedName,\n    })\n  }\n\n  if (!context.use2D && !!context.main.planeUIGroup) {\n    if (context.uiCollapsed && context.main.viewMode === 'Volume') {\n      context.main.planeUIGroup.style.display = 'none'\n    } else {\n      context.main.planeUIGroup.style.display = 'block'\n    }\n  }\n}\n\nexport default toggleUICollapsed\n"
  },
  {
    "path": "src/UI/reference-ui/src/utils.js",
    "content": "export const makeHtml = htmlString => {\n  const template = document.createElement('template')\n  template.innerHTML = htmlString\n  return template.content.firstElementChild\n}\n"
  },
  {
    "path": "src/UI/reference-ui/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"outDir\": \"dist\",\n    \"target\": \"es2019\",\n    \"module\": \"es2020\",\n    \"moduleResolution\": \"node\",\n    \"lib\": [\"es2019\", \"dom\"],\n    \"declaration\": true,\n    \"declarationMap\": true,\n    \"experimentalDecorators\": true,\n    \"useDefineForClassFields\": false,\n    \"strict\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"node_modules\", \"**/*.spec.ts\"]\n}\n"
  },
  {
    "path": "src/UI/styleRenderingViewContainers.js",
    "content": "function applyStyle(el, style) {\n  Object.keys(style).forEach(key => {\n    el.style[key] = style[key]\n  })\n}\n\nfunction styleContainer(context, event) {\n  if (event.data) {\n    context.renderingViewContainerStyle = event.data\n  }\n  for (let container of context.renderingViewContainers.values()) {\n    applyStyle(container, context.renderingViewContainerStyle)\n  }\n}\n\nexport default styleContainer\n"
  },
  {
    "path": "src/UserInterface/CategoricalPresetNames.js",
    "content": "const CategoricalPresetNames = [\n  'glasbey',\n  'glasbey_light',\n  'glasbey_warm',\n  'modulate',\n\n  'glasbey_bw',\n  'glasbey_dark',\n  'glasbey_cool',\n  'modulate_dark',\n]\n\nexport default CategoricalPresetNames\n"
  },
  {
    "path": "src/UserInterface/Geometries/createGeometryColorBySelector.js",
    "content": "import { reaction } from 'mobx'\n\nimport style from '../ItkVtkViewer.module.css'\n\nimport {\n  ColorMode,\n  ScalarMode,\n} from 'vtk.js/Sources/Rendering/Core/Mapper/Constants'\n\nfunction createGeometryColorBySelector(store, colorByRow) {\n  const colorBySelector = document.createElement('select')\n  colorBySelector.setAttribute('class', style.selector)\n  colorBySelector.id = `${store.id}-colorBySelector`\n\n  reaction(\n    () => {\n      return store.geometriesUI.geometries.slice()\n    },\n    geometries => {\n      if (!!!geometries || geometries.length === 0) {\n        return\n      }\n\n      const hasScalars = store.geometriesUI.hasScalars\n      const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n      const colorByOptions = store.geometriesUI.colorByOptions\n\n      if (\n        store.geometriesUI.hasScalars[selectedGeometryIndex] &&\n        colorByOptions[selectedGeometryIndex].length > 1\n      ) {\n        colorByRow.style.display = 'flex'\n      } else {\n        colorByRow.style.display = 'none'\n      }\n\n      const colorByDefault = store.geometriesUI.colorByDefault\n      geometries.forEach((geometry, index) => {\n        if (store.geometriesUI.colorBy.length <= index) {\n          store.geometriesUI.colorBy.push(colorByDefault[index])\n        } else {\n          const current = store.geometriesUI.colorBy[index]\n          if (\n            !!store.geometriesUI.colorByOptions[index] &&\n            !!!store.geometriesUI.colorByOptions[index].filter(option => {\n              return (\n                option.label === current.label && option.value === current.value\n              )\n            }).length\n          ) {\n            store.geometriesUI.colorBy[index] = colorByDefault[index]\n          }\n        }\n      })\n\n      if (hasScalars[selectedGeometryIndex]) {\n        colorBySelector.value =\n          store.geometriesUI.colorBy[selectedGeometryIndex].value\n      }\n    }\n  )\n\n  reaction(\n    () => {\n      return store.geometriesUI.selectedGeometryIndex\n    },\n    selectedGeometryIndex => {\n      const colorByOptions = store.geometriesUI.colorByOptions\n\n      if (\n        !!colorByOptions[selectedGeometryIndex] &&\n        !!colorByOptions[selectedGeometryIndex].length\n      ) {\n        colorBySelector.innerHTML = colorByOptions[selectedGeometryIndex]\n          .map(\n            ({ label, value }) => `<option value=\"${value}\" >${label}</option>`\n          )\n          .join('')\n        colorBySelector.value =\n          store.geometriesUI.colorBy[selectedGeometryIndex].value\n      }\n      const hasScalars = store.geometriesUI.hasScalars\n      if (\n        hasScalars[selectedGeometryIndex] &&\n        colorByOptions[selectedGeometryIndex].length > 1\n      ) {\n        colorByRow.style.display = 'flex'\n      } else {\n        colorByRow.style.display = 'none'\n      }\n    }\n  )\n\n  reaction(\n    () => {\n      return store.geometriesUI.colorBy.slice()\n    },\n    colorBy => {\n      const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n      if (!!!colorBy[selectedGeometryIndex]) {\n        return\n      }\n      const [location, colorByArrayName] = colorBy[\n        selectedGeometryIndex\n      ].value.split(':')\n      const proxy =\n        store.geometriesUI.representationProxies[selectedGeometryIndex]\n      const interpolateScalarsBeforeMapping = location === 'pointData'\n      proxy.setInterpolateScalarsBeforeMapping(interpolateScalarsBeforeMapping)\n      proxy.setColorBy(colorByArrayName, location)\n      proxy.getMapper().setColorModeToDefault()\n      store.renderWindow.render()\n\n      const hasScalars = store.geometriesUI.hasScalars\n      if (hasScalars[selectedGeometryIndex]) {\n        colorBySelector.value =\n          store.geometriesUI.colorBy[selectedGeometryIndex].value\n      }\n    }\n  )\n\n  colorBySelector.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n    const colorByOptions = store.geometriesUI.colorByOptions\n    const selectedOption = store.geometriesUI.colorByOptions[\n      selectedGeometryIndex\n    ].filter(option => {\n      return option.value === event.target.value\n    })[0]\n    store.geometriesUI.colorBy[selectedGeometryIndex] = selectedOption\n  })\n\n  // Initialize coloring\n  const colorByDefault = store.geometriesUI.colorByDefault\n  colorByDefault.forEach((colorBy, index) => {\n    if (colorBy) {\n      const [location, colorByArrayName] = colorBy.value.split(':')\n      const proxy = store.geometriesUI.representationProxies[index]\n      const interpolateScalarsBeforeMapping = location === 'pointData'\n      proxy.setInterpolateScalarsBeforeMapping(interpolateScalarsBeforeMapping)\n      proxy.setColorBy(colorByArrayName, location)\n      proxy.getMapper().setColorModeToDefault()\n    }\n  })\n  const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n  const colorByOptions = store.geometriesUI.colorByOptions\n  if (colorByDefault[selectedGeometryIndex]) {\n    colorBySelector.innerHTML = colorByOptions[selectedGeometryIndex]\n      .map(({ label, value }) => `<option value=\"${value}\" >${label}</option>`)\n      .join('')\n    colorBySelector.value = colorByDefault[selectedGeometryIndex].value\n  }\n  if (\n    store.geometriesUI.hasScalars[selectedGeometryIndex] &&\n    colorByOptions[selectedGeometryIndex].length > 1\n  ) {\n    colorByRow.style.display = 'flex'\n  } else {\n    colorByRow.style.display = 'none'\n  }\n  store.geometriesUI.colorBy = colorByDefault\n\n  colorByRow.appendChild(colorBySelector)\n}\n\nexport default createGeometryColorBySelector\n"
  },
  {
    "path": "src/UserInterface/Geometries/createGeometryColorChooser.js",
    "content": "import { reaction } from 'mobx'\n\nimport style from '../ItkVtkViewer.module.css'\nimport hex2rgb from '../hex2rgb'\n\nfunction createGeometryColorChooser(store, geometryColorRow) {\n  const geometryColorInput = document.createElement('input')\n  geometryColorInput.setAttribute('type', 'color')\n  geometryColorInput.id = `${store.id}-geometryColorInput`\n\n  const defaultGeometryColor = '#ff0000'\n\n  reaction(\n    () => {\n      return store.geometriesUI.geometries.slice()\n    },\n    geometries => {\n      if (!!!geometries || geometries.length === 0) {\n        return\n      }\n\n      const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n\n      geometries.forEach((geometry, index) => {\n        if (store.geometriesUI.colors.length <= index) {\n          store.geometriesUI.colors.push(defaultGeometryColor)\n        }\n      })\n      geometryColorInput.value =\n        store.geometriesUI.colors[selectedGeometryIndex]\n    }\n  )\n\n  reaction(\n    () => {\n      return store.geometriesUI.selectedGeometryIndex\n    },\n    selectedGeometryIndex => {\n      geometryColorInput.value =\n        store.geometriesUI.colors[selectedGeometryIndex]\n      if (store.geometriesUI.hasScalars[selectedGeometryIndex]) {\n        geometryColorInput.style.display = 'none'\n      } else {\n        geometryColorInput.style.display = 'inline-block'\n      }\n    }\n  )\n\n  function applyColors(colors) {\n    colors.forEach((value, index) => {\n      const rgb = hex2rgb(value)\n      store.geometriesUI.representationProxies[index].setColor(rgb)\n    })\n    store.renderWindow.render()\n    const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n    geometryColorInput.value = colors[selectedGeometryIndex]\n  }\n  reaction(() => {\n    return store.geometriesUI.colors.slice()\n  }, applyColors)\n\n  geometryColorInput.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n    store.geometriesUI.colors[selectedGeometryIndex] = event.target.value\n  })\n\n  const defaultGeometryColors = Array(store.geometriesUI.geometries.length)\n  defaultGeometryColors.fill(defaultGeometryColor)\n  geometryColorInput.value = defaultGeometryColor\n  store.geometriesUI.colors = defaultGeometryColors\n  applyColors(store.geometriesUI.colors)\n  const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n  if (store.geometriesUI.hasScalars[selectedGeometryIndex]) {\n    geometryColorInput.style.display = 'none'\n  } else {\n    geometryColorInput.style.display = 'inline-block'\n  }\n\n  geometryColorRow.appendChild(geometryColorInput)\n}\n\nexport default createGeometryColorChooser\n"
  },
  {
    "path": "src/UserInterface/Geometries/createGeometryColorRangeInput.js",
    "content": "import { reaction, observable, action, toJS } from 'mobx'\n\nimport vtkLookupTableProxy from 'vtk.js/Sources/Proxy/Core/LookupTableProxy'\n\nimport style from '../ItkVtkViewer.module.css'\n\nimport createColorMapIconSelector from '../createColorMapIconSelector'\nimport customColorMapIcon from '../customColorMapIcon'\n\nfunction createColorRangeInput(store, uiContainer) {\n  const minimumInput = document.createElement('input')\n  minimumInput.type = 'number'\n  minimumInput.setAttribute('class', style.numberInput)\n  const maximumInput = document.createElement('input')\n  maximumInput.type = 'number'\n  maximumInput.setAttribute('class', style.numberInput)\n\n  function updateColorRangeInput() {\n    const selectedIndex = store.geometriesUI.selectedGeometryIndex\n    if (\n      !store.geometriesUI.hasScalars[selectedIndex] ||\n      store.geometriesUI.hasOnlyDirectColors[selectedIndex]\n    ) {\n      return\n    }\n    const colorByKey = store.geometriesUI.colorBy[selectedIndex].value\n    const [location, colorByArrayName] = colorByKey.split(':')\n    const geometry = store.geometriesUI.geometries[selectedIndex]\n    const dataArray =\n      location === 'pointData'\n        ? geometry.getPointData().getArrayByName(colorByArrayName)\n        : geometry.getCellData().getArrayByName(colorByArrayName)\n    const range = dataArray.getRange()\n\n    minimumInput.min = range[0]\n    minimumInput.max = range[1]\n    maximumInput.min = range[0]\n    maximumInput.max = range[1]\n    const data = dataArray.getData()\n    if (data instanceof Float32Array || data instanceof Float64Array) {\n      const step = (range[1] - range[0]) / 100.0\n      minimumInput.step = step\n      maximumInput.step = step\n    }\n\n    const colorRange = store.geometriesUI.selectedColorRange\n    minimumInput.value = colorRange[0]\n    maximumInput.value = colorRange[1]\n  }\n\n  function addColorRangesReactions(index, colorRanges) {\n    if (store.geometriesUI.colorRangesReactions.has(index)) {\n      const disposer = store.geometriesUI.colorRangesReactions.get(index)\n      disposer()\n    }\n    const disposer = reaction(\n      () => {\n        return toJS(store.geometriesUI.colorRanges)\n      },\n      colorRanges => {\n        if (index !== store.geometriesUI.selectedGeometryIndex) {\n          return\n        }\n        const colorRange = store.geometriesUI.selectedColorRange\n        if (!!colorRange) {\n          minimumInput.value = colorRange[0]\n          maximumInput.value = colorRange[1]\n          const lutProxy = store.geometriesUI.selectedLookupTableProxy\n          const colorTransferFunction = lutProxy.getLookupTable()\n          colorTransferFunction.setMappingRange(...colorRange)\n          colorTransferFunction.updateRange()\n          if (!store.renderWindow.getInteractor().isAnimating()) {\n            store.renderWindow.render()\n          }\n        }\n      }\n    )\n    store.geometriesUI.colorRangesReactions.set(index, disposer)\n  }\n\n  function setDefaultColorRangesColorMaps() {\n    const colorByOptions = store.geometriesUI.colorByOptions\n    if (!!!colorByOptions || colorByOptions.length === 0) {\n      return\n    }\n\n    const geometries = store.geometriesUI.geometries\n    colorByOptions.forEach((options, index) => {\n      const geometry = geometries[index]\n      if (!store.geometriesUI.colorRanges.has(index)) {\n        const colorRanges = observable(new Map())\n        if (options) {\n          options.forEach(option => {\n            const [location, colorByArrayName] = option.value.split(':')\n            const dataArray =\n              location === 'pointData'\n                ? geometry.getPointData().getArrayByName(colorByArrayName)\n                : geometry.getCellData().getArrayByName(colorByArrayName)\n            const range = dataArray.getRange()\n            colorRanges.set(option.value, range)\n          })\n        }\n        store.geometriesUI.colorRanges.set(index, colorRanges)\n        addColorRangesReactions(index, colorRanges)\n      } else {\n        // Constrain by min / max of possibly new inputs\n        const colorRanges = store.geometriesUI.colorRanges.get(index)\n        !!options &&\n          options.forEach(option => {\n            const [location, colorByArrayName] = option.value.split(':')\n            const dataArray =\n              location === 'pointData'\n                ? geometry.getPointData().getArrayByName(colorByArrayName)\n                : geometry.getCellData().getArrayByName(colorByArrayName)\n            const range = dataArray.getRange()\n\n            if (colorRanges.has(option.value)) {\n              const current = colorRanges.get(option.value)\n              if (current[0] < range[0] || current[1] > range[1]) {\n                const newRange = current.slice()\n                if (current[0] < range[0]) {\n                  newRange[0] = range[0]\n                }\n                if (current[1] > range[1]) {\n                  newRange[1] = range[1]\n                }\n                colorRanges.set(option.value, newRange)\n              }\n            } else {\n              colorRanges.set(option.value, range)\n            }\n          })\n        addColorRangesReactions(index, colorRanges)\n      }\n      if (store.geometriesUI.colorMaps.length <= index) {\n        const defaultColorMap = 'Viridis (matplotlib)'\n        store.geometriesUI.colorMaps.push(defaultColorMap)\n        const lutProxy = store.geometriesUI.selectedLookupTableProxy\n        if (!!lutProxy) {\n          lutProxy.setPresetName(defaultColorMap)\n        }\n      }\n      if (store.geometriesUI.colorMaps.length <= index) {\n        const defaultColorMap = 'Viridis (matplotlib)'\n        store.geometriesUI.colorMaps.push(defaultColorMap)\n        const lutProxy = store.geometriesUI.selecetdLookupTableProxy\n        if (!!lutProxy) {\n          lutProxy.setPresetName(defaultColorMap)\n        }\n      }\n    })\n    updateColorRangeInput()\n  }\n\n  setDefaultColorRangesColorMaps()\n\n  reaction(\n    () => {\n      return store.geometriesUI.selectedColorRange\n    },\n    colorRange => {\n      if (!!colorRange) {\n        minimumInput.value = colorRange[0]\n        maximumInput.value = colorRange[1]\n        const lutProxy = store.geometriesUI.selectedLookupTableProxy\n        const colorTransferFunction = lutProxy.getLookupTable()\n        colorTransferFunction.setMappingRange(...colorRange)\n        colorTransferFunction.updateRange()\n      }\n    }\n  )\n\n  minimumInput.addEventListener(\n    'change',\n    action(event => {\n      event.preventDefault()\n      event.stopPropagation()\n      const selectedIndex = store.geometriesUI.selectedGeometryIndex\n      const colorByKey = store.geometriesUI.colorBy[selectedIndex].value\n      const range = store.geometriesUI.colorRanges\n        .get(selectedIndex)\n        .get(colorByKey)\n      range[0] = Number(event.target.value)\n      store.geometriesUI.colorRanges.get(selectedIndex).set(colorByKey, range)\n    })\n  )\n  maximumInput.addEventListener(\n    'change',\n    action(event => {\n      event.preventDefault()\n      event.stopPropagation()\n      const selectedIndex = store.geometriesUI.selectedGeometryIndex\n      const colorByKey = store.geometriesUI.colorBy[selectedIndex].value\n      const range = store.geometriesUI.colorRanges\n        .get(selectedIndex)\n        .get(colorByKey)\n      range[1] = Number(event.target.value)\n      store.geometriesUI.colorRanges.get(selectedIndex).set(colorByKey, range)\n    })\n  )\n\n  const colorMapSelector = document.createElement('div')\n  colorMapSelector.id = `${store.id}-geometryColorMapSelector`\n\n  const iconSelector = createColorMapIconSelector(colorMapSelector)\n\n  function updateColorCanvas() {\n    const geometryIndex = store.geometriesUI.selectedGeometryIndex\n    if (\n      !store.geometriesUI.hasScalars[selectedIndex] ||\n      store.geometriesUI.hasOnlyDirectColors[geometryIndex]\n    ) {\n      return\n    }\n    const colorMap = store.geometriesUI.colorMaps[geometryIndex]\n    const lookupTableProxy = store.geometriesUI.selectedLookupTableProxy\n    const colorTransferFunction = lookupTableProxy.getLookupTable()\n\n    if (colorMap.startsWith('Custom')) {\n      lookupTableProxy.setMode(vtkLookupTableProxy.Mode.RGBPoints)\n      const colorRange = store.geometriesUI.selectedColorRange\n      const isIcons = iconSelector.getIcons()\n      if (!!!customIcon) {\n        const colorMapIcon = customColorMapIcon(\n          colorTransferFunction,\n          colorDataRange\n        )\n        customIcon = { iconFilePath: colorMapIcon, iconValue: colorMap }\n        icons.push(customIcon)\n        iconSelector.refresh(icons)\n      } else if (isIcons[isIcons.length - 1].iconValue !== colorMap) {\n        const colorMapIcon = customColorMapIcon(\n          colorTransferFunction,\n          colorDataRange\n        )\n        isIcons[isIcons.length - 1].element.src = colorMapIcon\n        isIcons[isIcons.length - 1].iconFilePath = colorMapIcon\n        isIcons[isIcons.length - 1].iconValue = colorMap\n        isIcons[isIcons.length - 1].element.setAttribute('icon-value', colorMap)\n        isIcons[isIcons.length - 1].element.setAttribute('alt', colorMap)\n        isIcons[isIcons.length - 1].element.setAttribute('title', colorMap)\n      }\n    } else {\n      lookupTableProxy.setPresetName(colorMap)\n      lookupTableProxy.setMode(vtkLookupTableProxy.Mode.Preset)\n    }\n    iconSelector.setSelectedValue(colorMap)\n    if (!store.renderWindow.getInteractor().isAnimating()) {\n      store.renderWindow.render()\n    }\n  }\n  let customIcon = null\n  reaction(\n    () => {\n      return store.geometriesUI.colorMaps.slice()\n    },\n    colorMaps => {\n      updateColorCanvas()\n    }\n  )\n  colorMapSelector.addEventListener('changed', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const geometryIndex = store.geometriesUI.selectedGeometryIndex\n    store.geometriesUI.colorMaps[\n      geometryIndex\n    ] = iconSelector.getSelectedValue()\n  })\n  const geometryIndex = store.geometriesUI.selectedGeometryIndex\n  iconSelector.setSelectedValue(store.geometriesUI.colorMaps[geometryIndex])\n\n  reaction(\n    () => {\n      return store.geometriesUI.colorByOptions.slice()\n    },\n    () => {\n      setDefaultColorRangesColorMaps()\n    }\n  )\n\n  reaction(\n    () => {\n      return store.geometriesUI.selectedGeometryIndex\n    },\n    selectedIndex => {\n      const directColors = store.geometriesUI.hasOnlyDirectColors\n      if (directColors[selectedIndex]) {\n        uiContainer.style.display = 'flex'\n        updateColorRangeInput()\n        updateColorCanvas()\n      } else {\n        uiContainer.style.display = 'none'\n      }\n    }\n  )\n  reaction(\n    () => {\n      return store.geometriesUI.colorBy.slice()\n    },\n    () => {\n      updateColorRangeInput()\n      updateColorCanvas()\n    }\n  )\n\n  updateColorCanvas()\n  const directColors = store.geometriesUI.hasOnlyDirectColors\n  const selectedIndex = store.geometriesUI.selectedGeometryIndex\n  if (directColors[selectedIndex]) {\n    uiContainer.style.display = 'flex'\n  } else {\n    uiContainer.style.display = 'none'\n  }\n\n  uiContainer.appendChild(minimumInput)\n  uiContainer.appendChild(colorMapSelector)\n  uiContainer.appendChild(maximumInput)\n}\n\nexport default createColorRangeInput\n"
  },
  {
    "path": "src/UserInterface/Geometries/createGeometryColorWidget.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport createGeometryColorChooser from './createGeometryColorChooser'\nimport createGeometryOpacitySlider from './createGeometryOpacitySlider'\nimport createGeometryColorBySelector from './createGeometryColorBySelector'\nimport createGeometryColorRangeInput from './createGeometryColorRangeInput'\n\nfunction createGeometryColorWidget(store, geometriesUIGroup) {\n  const colorByRow = document.createElement('div')\n  colorByRow.setAttribute('class', style.uiRow)\n  colorByRow.className += ` ${store.id}-collapsible`\n  createGeometryColorBySelector(store, colorByRow)\n  geometriesUIGroup.appendChild(colorByRow)\n\n  const geometryColorRow = document.createElement('div')\n  geometryColorRow.setAttribute('class', style.uiRow)\n  geometryColorRow.className += ` ${store.id}-collapsible`\n\n  createGeometryColorChooser(store, geometryColorRow)\n\n  createGeometryOpacitySlider(store, geometryColorRow)\n  geometriesUIGroup.appendChild(geometryColorRow)\n\n  const colorRangeInputRow = document.createElement('div')\n  colorRangeInputRow.setAttribute('class', style.uiRow)\n  createGeometryColorRangeInput(store, colorRangeInputRow)\n  colorRangeInputRow.className += ` ${store.id}-collapsible`\n  geometriesUIGroup.appendChild(colorRangeInputRow)\n\n  if (store.mainUI.collapsed) {\n    colorByRow.style.display = 'none'\n    geometryColorRow.style.display = 'none'\n    geometriesUIGroup.style.display = 'none'\n  }\n}\n\nexport default createGeometryColorWidget\n"
  },
  {
    "path": "src/UserInterface/Geometries/createGeometryOpacitySlider.js",
    "content": "import { reaction, action } from 'mobx'\n\nimport style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyle from '../applyContrastSensitiveStyle'\n\nimport opacityIcon from '../icons/opacity.svg'\n\nfunction createGeometryOpacitySlider(store, geometryColorRow) {\n  const defaultGeometryOpacity = 1.0\n\n  const sliderEntry = document.createElement('div')\n  sliderEntry.setAttribute('class', style.sliderEntry)\n  sliderEntry.innerHTML = `\n    <div itk-vtk-tooltip itk-vtk-tooltip-bottom itk-vtk-tooltip-content=\"Opacity\" class=\"${style.gradientOpacitySlider}\">\n      ${opacityIcon}\n    </div>\n    <input type=\"range\" min=\"0\" max=\"1\" value=\"${defaultGeometryOpacity}\" step=\"0.01\"\n      id=\"${store.id}-geometryOpacitySlider\"\n      class=\"${style.slider}\" />`\n  const opacityElement = sliderEntry.querySelector(\n    `#${store.id}-geometryOpacitySlider`\n  )\n  const sliderEntryDiv = sliderEntry.children[0]\n  applyContrastSensitiveStyle(store, 'invertibleButton', sliderEntryDiv)\n\n  reaction(\n    () => {\n      return store.geometriesUI.geometries.slice()\n    },\n    geometries => {\n      if (!!!geometries || geometries.length === 0) {\n        return\n      }\n\n      geometries.forEach((geometry, index) => {\n        if (store.geometriesUI.opacities.length <= index) {\n          store.geometriesUI.opacities.push(defaultGeometryOpacity)\n        }\n      })\n      const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n      opacityElement.value = store.geometriesUI.opacities[selectedGeometryIndex]\n    }\n  )\n\n  reaction(\n    () => {\n      return store.geometriesUI.selectedGeometryIndex\n    },\n    selectedGeometryIndex => {\n      opacityElement.value = store.geometriesUI.opacities[selectedGeometryIndex]\n    }\n  )\n\n  function applyOpacities(opacities) {\n    opacities.forEach((opacity, index) => {\n      store.geometriesUI.representationProxies[index].setOpacity(opacity)\n    })\n\n    store.renderWindow.render()\n    const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n    opacityElement.value = opacities[selectedGeometryIndex]\n  }\n\n  reaction(() => {\n    return store.geometriesUI.opacities.slice()\n  }, applyOpacities)\n\n  opacityElement.addEventListener(\n    'input',\n    action(event => {\n      event.preventDefault()\n      event.stopPropagation()\n      const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n      store.geometriesUI.opacities[selectedGeometryIndex] = Number(\n        event.target.value\n      )\n    })\n  )\n\n  const defaultGeometryOpacities = new Array(\n    store.geometriesUI.geometries.length\n  )\n  defaultGeometryOpacities.fill(defaultGeometryOpacity)\n  opacityElement.value = defaultGeometryOpacity\n  store.geometriesUI.opacities = defaultGeometryOpacities\n  applyOpacities(store.geometriesUI.opacities)\n\n  geometryColorRow.appendChild(sliderEntry)\n}\n\nexport default createGeometryOpacitySlider\n"
  },
  {
    "path": "src/UserInterface/Geometries/createGeometryRepresentationSelector.js",
    "content": "import { reaction } from 'mobx'\n\nimport style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyle from '../applyContrastSensitiveStyle'\n\nimport hiddenIcon from '../icons/hidden.svg'\nimport wireframeIcon from '../icons/geometry-wireframe.svg'\nimport surfaceIcon from '../icons/geometry-surface.svg'\nimport surfaceWithEdgesIcon from '../icons/geometry-surface-with-edges.svg'\n\nfunction createGeometryRepresentationSelector(\n  store,\n  geometryRepresentationRow\n) {\n  const viewerDOMId = store.id\n\n  const geometryHiddenButton = document.createElement('div')\n  geometryHiddenButton.innerHTML = `<input id=\"${viewerDOMId}-geometryHiddenButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Hidden\" class=\"${style.fullscreenButton} ${style.toggleButton}\" for=\"${viewerDOMId}-geometryHiddenButton\">${hiddenIcon}</label>`\n  geometryHiddenButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n    store.geometriesUI.representations[selectedGeometryIndex] = 'Hidden'\n  })\n  geometryRepresentationRow.appendChild(geometryHiddenButton)\n  const geometryHiddenButtonInput = geometryHiddenButton.children[0]\n  const geometryHiddenButtonLabel = geometryHiddenButton.children[1]\n  applyContrastSensitiveStyle(store, 'tooltipButton', geometryHiddenButtonLabel)\n\n  const geometryWireframeButton = document.createElement('div')\n  geometryWireframeButton.innerHTML = `<input id=\"${viewerDOMId}-geometryWireframeButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Wireframe\" class=\"${style.fullscreenButton} ${style.toggleButton}\" for=\"${viewerDOMId}-geometryWireframeButton\">${wireframeIcon}</label>`\n  geometryWireframeButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n    store.geometriesUI.representations[selectedGeometryIndex] = 'Wireframe'\n  })\n  geometryRepresentationRow.appendChild(geometryWireframeButton)\n  const geometryWireframeButtonInput = geometryWireframeButton.children[0]\n  const geometryWireframeButtonLabel = geometryWireframeButton.children[1]\n  applyContrastSensitiveStyle(\n    store,\n    'tooltipButton',\n    geometryWireframeButtonLabel\n  )\n\n  const geometrySurfaceButton = document.createElement('div')\n  geometrySurfaceButton.innerHTML = `<input id=\"${viewerDOMId}-geometrySurfaceButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Surface\" class=\"${style.fullscreenButton} ${style.toggleButton}\" for=\"${viewerDOMId}-geometrySurfaceButton\">${surfaceIcon}</label>`\n  geometrySurfaceButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n    store.geometriesUI.representations[selectedGeometryIndex] = 'Surface'\n  })\n  geometryRepresentationRow.appendChild(geometrySurfaceButton)\n  const geometrySurfaceButtonInput = geometrySurfaceButton.children[0]\n  const geometrySurfaceButtonLabel = geometrySurfaceButton.children[1]\n  applyContrastSensitiveStyle(\n    store,\n    'tooltipButton',\n    geometrySurfaceButtonLabel\n  )\n\n  const geometrySurfaceWithEdgesButton = document.createElement('div')\n  geometrySurfaceWithEdgesButton.innerHTML = `<input id=\"${viewerDOMId}-geometrySurfaceWithEdgesButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-left itk-vtk-tooltip-content=\"Surface with edges\" class=\"${style.viewModeButton} ${style.toggleButton}\" for=\"${viewerDOMId}-geometrySurfaceWithEdgesButton\">${surfaceWithEdgesIcon}</label>`\n  geometrySurfaceWithEdgesButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n    store.geometriesUI.representations[selectedGeometryIndex] =\n      'Surface with edges'\n  })\n  geometryRepresentationRow.appendChild(geometrySurfaceWithEdgesButton)\n  const geometrySurfaceWithEdgesButtonInput =\n    geometrySurfaceWithEdgesButton.children[0]\n  const geometrySurfaceWithEdgesButtonLabel =\n    geometrySurfaceWithEdgesButton.children[1]\n  applyContrastSensitiveStyle(\n    store,\n    'tooltipButton',\n    geometrySurfaceWithEdgesButtonLabel\n  )\n\n  function updateEnabledRepresentationButtons(selectedGeometryRepresentation) {\n    switch (selectedGeometryRepresentation) {\n      case 'Hidden':\n        geometryHiddenButtonInput.checked = true\n        geometryWireframeButtonInput.checked = false\n        geometrySurfaceButtonInput.checked = false\n        geometrySurfaceWithEdgesButtonInput.checked = false\n        break\n      case 'Wireframe':\n        geometryHiddenButtonInput.checked = false\n        geometryWireframeButtonInput.checked = true\n        geometrySurfaceButtonInput.checked = false\n        geometrySurfaceWithEdgesButtonInput.checked = false\n        break\n      case 'Surface':\n        geometryHiddenButtonInput.checked = false\n        geometryWireframeButtonInput.checked = false\n        geometrySurfaceButtonInput.checked = true\n        geometrySurfaceWithEdgesButtonInput.checked = false\n        break\n      case 'Surface with edges':\n        geometryHiddenButtonInput.checked = false\n        geometryWireframeButtonInput.checked = false\n        geometrySurfaceButtonInput.checked = false\n        geometrySurfaceWithEdgesButtonInput.checked = true\n        break\n      default:\n        console.error(\n          'Invalid geometry representation: ' + selectedGeometryRepresentation\n        )\n    }\n  }\n\n  function setRepresentation(value, index) {\n    if (value === 'Hidden') {\n      store.geometriesUI.representationProxies[index].setVisibility(false)\n    } else {\n      store.geometriesUI.representationProxies[index].setRepresentation(value)\n      store.geometriesUI.representationProxies[index].setVisibility(true)\n    }\n    updateEnabledRepresentationButtons(value)\n    store.renderWindow.render()\n  }\n\n  reaction(\n    () => {\n      return store.geometriesUI.representations.slice()\n    },\n    representations => {\n      const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n      const representation =\n        store.geometriesUI.representations[selectedGeometryIndex]\n      setRepresentation(representation, selectedGeometryIndex)\n      store.renderWindow.render()\n    }\n  )\n\n  reaction(\n    () => {\n      return store.geometriesUI.selectedGeometryIndex\n    },\n    selectedIndex => {\n      const selectedGeometryRepresentation =\n        store.geometriesUI.representations[selectedIndex]\n      updateEnabledRepresentationButtons(selectedGeometryRepresentation)\n    }\n  )\n\n  const defaultGeometryRepresentation = 'Surface'\n\n  reaction(\n    () => {\n      return store.geometriesUI.geometries.slice()\n    },\n    geometries => {\n      if (!!!geometries || geometries.length === 0) {\n        return\n      }\n\n      geometries.forEach((geometry, index) => {\n        if (store.geometriesUI.representations.length <= index) {\n          store.geometriesUI.representations.push(defaultGeometryRepresentation)\n        }\n      })\n      const selectedGeometryIndex = store.geometriesUI.selectedGeometryIndex\n      updateEnabledRepresentationButtons(\n        store.geometriesUI.representations[selectedGeometryIndex]\n      )\n    }\n  )\n\n  const defaultGeometryRepresentations = new Array(\n    store.geometriesUI.geometries.length\n  )\n  defaultGeometryRepresentations.fill(defaultGeometryRepresentation)\n  updateEnabledRepresentationButtons(defaultGeometryRepresentation)\n  store.geometriesUI.representations = defaultGeometryRepresentations\n}\n\nexport default createGeometryRepresentationSelector\n"
  },
  {
    "path": "src/UserInterface/ItkVtkViewer.module.css",
    "content": ".loading {\n  border: 16px solid #f3f3f3; /* Light grey */\n  border-top: 16px solid #3498db; /* Blue */\n  border-radius: 50%;\n  width: 120px;\n  height: 120px;\n  position: absolute;\n  left: calc(50% - 60px);\n  top: calc(50% - 60px);\n  animation: spin 2s linear infinite;\n  box-sizing: border-box;\n}\n\n@keyframes spin {\n  0% {\n    transform: rotate(0deg);\n  }\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n.uiContainer {\n  display: flex;\n  align-items: stretch;\n  flex-direction: column;\n  justify-content: space-between;\n  position: absolute;\n  top: 5px;\n  left: 5px;\n  padding: 2px;\n  border: 0px;\n  box-sizing: border-box;\n  z-index: 1000;\n}\n\n.uiGroup {\n  background: rgba(128, 128, 128, 0.5);\n  border-radius: 4px;\n  margin: 2px;\n}\n\n.uiRow {\n  display: flex;\n  flex-direction: row;\n  flex: 1;\n  align-items: center;\n  justify-content: space-between;\n  padding: 5px;\n}\n\n.mainUIRow {\n  composes: uiRow;\n  justify-content: space-around;\n  max-width: 420px;\n}\n\n.progress {\n  color: white;\n  font-size: 200%;\n  height: 100vh;\n  width: 100vw;\n  text-align: center;\n  vertical-align: middle;\n  line-height: 100vh;\n}\n\n.piecewiseWidget {\n  flex: 1;\n  background: rgba(255, 255, 255, 0.2);\n  border-radius: 3px;\n  z-index: 1000;\n}\n\n.logo {\n  position: absolute;\n  top: 5px;\n  right: 5px;\n  height: 2em;\n  width: 2em;\n  cursor: pointer;\n  z-index: 100;\n}\n\n.fpsMonitor {\n  position: absolute;\n  top: 5px;\n  right: 5px;\n  border-radius: 5px;\n  background: rgba(255, 255, 255, 0.6);\n  cursor: pointer;\n  z-index: 101;\n}\n\n[itk-vtk-tooltip] {\n  position: relative;\n}\n[itk-vtk-tooltip]::before {\n  content: attr(itk-vtk-tooltip-content);\n  visibility: hidden;\n  position: absolute;\n  top: 50%;\n  right: calc(100% + 16px);\n  width: 400%;\n  padding: 4px 6px;\n  text-align: center;\n  text-transform: none;\n  font-size: 0.9em;\n  font-family: monospace;\n  border-radius: 3px;\n  background: rgba(0.9, 0.9, 0.9, 0.95);\n  color: white;\n  opacity: 0;\n  transform: translate(15px, -50%);\n  transition-property: all;\n  transition-duration: 0.3s;\n  transition-timing-function: ease-in-out;\n  transition-delay: 0.8s;\n  z-index: 1;\n}\n\n[itk-vtk-tooltip]:hover::before {\n  opacity: 1;\n  visibility: visible;\n  transform: translate(0, -50%);\n}\n\n[itk-vtk-tooltip-bottom]::before {\n  top: calc(100% + 16px);\n  left: 50%;\n  right: initial;\n  transform: translate(-50%, -15px);\n}\n[itk-vtk-tooltip-bottom]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-right]::before {\n  top: 50%;\n  left: calc(100% + 16px);\n  right: initial;\n  transform: translate(-15px, -50%);\n}\n[itk-vtk-tooltip-right]:hover::before {\n  transform: translate(0, -50%);\n}\n\n[itk-vtk-tooltip-top-screenshot]::before {\n  top: initial;\n  left: 260%;\n  right: initial;\n  bottom: calc(100% + 8px);\n  transform: translate(-50%, 15px);\n}\n[itk-vtk-tooltip-top-screenshot]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top-annotation]::before {\n  top: initial;\n  left: 160%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n}\n[itk-vtk-tooltip-top-annotation]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top-axes]::before {\n  top: initial;\n  left: 160%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n}\n[itk-vtk-tooltip-top-axes]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top-fullscreen]::before {\n  top: initial;\n  left: 120%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n  width: 400%;\n}\n[itk-vtk-tooltip-top-fullscreen]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top]::before {\n  top: initial;\n  left: 60%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n}\n[itk-vtk-tooltip-top]:hover::before {\n  transform: translate(-50%, 0);\n}\n[itk-vtk-tooltip-top-fullscreen]::before {\n  top: initial;\n  left: 120%;\n  right: initial;\n  bottom: calc(100% + 10px);\n  transform: translate(-50%, 15px);\n  width: 400%;\n}\n\n.tooltipButtonBrightBG::before {\n}\n\n.tooltipButtonDarkBG::before {\n  filter: invert(100%);\n  -webkit-filter: invert(100%);\n}\n\n.invertibleButtonBrightBG {\n}\n\n.invertibleButtonDarkBG {\n  filter: invert(100%);\n  -webkit-filter: invert(100%);\n}\n\n.toggleUserInterfaceButton {\n  height: 1.5em;\n  width: 1.5em;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.screenshotButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.screenshotButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.annotationButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.annotationButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.axesButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.axesButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.fullscreenButton {\n  flex: 1;\n  width: 8m;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.fullscreenButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.interpolationButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.interpolationButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.cropButton {\n  flex: 1;\n  height: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.cropButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.resetCropButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.resetCropButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.distanceEntry {\n  flex: 1;\n  display: flex;\n  flex-direction: row;\n  align-items: self-start;\n}\n\n.distanceButton {\n  flex: 1;\n  height: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.distanceButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.distanceLabelCommon {\n  border: none;\n  background: transparent;\n  font-size: 1.2em;\n  margin-right: 10px;\n  z-index: 1000;\n}\n\n.distanceLabelBrightBG {\n  color: black;\n}\n\n.distanceLabelDarkBG {\n  color: white;\n}\n\n.distanceInput {\n  background: transparent;\n  color: white;\n  font-size: 1em;\n  width: 80px;\n}\n\n.resetCameraButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.resetCameraButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.bgColorButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.bgColorButton svg {\n  height: 1.2em;\n  width: 1.2em;\n}\n\n.viewModeButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 6px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.viewModeButton svg {\n  width: 1.3em;\n  height: 1.3em;\n}\n\n.shadowButton {\n  width: 8mm;\n  padding: 4px;\n  padding-left: 0px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.shadowButton svg {\n  width: 1.3em;\n  height: 1.3em;\n}\n\n.viewPlanesButton {\n  flex: 1;\n  width: 8mm;\n  padding-top: 2px;\n  padding-bottom: 2px;\n  padding-left: 0px;\n  padding-right: 6px;\n  cursor: pointer;\n  z-index: 1000;\n}\n\n.viewPlanesButton svg {\n  width: 1.3em;\n  height: 1.3em;\n}\n\n.toggleInput {\n  margin: 0px;\n  width: 0%;\n  opacity: 0;\n  box-sizing: content-box;\n}\n\n.toggleButton {\n  cursor: pointer;\n  border-radius: 0.2em;\n  opacity: 0.45;\n}\n\ninput:checked.toggleInput + label {\n  opacity: 1;\n}\n\n.numberInput {\n  color: white;\n  background: transparent;\n  font-size: 1em;\n  width: 80px;\n}\n\n.selector {\n  display: flex;\n  direction: row;\n  font-size: 1.2em;\n  z-index: 1000;\n}\n\n.componentTab {\n  position: absolute;\n  opacity: 0;\n  pointer-events: none;\n}\n\n.componentDisabled {\n  pointer-events: none;\n  opacity: 0.5;\n}\n\n.componentTab + .compTabLabel {\n  background: rgba(40, 40, 40, 0.5);\n  padding: 5px;\n  margin-right: 2px;\n  border-radius: 5px 5px 0px 0px;\n  color: #777;\n}\n\n.componentTab:hover + .compTabLabel {\n  background: rgba(90, 90, 90, 0.5);\n}\n\n.componentTab:checked + .compTabLabel {\n  background: rgba(127, 127, 127, 0.5);\n  color: #fff;\n}\n\n.componentVisibility {\n  position: relative;\n  top: -2px;\n  margin-left: 10px;\n}\n\nselect {\n  -moz-appearance: none;\n}\n\nselect option {\n  color: black;\n}\n\nselect:focus {\n  outline: none;\n  border: none;\n}\n\n.sampleDistanceButton {\n  width: 8mm;\n  padding: 4px;\n  padding-left: 6px;\n  z-index: 1000;\n}\n\n.sampleDistanceButton svg {\n  width: 1.2em;\n  height: 1.2em;\n}\n\n.blendModeButton {\n  width: 8mm;\n  padding: 4px;\n  padding-left: 8px;\n  padding-right: 0px;\n  z-index: 1000;\n}\n\n.blendModeButton svg {\n  width: 1.2em;\n  height: 1.2em;\n}\n\n.gradientOpacitySlider {\n  width: 8mm;\n  padding: 4px;\n  padding-left: 6px;\n  padding-right: 0px;\n  z-index: 1000;\n}\n\n.gradientOpacitySlider svg {\n  width: 1.2em;\n  height: 1.2em;\n}\n\n.sliderEntry {\n  flex: 1;\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n}\n\n.slider {\n  flex: 1;\n  min-height: 1rem;\n  width: 5px;\n}\n\n.sliderLabelCommon {\n  padding-left: 6px;\n  padding-right: 6px;\n  font-size: 1.1em;\n  font-family: monospace;\n}\n\n.sliderLabelBrightBG {\n  color: black;\n}\n\n.sliderLabelDarkBG {\n  color: white;\n}\n\n.bigFileDrop {\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  transform: translate(-50%, -50%);\n  background-color: white;\n  background-image: url('./dropBG.jpg');\n  background-repeat: no-repeat;\n  background-position: center;\n  background-size: contain;\n  border-radius: 10px;\n  width: 50px;\n  padding: calc(50vh - 2em) calc(50vw - 25px - 2em);\n}\n\n.fullscreenContainer {\n  position: absolute;\n  width: 100vw;\n  height: 100vh;\n  top: 0;\n  left: 0;\n  overflow: hidden;\n  background: black;\n  margin: 0;\n  padding: 0;\n}\n"
  },
  {
    "path": "src/UserInterface/PointSets/createPointSetColorBySelector.js",
    "content": "import { reaction } from 'mobx'\n\nimport style from '../ItkVtkViewer.module.css'\n\nimport {\n  ColorMode,\n  ScalarMode,\n} from 'vtk.js/Sources/Rendering/Core/Mapper/Constants'\n\nfunction createPointSetColorBySelector(store, colorByRow) {\n  const colorBySelector = document.createElement('select')\n  colorBySelector.setAttribute('class', style.selector)\n  colorBySelector.id = `${store.id}-colorBySelector`\n\n  reaction(\n    () => {\n      return store.pointSetsUI.pointSets.slice()\n    },\n    pointSets => {\n      if (!!!pointSets || pointSets.length === 0) {\n        return\n      }\n\n      const hasScalars = store.pointSetsUI.hasScalars\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      const colorByOptions = store.pointSetsUI.colorByOptions\n\n      if (\n        store.pointSetsUI.hasScalars[selectedPointSetIndex] &&\n        colorByOptions[selectedPointSetIndex].length > 1\n      ) {\n        colorByRow.style.display = 'flex'\n      } else {\n        colorByRow.style.display = 'none'\n      }\n\n      const colorByDefault = store.pointSetsUI.colorByDefault\n      pointSets.forEach((pointSet, index) => {\n        if (store.pointSetsUI.colorBy.length <= index) {\n          store.pointSetsUI.colorBy.push(colorByDefault[index])\n        } else {\n          const current = store.pointSetsUI.colorBy[index]\n          if (\n            !!store.pointSetsUI.colorByOptions[index] &&\n            !!!store.pointSetsUI.colorByOptions[index].filter(option => {\n              return (\n                option.label === current.label && option.value === current.value\n              )\n            }).length\n          ) {\n            store.pointSetsUI.colorBy[index] = colorByDefault[index]\n          }\n        }\n      })\n\n      if (hasScalars[selectedPointSetIndex]) {\n        colorBySelector.value =\n          store.pointSetsUI.colorBy[selectedPointSetIndex].value\n      }\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.selectedPointSetIndex\n    },\n    selectedPointSetIndex => {\n      const colorByOptions = store.pointSetsUI.colorByOptions\n\n      if (\n        !!colorByOptions[selectedPointSetIndex] &&\n        !!colorByOptions[selectedPointSetIndex].length\n      ) {\n        colorBySelector.innerHTML = colorByOptions[selectedPointSetIndex]\n          .map(\n            ({ label, value }) => `<option value=\"${value}\" >${label}</option>`\n          )\n          .join('')\n        colorBySelector.value =\n          store.pointSetsUI.colorBy[selectedPointSetIndex].value\n      }\n      const hasScalars = store.pointSetsUI.hasScalars\n      if (\n        hasScalars[selectedPointSetIndex] &&\n        colorByOptions[selectedPointSetIndex].length > 1\n      ) {\n        colorByRow.style.display = 'flex'\n      } else {\n        colorByRow.style.display = 'none'\n      }\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.colorBy.slice()\n    },\n    colorBy => {\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      if (!!!colorBy[selectedPointSetIndex]) {\n        return\n      }\n      const [location, colorByArrayName] = colorBy[\n        selectedPointSetIndex\n      ].value.split(':')\n      const proxy =\n        store.pointSetsUI.representationProxies[selectedPointSetIndex]\n      const interpolateScalarsBeforeMapping = location === 'pointData'\n      proxy.setInterpolateScalarsBeforeMapping(interpolateScalarsBeforeMapping)\n      proxy.setColorBy(colorByArrayName, location)\n      store.renderWindow.render()\n\n      const hasScalars = store.pointSetsUI.hasScalars\n      if (hasScalars[selectedPointSetIndex]) {\n        colorBySelector.value =\n          store.pointSetsUI.colorBy[selectedPointSetIndex].value\n      }\n    }\n  )\n\n  colorBySelector.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n    const colorByOptions = store.pointSetsUI.colorByOptions\n    const selectedOption = store.pointSetsUI.colorByOptions[\n      selectedPointSetIndex\n    ].filter(option => {\n      return option.value === event.target.value\n    })[0]\n    store.pointSetsUI.colorBy[selectedPointSetIndex] = selectedOption\n  })\n\n  // Initialize coloring\n  const colorByDefault = store.pointSetsUI.colorByDefault\n  colorByDefault.forEach((colorBy, index) => {\n    if (colorBy) {\n      const [location, colorByArrayName] = colorBy.value.split(':')\n      const proxy = store.pointSetsUI.representationProxies[index]\n      const interpolateScalarsBeforeMapping = location === 'pointData'\n      proxy.setInterpolateScalarsBeforeMapping(interpolateScalarsBeforeMapping)\n      proxy.setColorBy(colorByArrayName, location)\n    }\n  })\n  const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n  const colorByOptions = store.pointSetsUI.colorByOptions\n  if (colorByDefault[selectedPointSetIndex]) {\n    colorBySelector.innerHTML = colorByOptions[selectedPointSetIndex]\n      .map(({ label, value }) => `<option value=\"${value}\" >${label}</option>`)\n      .join('')\n    colorBySelector.value = colorByDefault[selectedPointSetIndex].value\n  }\n  const hasScalars = store.pointSetsUI.hasScalars\n  if (\n    hasScalars[selectedPointSetIndex] &&\n    colorByOptions[selectedPointSetIndex].length > 1\n  ) {\n    colorByRow.style.display = 'flex'\n  } else {\n    colorByRow.style.display = 'none'\n  }\n  store.pointSetsUI.colorBy = colorByDefault\n\n  colorByRow.appendChild(colorBySelector)\n}\n\nexport default createPointSetColorBySelector\n"
  },
  {
    "path": "src/UserInterface/PointSets/createPointSetColorChooser.js",
    "content": "import { reaction } from 'mobx'\n\nimport style from '../ItkVtkViewer.module.css'\nimport hex2rgb from '../hex2rgb'\n\nfunction createPointSetColorChooser(store, pointSetColorRow) {\n  const pointSetColorInput = document.createElement('input')\n  pointSetColorInput.setAttribute('type', 'color')\n  pointSetColorInput.id = `${store.id}-pointSetColorInput`\n\n  const defaultPointSetColor = '#ffffff'\n\n  reaction(\n    () => {\n      return store.pointSetsUI.pointSets.slice()\n    },\n    pointSets => {\n      if (!!!pointSets || pointSets.length === 0) {\n        return\n      }\n\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n\n      pointSets.forEach((pointSet, index) => {\n        if (store.pointSetsUI.colors.length <= index) {\n          store.pointSetsUI.colors.push(defaultPointSetColor)\n        }\n      })\n      pointSetColorInput.value = store.pointSetsUI.colors[selectedPointSetIndex]\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.selectedPointSetIndex\n    },\n    selectedPointSetIndex => {\n      pointSetColorInput.value = store.pointSetsUI.colors[selectedPointSetIndex]\n      if (store.pointSetsUI.hasScalars[selectedPointSetIndex]) {\n        pointSetColorInput.style.display = 'none'\n      } else {\n        pointSetColorInput.style.display = 'inline-block'\n      }\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.colors.slice()\n    },\n    colors => {\n      colors.forEach((value, index) => {\n        const rgb = hex2rgb(value)\n        store.pointSetsUI.representationProxies[index].setColor(rgb)\n      })\n      store.renderWindow.render()\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      pointSetColorInput.value = colors[selectedPointSetIndex]\n    }\n  )\n\n  pointSetColorInput.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n    store.pointSetsUI.colors[selectedPointSetIndex] = event.target.value\n  })\n\n  const defaultPointSetColors = Array(store.pointSetsUI.pointSets.length)\n  defaultPointSetColors.fill(defaultPointSetColor)\n  pointSetColorInput.value = defaultPointSetColor\n  store.pointSetsUI.colors = defaultPointSetColors\n  const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n  if (store.pointSetsUI.hasScalars[selectedPointSetIndex]) {\n    pointSetColorInput.style.display = 'none'\n  } else {\n    pointSetColorInput.style.display = 'inline-block'\n  }\n\n  pointSetColorRow.appendChild(pointSetColorInput)\n}\n\nexport default createPointSetColorChooser\n"
  },
  {
    "path": "src/UserInterface/PointSets/createPointSetColorRangeInput.js",
    "content": "import { reaction, observable, action, toJS } from 'mobx'\n\nimport vtkLookupTableProxy from 'vtk.js/Sources/Proxy/Core/LookupTableProxy'\n\nimport style from '../ItkVtkViewer.module.css'\n\nimport createColorMapIconSelector from '../createColorMapIconSelector'\nimport customColorMapIcon from '../customColorMapIcon'\n\nfunction createColorRangeInput(store, uiContainer) {\n  const minimumInput = document.createElement('input')\n  minimumInput.type = 'number'\n  minimumInput.setAttribute('class', style.numberInput)\n  const maximumInput = document.createElement('input')\n  maximumInput.type = 'number'\n  maximumInput.setAttribute('class', style.numberInput)\n\n  function updateColorRangeInput() {\n    const selectedIndex = store.pointSetsUI.selectedPointSetIndex\n    if (!store.pointSetsUI.hasScalars[selectedIndex]) {\n      return\n    }\n    const colorByKey = store.pointSetsUI.colorBy[selectedIndex].value\n    const [location, colorByArrayName] = colorByKey.split(':')\n    const pointSet = store.pointSetsUI.pointSets[selectedIndex]\n    const dataArray =\n      location === 'pointData'\n        ? pointSet.getPointData().getArrayByName(colorByArrayName)\n        : pointSet.getCellData().getArrayByName(colorByArrayName)\n    const range = dataArray.getRange()\n\n    minimumInput.min = range[0]\n    minimumInput.max = range[1]\n    maximumInput.min = range[0]\n    maximumInput.max = range[1]\n    const data = dataArray.getData()\n    if (data instanceof Float32Array || data instanceof Float64Array) {\n      const step = (range[1] - range[0]) / 100.0\n      minimumInput.step = step\n      maximumInput.step = step\n    }\n\n    const colorRange = store.pointSetsUI.selectedColorRange\n    minimumInput.value = colorRange[0]\n    maximumInput.value = colorRange[1]\n  }\n\n  function addColorRangesReactions(index, colorRanges) {\n    if (store.pointSetsUI.colorRangesReactions.has(index)) {\n      const disposer = store.pointSetsUI.colorRangesReactions.get(index)\n      disposer()\n    }\n    const disposer = reaction(\n      () => {\n        return toJS(store.pointSetsUI.colorRanges)\n      },\n      colorRanges => {\n        if (index !== store.pointSetsUI.selectedPointSetIndex) {\n          return\n        }\n        const colorRange = store.pointSetsUI.selectedColorRange\n        if (!!colorRange) {\n          minimumInput.value = colorRange[0]\n          maximumInput.value = colorRange[1]\n          const lutProxy = store.pointSetsUI.selectedLookupTableProxy\n          const colorTransferFunction = lutProxy.getLookupTable()\n          colorTransferFunction.setMappingRange(...colorRange)\n          colorTransferFunction.updateRange()\n          if (!store.renderWindow.getInteractor().isAnimating()) {\n            store.renderWindow.render()\n          }\n        }\n      }\n    )\n    store.pointSetsUI.colorRangesReactions.set(index, disposer)\n  }\n\n  function setDefaultColorRangesColorMaps() {\n    const colorByOptions = store.pointSetsUI.colorByOptions\n    if (!!!colorByOptions || colorByOptions.length === 0) {\n      return\n    }\n\n    const pointSets = store.pointSetsUI.pointSets\n    colorByOptions.forEach((options, index) => {\n      const pointSet = pointSets[index]\n      if (!store.pointSetsUI.colorRanges.has(index)) {\n        const colorRanges = observable(new Map())\n        if (options) {\n          options.forEach(option => {\n            const [location, colorByArrayName] = option.value.split(':')\n            const dataArray =\n              location === 'pointData'\n                ? pointSet.getPointData().getArrayByName(colorByArrayName)\n                : pointSet.getCellData().getArrayByName(colorByArrayName)\n            const range = dataArray.getRange()\n            colorRanges.set(option.value, range)\n          })\n        }\n        store.pointSetsUI.colorRanges.set(index, colorRanges)\n        addColorRangesReactions(index, colorRanges)\n      } else {\n        // Constrain by min / max of possibly new inputs\n        const colorRanges = store.pointSetsUI.colorRanges.get(index)\n        !!options &&\n          options.forEach(option => {\n            const [location, colorByArrayName] = option.value.split(':')\n            const dataArray =\n              location === 'pointData'\n                ? pointSet.getPointData().getArrayByName(colorByArrayName)\n                : pointSet.getCellData().getArrayByName(colorByArrayName)\n            const range = dataArray.getRange()\n\n            if (colorRanges.has(option.value)) {\n              const current = colorRanges.get(option.value)\n              if (current[0] < range[0] || current[1] > range[1]) {\n                const newRange = current.slice()\n                if (current[0] < range[0]) {\n                  newRange[0] = range[0]\n                }\n                if (current[1] > range[1]) {\n                  newRange[1] = range[1]\n                }\n                colorRanges.set(option.value, newRange)\n              }\n            } else {\n              colorRanges.set(option.value, range)\n            }\n          })\n        addColorRangesReactions(index, colorRanges)\n      }\n      if (store.pointSetsUI.colorMaps.length <= index) {\n        const defaultColorMap = 'Viridis (matplotlib)'\n        store.pointSetsUI.colorMaps.push(defaultColorMap)\n        const lutProxy = store.pointSetsUI.selectedLookupTableProxy\n        if (!!lutProxy) {\n          lutProxy.setPresetName(defaultColorMap)\n        }\n      }\n    })\n    updateColorRangeInput()\n  }\n\n  setDefaultColorRangesColorMaps()\n\n  reaction(\n    () => {\n      return store.pointSetsUI.selectedColorRange\n    },\n    colorRange => {\n      if (!!colorRange) {\n        minimumInput.value = colorRange[0]\n        maximumInput.value = colorRange[1]\n        const lutProxy = store.pointSetsUI.selectedLookupTableProxy\n        const colorTransferFunction = lutProxy.getLookupTable()\n        colorTransferFunction.setMappingRange(...colorRange)\n        colorTransferFunction.updateRange()\n      }\n    }\n  )\n\n  minimumInput.addEventListener(\n    'change',\n    action(event => {\n      event.preventDefault()\n      event.stopPropagation()\n      const selectedIndex = store.pointSetsUI.selectedPointSetIndex\n      const colorByKey = store.pointSetsUI.colorBy[selectedIndex].value\n      const range = store.pointSetsUI.colorRanges\n        .get(selectedIndex)\n        .get(colorByKey)\n      range[0] = Number(event.target.value)\n      store.pointSetsUI.colorRanges.get(selectedIndex).set(colorByKey, range)\n    })\n  )\n  maximumInput.addEventListener(\n    'change',\n    action(event => {\n      event.preventDefault()\n      event.stopPropagation()\n      const selectedIndex = store.pointSetsUI.selectedPointSetIndex\n      const colorByKey = store.pointSetsUI.colorBy[selectedIndex].value\n      const range = store.pointSetsUI.colorRanges\n        .get(selectedIndex)\n        .get(colorByKey)\n      range[1] = Number(event.target.value)\n      store.pointSetsUI.colorRanges.get(selectedIndex).set(colorByKey, range)\n    })\n  )\n\n  const colorMapSelector = document.createElement('div')\n  colorMapSelector.id = `${store.id}-pointSetColorMapSelector`\n\n  const iconSelector = createColorMapIconSelector(colorMapSelector)\n\n  function updateColorCanvas() {\n    const selectedIndex = store.pointSetsUI.selectedPointSetIndex\n    if (!store.pointSetsUI.hasScalars[selectedIndex]) {\n      return\n    }\n    const colorMap = store.pointSetsUI.colorMaps[selectedIndex]\n    const lookupTableProxy = store.pointSetsUI.selectedLookupTableProxy\n    const colorTransferFunction = lookupTableProxy.getLookupTable()\n\n    if (colorMap.startsWith('Custom')) {\n      lookupTableProxy.setMode(vtkLookupTableProxy.Mode.RGBPoints)\n      const colorRange = store.pointSetsUI.selectedColorRange\n      const isIcons = iconSelector.getIcons()\n      if (!!!customIcon) {\n        const colorMapIcon = customColorMapIcon(\n          colorTransferFunction,\n          colorDataRange\n        )\n        customIcon = { iconFilePath: colorMapIcon, iconValue: colorMap }\n        icons.push(customIcon)\n        iconSelector.refresh(icons)\n      } else if (isIcons[isIcons.length - 1].iconValue !== colorMap) {\n        const colorMapIcon = customColorMapIcon(\n          colorTransferFunction,\n          colorDataRange\n        )\n        isIcons[isIcons.length - 1].element.src = colorMapIcon\n        isIcons[isIcons.length - 1].iconFilePath = colorMapIcon\n        isIcons[isIcons.length - 1].iconValue = colorMap\n        isIcons[isIcons.length - 1].element.setAttribute('icon-value', colorMap)\n        isIcons[isIcons.length - 1].element.setAttribute('alt', colorMap)\n        isIcons[isIcons.length - 1].element.setAttribute('title', colorMap)\n      }\n    } else {\n      lookupTableProxy.setPresetName(colorMap)\n      lookupTableProxy.setMode(vtkLookupTableProxy.Mode.Preset)\n    }\n    iconSelector.setSelectedValue(colorMap)\n    if (!store.renderWindow.getInteractor().isAnimating()) {\n      store.renderWindow.render()\n    }\n  }\n  let customIcon = null\n  reaction(\n    () => {\n      return store.pointSetsUI.colorMaps.slice()\n    },\n    colorMaps => {\n      updateColorCanvas()\n    }\n  )\n  colorMapSelector.addEventListener('changed', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedIndex = store.pointSetsUI.selectedPointSetIndex\n    store.pointSetsUI.colorMaps[selectedIndex] = iconSelector.getSelectedValue()\n  })\n  const pointSetIndex = store.pointSetsUI.selectedPointSetIndex\n  iconSelector.setSelectedValue(store.pointSetsUI.colorMaps[pointSetIndex])\n\n  reaction(\n    () => {\n      return store.pointSetsUI.colorByOptions.slice()\n    },\n    () => {\n      setDefaultColorRangesColorMaps()\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.selectedPointSetIndex\n    },\n    selectedIndex => {\n      const hasScalars = store.pointSetsUI.hasScalars\n      if (hasScalars[selectedIndex]) {\n        uiContainer.style.display = 'flex'\n        updateColorRangeInput()\n        updateColorCanvas()\n      } else {\n        uiContainer.style.display = 'none'\n      }\n    }\n  )\n  reaction(\n    () => {\n      return store.pointSetsUI.colorBy.slice()\n    },\n    () => {\n      updateColorRangeInput()\n      updateColorCanvas()\n    }\n  )\n\n  updateColorCanvas()\n  const hasScalars = store.pointSetsUI.hasScalars\n  const selectedIndex = store.pointSetsUI.selectedPointSetIndex\n  if (hasScalars[selectedIndex]) {\n    uiContainer.style.display = 'flex'\n  } else {\n    uiContainer.style.display = 'none'\n  }\n\n  uiContainer.appendChild(minimumInput)\n  uiContainer.appendChild(colorMapSelector)\n  uiContainer.appendChild(maximumInput)\n}\n\nexport default createColorRangeInput\n"
  },
  {
    "path": "src/UserInterface/PointSets/createPointSetColorWidget.js",
    "content": "import style from '../ItkVtkViewer.module.css'\n\nimport createPointSetColorChooser from './createPointSetColorChooser'\nimport createPointSetOpacitySlider from './createPointSetOpacitySlider'\nimport createPointSetColorBySelector from './createPointSetColorBySelector'\nimport createPointSetSizeSlider from './createPointSetSizeSlider'\nimport createPointSetColorRangeInput from './createPointSetColorRangeInput'\n\nfunction createPointSetColorWidget(store, pointSetsUIGroup) {\n  const colorByRow = document.createElement('div')\n  colorByRow.setAttribute('class', style.uiRow)\n  colorByRow.className += ` ${store.id}-collapsible`\n  createPointSetColorBySelector(store, colorByRow)\n  pointSetsUIGroup.appendChild(colorByRow)\n\n  const pointSetColorRow = document.createElement('div')\n  pointSetColorRow.setAttribute('class', style.uiRow)\n  pointSetColorRow.className += ` ${store.id}-collapsible`\n\n  createPointSetColorChooser(store, pointSetColorRow)\n\n  createPointSetOpacitySlider(store, pointSetColorRow)\n  pointSetsUIGroup.appendChild(pointSetColorRow)\n\n  const colorRangeInputRow = document.createElement('div')\n  colorRangeInputRow.setAttribute('class', style.uiRow)\n  createPointSetColorRangeInput(store, colorRangeInputRow)\n  colorRangeInputRow.className += ` ${store.id}-collapsible`\n  pointSetsUIGroup.appendChild(colorRangeInputRow)\n\n  const pointSetSizeRow = document.createElement('div')\n  pointSetSizeRow.setAttribute('class', style.uiRow)\n  pointSetSizeRow.className += ` ${store.id}-collapsible`\n  createPointSetSizeSlider(store, pointSetSizeRow)\n  pointSetsUIGroup.appendChild(pointSetSizeRow)\n\n  if (store.mainUI.collapsed) {\n    colorByRow.style.display = 'none'\n    colorRangeInputRow.style.display = 'none'\n    pointSetSizeRow.style.display = 'none'\n  }\n}\n\nexport default createPointSetColorWidget\n"
  },
  {
    "path": "src/UserInterface/PointSets/createPointSetOpacitySlider.js",
    "content": "import { reaction, action } from 'mobx'\n\nimport style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyle from '../applyContrastSensitiveStyle'\n\nimport opacityIcon from '../icons/opacity.svg'\n\nfunction createPointSetOpacitySlider(store, pointSetColorRow) {\n  const defaultPointSetOpacity = 1.0\n\n  const sliderEntry = document.createElement('div')\n  sliderEntry.setAttribute('class', style.sliderEntry)\n  sliderEntry.innerHTML = `\n    <div itk-vtk-tooltip itk-vtk-tooltip-bottom itk-vtk-tooltip-content=\"Opacity\" class=\"${style.gradientOpacitySlider}\">\n      ${opacityIcon}\n    </div>\n    <input type=\"range\" min=\"0\" max=\"1\" value=\"${defaultPointSetOpacity}\" step=\"0.01\"\n      id=\"${store.id}-pointSetOpacitySlider\"\n      class=\"${style.slider}\" />`\n  const opacityElement = sliderEntry.querySelector(\n    `#${store.id}-pointSetOpacitySlider`\n  )\n  const sliderEntryDiv = sliderEntry.children[0]\n  applyContrastSensitiveStyle(store, 'invertibleButton', sliderEntryDiv)\n\n  reaction(\n    () => {\n      return store.pointSetsUI.pointSets.slice()\n    },\n    pointSets => {\n      if (!!!pointSets || pointSets.length === 0) {\n        return\n      }\n\n      pointSets.forEach((pointSet, index) => {\n        if (store.pointSetsUI.opacities.length <= index) {\n          store.pointSetsUI.opacities.push(defaultPointSetOpacity)\n        }\n      })\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      opacityElement.value = store.pointSetsUI.opacities[selectedPointSetIndex]\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.selectedPointSetIndex\n    },\n    selectedPointSetIndex => {\n      opacityElement.value = store.pointSetsUI.opacities[selectedPointSetIndex]\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.opacities.slice()\n    },\n    opacities => {\n      opacities.forEach((opacity, index) => {\n        store.pointSetsUI.representationProxies[index].setOpacity(opacity)\n      })\n      store.renderWindow.render()\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      opacityElement.value = opacities[selectedPointSetIndex]\n    }\n  )\n\n  opacityElement.addEventListener(\n    'input',\n    action(event => {\n      event.preventDefault()\n      event.stopPropagation()\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      store.pointSetsUI.opacities[selectedPointSetIndex] = Number(\n        event.target.value\n      )\n    })\n  )\n\n  const defaultPointSetOpacities = new Array(store.pointSetsUI.pointSets.length)\n  defaultPointSetOpacities.fill(defaultPointSetOpacity)\n  opacityElement.value = defaultPointSetOpacity\n  store.pointSetsUI.opacities = defaultPointSetOpacities\n\n  pointSetColorRow.appendChild(sliderEntry)\n}\n\nexport default createPointSetOpacitySlider\n"
  },
  {
    "path": "src/UserInterface/PointSets/createPointSetRepresentationSelector.js",
    "content": "import { reaction } from 'mobx'\n\nimport style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyle from '../applyContrastSensitiveStyle'\n\nimport hiddenIcon from '../icons/hidden.svg'\nimport pointsIcon from '../icons/point-set-points.svg'\nimport spheresIcon from '../icons/point-set-spheres.svg'\n\nfunction createPointSetRepresentationSelector(\n  store,\n  pointSetRepresentationRow\n) {\n  const viewerDOMId = store.id\n\n  const pointSetHiddenButton = document.createElement('div')\n  pointSetHiddenButton.innerHTML = `<input id=\"${viewerDOMId}-pointSetHiddenButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Hidden\" class=\"${style.fullscreenButton} ${style.toggleButton}\" for=\"${viewerDOMId}-pointSetHiddenButton\">${hiddenIcon}</label>`\n  pointSetHiddenButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n    store.pointSetsUI.representations[selectedPointSetIndex] = 'Hidden'\n  })\n  pointSetRepresentationRow.appendChild(pointSetHiddenButton)\n  const pointSetHiddenButtonInput = pointSetHiddenButton.children[0]\n  const pointSetHiddenButtonLabel = pointSetHiddenButton.children[1]\n  applyContrastSensitiveStyle(store, 'tooltipButton', pointSetHiddenButtonLabel)\n\n  const pointSetPointsButton = document.createElement('div')\n  pointSetPointsButton.innerHTML = `<input id=\"${viewerDOMId}-pointSetPointsButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Points\" class=\"${style.fullscreenButton} ${style.toggleButton}\" for=\"${viewerDOMId}-pointSetPointsButton\">${pointsIcon}</label>`\n  pointSetPointsButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n    store.pointSetsUI.representations[selectedPointSetIndex] = 'Points'\n  })\n  pointSetRepresentationRow.appendChild(pointSetPointsButton)\n  const pointSetPointsButtonInput = pointSetPointsButton.children[0]\n  const pointSetPointsButtonLabel = pointSetPointsButton.children[1]\n  applyContrastSensitiveStyle(store, 'tooltipButton', pointSetPointsButtonLabel)\n\n  const pointSetSpheresButton = document.createElement('div')\n  pointSetSpheresButton.innerHTML = `<input id=\"${viewerDOMId}-pointSetSpheresButton\" type=\"checkbox\" class=\"${style.toggleInput}\"><label itk-vtk-tooltip itk-vtk-tooltip-top itk-vtk-tooltip-content=\"Spheres\" class=\"${style.fullscreenButton} ${style.toggleButton}\" for=\"${viewerDOMId}-pointSetSpheresButton\">${spheresIcon}</label>`\n  pointSetSpheresButton.addEventListener('click', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n    store.pointSetsUI.representations[selectedPointSetIndex] = 'Spheres'\n  })\n  pointSetRepresentationRow.appendChild(pointSetSpheresButton)\n  const pointSetSpheresButtonInput = pointSetSpheresButton.children[0]\n  const pointSetSpheresButtonLabel = pointSetSpheresButton.children[1]\n  applyContrastSensitiveStyle(\n    store,\n    'tooltipButton',\n    pointSetSpheresButtonLabel\n  )\n\n  function updateEnabledRepresentationButtons(selectedPointSetRepresentation) {\n    switch (selectedPointSetRepresentation) {\n      case 'Hidden':\n        pointSetHiddenButtonInput.checked = true\n        pointSetPointsButtonInput.checked = false\n        pointSetSpheresButtonInput.checked = false\n        break\n      case 'Points':\n        pointSetHiddenButtonInput.checked = false\n        pointSetPointsButtonInput.checked = true\n        pointSetSpheresButtonInput.checked = false\n        break\n      case 'Spheres':\n        pointSetHiddenButtonInput.checked = false\n        pointSetPointsButtonInput.checked = false\n        pointSetSpheresButtonInput.checked = true\n        break\n      default:\n        console.error(\n          'Invalid pointSet representation: ' + selectedPointSetRepresentation\n        )\n    }\n  }\n\n  function setRepresentation(value, index) {\n    if (value === 'Hidden') {\n      store.pointSetsUI.representationProxies[index].setVisibility(false)\n    } else {\n      store.pointSetsUI.representationProxies[index].setRepresentation(value)\n      store.pointSetsUI.representationProxies[index].setVisibility(true)\n    }\n  }\n\n  reaction(\n    () => {\n      return store.pointSetsUI.representations.slice()\n    },\n    representations => {\n      representations.forEach((representation, index) => {\n        setRepresentation(representation, index)\n      })\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      const representation =\n        store.pointSetsUI.representations[selectedPointSetIndex]\n      updateEnabledRepresentationButtons(representation)\n      store.renderWindow.render()\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.selectedPointSetIndex\n    },\n    selectedIndex => {\n      const selectedPointSetRepresentation =\n        store.pointSetsUI.representations[selectedIndex]\n      updateEnabledRepresentationButtons(selectedPointSetRepresentation)\n    }\n  )\n\n  const defaultPointSetRepresentation = 'Points'\n\n  reaction(\n    () => {\n      return store.pointSetsUI.pointSets.slice()\n    },\n    pointSets => {\n      if (!!!pointSets || pointSets.length === 0) {\n        return\n      }\n\n      pointSets.forEach((pointSet, index) => {\n        if (store.pointSetsUI.representations.length <= index) {\n          store.pointSetsUI.representations.push(defaultPointSetRepresentation)\n        }\n      })\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      updateEnabledRepresentationButtons(\n        store.pointSetsUI.representations[selectedPointSetIndex]\n      )\n    }\n  )\n\n  const defaultPointSetRepresentations = new Array(\n    store.pointSetsUI.pointSets.length\n  )\n  defaultPointSetRepresentations.fill(defaultPointSetRepresentation)\n  updateEnabledRepresentationButtons(defaultPointSetRepresentation)\n  store.pointSetsUI.representations = defaultPointSetRepresentations\n  const pointSetRepresentationProxies = store.pointSetsUI.representationProxies\n}\n\nexport default createPointSetRepresentationSelector\n"
  },
  {
    "path": "src/UserInterface/PointSets/createPointSetSizeSlider.js",
    "content": "import { reaction } from 'mobx'\n\nimport style from '../ItkVtkViewer.module.css'\nimport applyContrastSensitiveStyle from '../applyContrastSensitiveStyle'\n\nimport pointSetSizeIcon from '../icons/point-set-size.svg'\n\nfunction createPointSetSizeSlider(store, pointSetSizeRow) {\n  const defaultPointSetSize = 3\n\n  const sliderEntry = document.createElement('div')\n  sliderEntry.setAttribute('class', style.sliderEntry)\n  sliderEntry.innerHTML = `\n    <div itk-vtk-tooltip itk-vtk-tooltip-bottom itk-vtk-tooltip-content=\"Size\" class=\"${style.gradientOpacitySlider}\">\n      ${pointSetSizeIcon}\n    </div>\n    <input type=\"range\" min=\"1\" max=\"20\" value=\"${defaultPointSetSize}\" step=\"1\"\n      id=\"${store.id}-pointSetSizeSlider\"\n      class=\"${style.slider}\" />`\n  const sizeElement = sliderEntry.querySelector(\n    `#${store.id}-pointSetSizeSlider`\n  )\n  const sliderEntryDiv = sliderEntry.children[0]\n  applyContrastSensitiveStyle(store, 'invertibleButton', sliderEntryDiv)\n\n  reaction(\n    () => {\n      return store.pointSetsUI.pointSets.slice()\n    },\n    pointSets => {\n      if (!!!pointSets || pointSets.length === 0) {\n        return\n      }\n\n      pointSets.forEach((pointSet, index) => {\n        if (store.pointSetsUI.sizes.length <= index) {\n          store.pointSetsUI.sizes.push(defaultPointSetSize)\n        }\n      })\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      sizeElement.value = store.pointSetsUI.sizes[selectedPointSetIndex]\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.selectedPointSetIndex\n    },\n    selectedPointSetIndex => {\n      sizeElement.value = store.pointSetsUI.sizes[selectedPointSetIndex]\n    }\n  )\n\n  reaction(\n    () => {\n      return store.pointSetsUI.sizes.slice()\n    },\n    sizes => {\n      for (let index = 0; index < sizes.length; index++) {\n        store.pointSetsUI.representationProxies[index].setPointSize(\n          sizes[index]\n        )\n      }\n      store.renderWindow.render()\n      sizeElement.value = sizes[store.pointSetsUI.selectedPointSetIndex]\n    }\n  )\n\n  sizeElement.addEventListener('input', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n    store.pointSetsUI.sizes[selectedPointSetIndex] = Number(event.target.value)\n  })\n\n  const defaultPointSetSizes = new Array(store.pointSetsUI.pointSets.length)\n  defaultPointSetSizes.fill(defaultPointSetSize)\n  sizeElement.value = defaultPointSetSize\n  store.pointSetsUI.sizes = defaultPointSetSizes\n  store.pointSetsUI.representationProxies.forEach(proxy => {\n    proxy.setPointSize(defaultPointSetSize)\n  })\n\n  pointSetSizeRow.appendChild(sliderEntry)\n}\n\nexport default createPointSetSizeSlider\n"
  },
  {
    "path": "src/UserInterface/addLogo.js",
    "content": "import style from './ItkVtkViewer.module.css'\n\nimport logoIcon from './icons/logo.png'\n\nimport vtkFPSMonitor from 'vtk.js/Sources/Interaction/UI/FPSMonitor'\n\nfunction addLogo(store) {\n  const logo = new Image()\n  logo.src = logoIcon\n  logo.setAttribute('class', style.logo)\n  store.container.appendChild(logo)\n\n  const showCredits = () => {\n    logo.style.display = 'none'\n    if (!store.appAttribution) {\n      const appAttribution = document.createElement('div')\n      appAttribution.setAttribute('class', style.fpsMonitor)\n      appAttribution.innerHTML = `\n  <p style=\"border:2px; border-radius: 3px; border-style:solid; border-color:#4488BB; padding: 1em;\"><a href=\"https://kitware.github.io/itk-vtk-viewer/index.html\">itk-vtk-viewer</a> development is <br>lead by the hearts and minds at <br> <a href=\"https://www.kitware.com\">Kitware</a>.</p>`\n      store.container.appendChild(appAttribution)\n      store.appAttribution = appAttribution\n    }\n  }\n\n  const showFps = () => {\n    logo.style.display = 'none'\n    if (!store.fpsMonitor) {\n      const fpsMonitor = vtkFPSMonitor.newInstance()\n      const fpsElement = fpsMonitor.getFpsMonitorContainer()\n      fpsElement.setAttribute('class', style.fpsMonitor)\n\n      fpsMonitor.setContainer(store.container)\n      fpsMonitor.setBufferSize(100)\n      fpsMonitor.setRenderWindow(store.renderWindow)\n      fpsMonitor.update()\n      store.fpsMonitor = fpsMonitor\n    }\n  }\n\n  logo.addEventListener('mousedown', e => {\n    if (e.button === 0) {\n      showCredits()\n    } else {\n      showFps()\n    }\n  })\n}\n\nexport default addLogo\n"
  },
  {
    "path": "src/UserInterface/applyContrastSensitiveStyle.js",
    "content": "import style from './ItkVtkViewer.module.css'\nimport { autorun, reaction } from 'mobx'\n\nfunction applyContrastSensitiveStyle(store, cssClass, element) {\n  autorun(() => {\n    const isBackgroundDark = store.isBackgroundDark\n    const addPostFix = isBackgroundDark ? 'DarkBG' : 'BrightBG'\n    const removePostFix = !isBackgroundDark ? 'DarkBG' : 'BrightBG'\n    const removeClass = style[`${cssClass}${removePostFix}`]\n    if (element.classList.contains(removeClass)) {\n      element.classList.remove(removeClass)\n    }\n    element.classList.add(style[`${cssClass}${addPostFix}`])\n  })\n}\n\nexport default applyContrastSensitiveStyle\n"
  },
  {
    "path": "src/UserInterface/checkForWebGL.js",
    "content": "function checkForWebGL(container) {\n  const testCanvas = document.createElement('canvas')\n  const gl =\n    testCanvas.getContext('webgl') ||\n    testCanvas.getContext('experimental-webgl')\n  if (!(gl && gl instanceof WebGLRenderingContext)) {\n    const suggestion = document.createElement('p')\n    const preSuggestionText = document.createTextNode(\n      'WebGL could not be loaded. '\n    )\n    suggestion.appendChild(preSuggestionText)\n    const getWebGLA = document.createElement('a')\n    getWebGLA.setAttribute('href', 'http://get.webgl.org/troubleshooting')\n    const getWebGLAText = document.createTextNode(\n      'Try a different browser or video drivers for WebGL support.'\n    )\n    getWebGLA.appendChild(getWebGLAText)\n    suggestion.appendChild(getWebGLA)\n    const suggestionText = document.createTextNode(\n      ' This is required to view interactive 3D visualizations.'\n    )\n    suggestion.appendChild(suggestionText)\n    container.appendChild(suggestion)\n    return false\n  }\n  return true\n}\n\nexport default checkForWebGL\n"
  },
  {
    "path": "src/UserInterface/createCategoricalColorIconSelector.js",
    "content": "import { IconSelect } from '@thewtex/iconselect.js/lib/control/iconselect'\nimport { CategoricalColorIcons } from 'itk-viewer-color-maps'\n\nfunction createCategoricalColorIconSelector(categoricalColorSelectorDiv) {\n  const rows = 4\n  const cols = 2\n  const iconSelectParameters = {\n    selectedIconWidth: 140,\n    selectedIconHeight: 22,\n    selectedBoxPadding: 1,\n    iconsWidth: 60,\n    iconsHeight: 22,\n    boxIconSpace: 1,\n    vectoralIconNumber: cols,\n    horizontalIconNumber: rows,\n  }\n  const iconSelect = new IconSelect(\n    `${categoricalColorSelectorDiv.id}`,\n    categoricalColorSelectorDiv,\n    iconSelectParameters\n  )\n  categoricalColorSelectorDiv.style.width = '154px'\n  const icons = new Array(rows * cols)\n  let count = 0\n  for (let [key, value] of CategoricalColorIcons.entries()) {\n    const index = Math.floor(count % rows) * cols + Math.floor(count / rows)\n    icons[index] = { iconFilePath: value, iconValue: key }\n    count++\n  }\n  iconSelect.refresh(icons)\n\n  return iconSelect\n}\n\nexport default createCategoricalColorIconSelector\n"
  },
  {
    "path": "src/UserInterface/createColorMapIconSelector.js",
    "content": "import { IconSelect } from '@thewtex/iconselect.js/lib/control/iconselect'\nimport { ColorMapIcons } from 'itk-viewer-color-maps'\n\nfunction createColorMapIconSelector(colorMapSelectorDiv) {\n  const rows = 19\n  const cols = 4\n  const iconSelectParameters = {\n    selectedIconWidth: 230,\n    selectedIconHeight: 22,\n    selectedBoxPadding: 1,\n    iconsWidth: 80,\n    iconsHeight: 22,\n    boxIconSpace: 1,\n    vectoralIconNumber: cols,\n    horizontalIconNumber: rows,\n  }\n  const iconSelect = new IconSelect(\n    `${colorMapSelectorDiv.id}`,\n    colorMapSelectorDiv,\n    iconSelectParameters\n  )\n  colorMapSelectorDiv.style.width = '250px'\n  const icons = new Array(rows * cols)\n  let count = 0\n  for (let [key, value] of ColorMapIcons.entries()) {\n    const index = Math.floor(count % rows) * cols + Math.floor(count / rows)\n    icons[index] = { iconFilePath: value, iconValue: key }\n    count++\n  }\n  const contiguousIcons = icons.filter(i => i)\n  iconSelect.refresh(contiguousIcons)\n\n  return iconSelect\n}\n\nexport default createColorMapIconSelector\n"
  },
  {
    "path": "src/UserInterface/createFileDragAndDrop.js",
    "content": "import vtkURLExtract from 'vtk.js/Sources/Common/Core/URLExtract'\n\nimport getRootContainer from './getRootContainer'\nimport preventDefaults from './preventDefaults'\n\nimport style from './ItkVtkViewer.module.css'\nimport Mousetrap from 'mousetrap'\n\nconst MOUSETRAP = new Mousetrap()\n\nfunction createFileDragAndDrop(container, onDataChange) {\n  const myContainer = getRootContainer(container)\n\n  const fileContainer = document.createElement('div')\n  fileContainer.innerHTML = `<div class=\"${style.bigFileDrop}\"/><input type=\"file\" class=\"file\" style=\"display: none;\" multiple/>`\n  myContainer.appendChild(fileContainer)\n\n  const fileInput = fileContainer.querySelector('input')\n\n  MOUSETRAP.bind('enter', event => {\n    fileInput.click()\n  })\n\n  return new Promise(resolve => {\n    function handleFile(e) {\n      preventDefaults(e)\n      MOUSETRAP.unbind('enter')\n      const dataTransfer = e.dataTransfer\n      const files = e.target.files || dataTransfer.files\n      myContainer.removeChild(fileContainer)\n      const use2D = !!vtkURLExtract.extractURLParameters().use2D\n      resolve(\n        onDataChange(myContainer, { files, use2D }).catch(error => {\n          const message =\n            'An error occurred while loading the file:\\n\\n' + error.message\n          alert(message)\n          createFileDragAndDrop(container, onDataChange)\n        })\n      )\n    }\n\n    fileInput.addEventListener('change', handleFile)\n    fileContainer.addEventListener('drop', handleFile)\n    fileContainer.addEventListener('click', e => fileInput.click())\n    fileContainer.addEventListener('dragover', preventDefaults)\n  })\n}\n\nexport default createFileDragAndDrop\n"
  },
  {
    "path": "src/UserInterface/createGeometriesUI.js",
    "content": "import { reaction, autorun } from 'mobx'\n\nimport style from './ItkVtkViewer.module.css'\n\nimport createGeometryRepresentationSelector from './Geometries/createGeometryRepresentationSelector'\nimport createGeometryColorWidget from './Geometries/createGeometryColorWidget'\n\nfunction createGeometriesUI(store, uiContainer) {\n  const geometriesUIGroup = document.createElement('div')\n  geometriesUIGroup.setAttribute('class', style.uiGroup)\n\n  const geometryRepresentationRow = document.createElement('div')\n  geometryRepresentationRow.setAttribute('class', style.uiRow)\n  geometryRepresentationRow.className += ` ${store.id}-collapsible`\n  if (store.mainUI.collapsed) {\n    geometryRepresentationRow.style.display = 'none'\n  }\n\n  const geometrySelector = document.createElement('select')\n  geometrySelector.setAttribute('class', style.selector)\n  geometrySelector.id = `${store.id}-geometrySelector`\n  geometryRepresentationRow.appendChild(geometrySelector)\n\n  geometrySelector.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    store.geometriesUI.selectedGeometryIndex = geometrySelector.selectedIndex\n  })\n  function updateGeometryNames(names) {\n    geometrySelector.innerHTML = names\n      .map(name => `<option value=\"${name}\">${name}</option>`)\n      .join('')\n    if (names.length > 1) {\n      geometrySelector.disabled = false\n    } else {\n      geometrySelector.disabled = true\n    }\n  }\n  reaction(\n    () => {\n      return store.geometriesUI.names.slice()\n    },\n    names => {\n      updateGeometryNames(names)\n    }\n  )\n  if (store.geometriesUI.geometries.length > 0) {\n    store.geometriesUI.selectedGeometryIndex = 0\n  }\n  autorun(() => {\n    const geometries = store.geometriesUI.geometries\n    store.geometriesUI.names = geometries.map((geometry, index) => {\n      const metadata = geometry.getState().metadata\n      return !!metadata && !!metadata.name ? metadata.name : `Geometry ${index}`\n    })\n  })\n\n  createGeometryRepresentationSelector(store, geometryRepresentationRow)\n  geometriesUIGroup.appendChild(geometryRepresentationRow)\n\n  createGeometryColorWidget(store, geometriesUIGroup)\n\n  uiContainer.appendChild(geometriesUIGroup)\n  store.geometriesUI.initialized = true\n}\n\nexport default createGeometriesUI\n"
  },
  {
    "path": "src/UserInterface/createLoadingProgress.js",
    "content": "import getRootContainer from './getRootContainer'\n\nimport style from './ItkVtkViewer.module.css'\n\nfunction createLoadingProgress(container) {\n  const rootContainer = getRootContainer(container)\n\n  const loading = document.createElement('div')\n  loading.setAttribute('class', style.loading)\n  rootContainer.appendChild(loading)\n\n  const progressContainer = document.createElement('div')\n  progressContainer.setAttribute('class', style.progress)\n  rootContainer.appendChild(progressContainer)\n\n  function progressCallback(progressEvent) {\n    const percent = Math.floor(\n      (100 * progressEvent.loaded) / progressEvent.total\n    )\n    progressContainer.innerHTML = `${percent}%`\n  }\n\n  return progressCallback\n}\n\nexport default createLoadingProgress\n"
  },
  {
    "path": "src/UserInterface/createPointSetsUI.js",
    "content": "import { reaction, autorun } from 'mobx'\n\nimport style from './ItkVtkViewer.module.css'\n\nimport createPointSetRepresentationSelector from './PointSets/createPointSetRepresentationSelector'\nimport createPointSetColorWidget from './PointSets/createPointSetColorWidget'\n\nfunction createPointSetsUI(store, uiContainer) {\n  const pointSetsUIGroup = document.createElement('div')\n  pointSetsUIGroup.setAttribute('class', style.uiGroup)\n\n  const pointSetRepresentationRow = document.createElement('div')\n  pointSetRepresentationRow.setAttribute('class', style.uiRow)\n  pointSetRepresentationRow.className += ` ${store.id}-collapsible`\n  if (store.mainUI.collapsed) {\n    pointSetRepresentationRow.style.display = 'none'\n  }\n\n  const pointSetSelector = document.createElement('select')\n  pointSetSelector.setAttribute('class', style.selector)\n  pointSetSelector.id = `${store.id}-pointSetSelector`\n  pointSetRepresentationRow.appendChild(pointSetSelector)\n\n  pointSetSelector.addEventListener('change', event => {\n    event.preventDefault()\n    event.stopPropagation()\n    store.pointSetsUI.selectedPointSetIndex = pointSetSelector.selectedIndex\n  })\n\n  function updatePointSetNames(names) {\n    pointSetSelector.innerHTML = names\n      .map(name => `<option value=\"${name}\">${name}</option>`)\n      .join('')\n    if (names.length > 1) {\n      pointSetSelector.disabled = false\n    } else {\n      pointSetSelector.disabled = true\n    }\n  }\n  reaction(\n    () => {\n      return store.pointSetsUI.names.slice()\n    },\n    names => {\n      updatePointSetNames(names)\n    }\n  )\n  if (store.pointSetsUI.pointSets.length > 0) {\n    store.pointSetsUI.selectedPointSetIndex = 0\n  }\n  autorun(() => {\n    const pointSets = store.pointSetsUI.pointSets\n    store.pointSetsUI.names = pointSets.map((pointSet, index) => {\n      const metadata = pointSet.getState().metadata\n      return !!metadata && !!metadata.name\n        ? metadata.name\n        : `Point Set ${index}`\n    })\n  })\n\n  createPointSetRepresentationSelector(store, pointSetRepresentationRow)\n  pointSetsUIGroup.appendChild(pointSetRepresentationRow)\n\n  createPointSetColorWidget(store, pointSetsUIGroup)\n\n  uiContainer.appendChild(pointSetsUIGroup)\n  store.pointSetsUI.initialized = true\n}\n\nexport default createPointSetsUI\n"
  },
  {
    "path": "src/UserInterface/customColorMapIcon.js",
    "content": "const canvas = document.createElement('canvas')\nconst width = 240\nconst height = 20\ncanvas.setAttribute('width', width)\ncanvas.setAttribute('height', height)\n\nfunction customColorMapIcon(colorTransferFunction, range) {\n  const ctx = canvas.getContext('2d')\n\n  const rgba = colorTransferFunction.getUint8Table(range[0], range[1], width, 4)\n  const pixelsArea = ctx.getImageData(0, 0, width, 256)\n  for (let lineIdx = 0; lineIdx < 256; lineIdx++) {\n    pixelsArea.data.set(rgba, lineIdx * 4 * width)\n  }\n\n  const nbValues = 256 * width * 4\n  const lineSize = width * 4\n  for (let i = 3; i < nbValues; i += 4) {\n    pixelsArea.data[i] = 255 - Math.floor(i / lineSize)\n  }\n\n  ctx.putImageData(pixelsArea, 0, 0)\n  return canvas.toDataURL('image/png')\n}\n\nexport default customColorMapIcon\n"
  },
  {
    "path": "src/UserInterface/emptyContainer.js",
    "content": "function emptyContainer(container) {\n  if (container) {\n    while (container.firstChild) {\n      container.removeChild(container.firstChild)\n    }\n  }\n}\n\nexport default emptyContainer\n"
  },
  {
    "path": "src/UserInterface/getContrastSensitiveStyle.js",
    "content": "import style from './ItkVtkViewer.module.css'\n\nfunction getContrastSensitiveStyle(cssClasses, isBackgroundDark) {\n  const stylePostFix = isBackgroundDark ? 'DarkBG' : 'BrightBG'\n  const contrastSensitiveStyle = {}\n  cssClasses.forEach(name => {\n    contrastSensitiveStyle[name] = style[`${name}${stylePostFix}`]\n  })\n  return contrastSensitiveStyle\n}\n\nexport default getContrastSensitiveStyle\n"
  },
  {
    "path": "src/UserInterface/getRootContainer.js",
    "content": "function getRootContainer(container) {\n  const workContainer = document.querySelector('.content')\n  const rootBody = document.querySelector('body')\n\n  return container || workContainer || rootBody\n}\n\nexport default getRootContainer\n"
  },
  {
    "path": "src/UserInterface/hex2rgb.js",
    "content": "function hex2rgb(hexColor) {\n  const bigint = parseInt(hexColor.substring(1), 16)\n  const r = ((bigint >> 16) & 255) / 255.0\n  const g = ((bigint >> 8) & 255) / 255.0\n  const b = (bigint & 255) / 255.0\n\n  return [r, g, b]\n}\n\nexport default hex2rgb\n"
  },
  {
    "path": "src/UserInterface/index.js",
    "content": "import addLogo from './addLogo'\nimport createLoadingProgress from './createLoadingProgress'\nimport createGeometriesUI from './createGeometriesUI'\nimport createPointSetsUI from './createPointSetsUI'\nimport emptyContainer from './emptyContainer'\nimport getRootContainer from './getRootContainer'\nimport checkForWebGL from './checkForWebGL'\n\nexport default {\n  addLogo,\n  createLoadingProgress,\n  createGeometriesUI,\n  createPointSetsUI,\n  emptyContainer,\n  getRootContainer,\n  checkForWebGL,\n}\n"
  },
  {
    "path": "src/UserInterface/preventDefaults.js",
    "content": "function preventDefaults(e) {\n  e.preventDefault()\n  e.stopPropagation()\n}\n\nexport default preventDefaults\n"
  },
  {
    "path": "src/UserInterface/rgb2hex.js",
    "content": "function rgb2hex(rgb) {\n  return (\n    '#' +\n    ((1 << 24) + ((rgb[0] * 255) << 16) + ((rgb[1] * 255) << 8) + rgb[2] * 255)\n      .toString(16)\n      .slice(1)\n  ).substring(0, 7)\n}\n\nexport default rgb2hex\n"
  },
  {
    "path": "src/ViewerStore.js",
    "content": "import { observable, computed, trace } from 'mobx'\nimport EventEmitter from 'eventemitter3'\n\nimport vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData'\nimport vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray'\nimport { VtkDataTypes } from 'vtk.js/Sources/Common/Core/DataArray/Constants'\n\nconst STYLE_RENDERING_VIEW_CONTAINER = {\n  position: 'relative',\n  width: '100%',\n  height: '100%',\n  minHeight: '200px',\n  minWidth: '450px',\n  margin: '0',\n  padding: '0',\n  top: '0',\n  left: '0',\n  overflow: 'hidden',\n}\n\nclass MainUIStore {\n  uiContainer = null\n  @observable collapsed = false\n  @observable annotationsEnabled = true\n  @observable axesEnabled = false\n  @observable fullscreenEnabled = false\n  @observable rotateEnabled = false\n  @observable interpolationEnabled = true\n  @observable croppingPlanesEnabled = false\n\n  @observable viewMode = 'Volume'\n\n  fps = [60, 60, 60]\n  @observable fpsTooLow = false\n  fpsMonitor = null\n}\n\nclass ImageUIStore {\n  constructor(eventEmitter) {\n    this.eventEmitter = eventEmitter\n  }\n\n  eventEmitter = null\n\n  @observable.ref image = null\n  @observable.ref multiscaleImage = null\n\n  source = null\n  @observable.ref representationProxy = null\n\n  @observable selectedComponent = 0\n  // Does not include the label map\n  @computed get numberOfComponents() {\n    if (!!!this.image) {\n      return 0\n    }\n    const dataArray = this.fusedImageLabelMap.getPointData().getScalars()\n    if (!!this.labelMap) {\n      return dataArray.getNumberOfComponents() - 1\n    }\n    return dataArray.getNumberOfComponents()\n  }\n  totalIntensityComponents = 0\n  maxIntensityComponents = 3\n\n  piecewiseFunctionProxies = []\n  @observable componentVisibilities = []\n  lastVisualizedComponents = []\n  fusedImageData = null\n  @observable visualizedComponents = []\n  lastComponentVisibilityChanged = 0\n  transferFunctionManipulator = {\n    rangeManipulator: null,\n    windowMotionScale: 150.0,\n    levelMotionScale: 150.0,\n    windowGet: null,\n    windowSet: null,\n    levelGet: null,\n    levelSet: null,\n  }\n  independentComponents = true\n\n  imageUIGroup = null\n  croppingWidget = null\n  addCroppingPlanesChangedHandler = () => {}\n  addResetCropHandler = () => {}\n\n  @observable colorMaps = null\n  @observable colorRanges = []\n  @observable opacityGaussians = []\n\n  @observable blendMode = 0\n  @observable useShadow = true\n  @observable slicingPlanesEnabled = false\n  @observable gradientOpacity = 0.2\n  @observable volumeSampleDistance = 0.25\n  @observable xSlice = null\n  @observable ySlice = null\n  @observable zSlice = null\n\n  @observable.ref labelMap = null\n  @observable.ref multiscaleLabelMap = null\n\n  // @observable fusingImages = false\n\n  @computed get fusedImageLabelMap() {\n    const image = this.image\n    const labelMap = this.labelMap\n\n    if (!!!image && !!!labelMap) {\n      return null\n    }\n    if (!!!image) {\n      return labelMap\n    }\n\n    if (this.visualizedComponents.length === 0) {\n      return null\n    } else if (!!labelMap && this.visualizedComponents.length === 4) {\n      return null\n    }\n\n    const imageScalars = image.getPointData().getScalars()\n    const imageData = imageScalars.getData()\n    const imageComponents = imageScalars.getNumberOfComponents()\n\n    this.totalIntensityComponents = imageComponents\n\n    if (!!!labelMap && imageComponents <= 4) {\n      return image\n    }\n\n    const visualizedComponents = this.visualizedComponents.map(idx => idx)\n\n    const fusedImage = vtkImageData.newInstance()\n    fusedImage.setOrigin(image.getOrigin())\n    fusedImage.setSpacing(image.getSpacing())\n    fusedImage.setDirection(image.getDirection())\n    const imageDimensions = image.getDimensions()\n\n    if (!!labelMap) {\n      const labelMapDimensions = labelMap.getDimensions()\n      const dimensionsEqual = imageDimensions.every((dim, index) => {\n        return labelMapDimensions[index] === dim\n      })\n      if (!dimensionsEqual) {\n        console.error(\n          `Dimensions not equal! Not fusing. Image: ${imageDimensions} Label map: ${labelMapDimensions}`\n        )\n        return image\n      }\n    }\n\n    const numVisualizedComponents = this.visualizedComponents.length\n\n    fusedImage.setDimensions(image.getDimensions())\n\n    const imageTuples = imageScalars.getNumberOfTuples()\n\n    let labelMapScalars = null\n    let labelMapData = null\n\n    if (!!labelMap) {\n      labelMapScalars = labelMap.getPointData().getScalars()\n      labelMapData = labelMapScalars.getData()\n      visualizedComponents.push(-1)\n    }\n\n    const fusedImageComponents = labelMapData\n      ? numVisualizedComponents + 1\n      : numVisualizedComponents\n\n    const length = imageTuples * fusedImageComponents\n\n    // We only need to construct a new typed array if we don't already\n    // have one of the right length.\n    if (!!!this.fusedImageData || this.fusedImageData.length !== length) {\n      this.fusedImageData = new imageData.constructor(length)\n    }\n\n    const copyStructure = []\n\n    // Loop through comparing to last time and check which components need\n    // to be copied into fusedImageData.  This loop doesn't include the\n    // labelmap componentm, it will be checked next.\n    for (let i = 0; i < numVisualizedComponents; i++) {\n      if (visualizedComponents[i] !== this.lastVisualizedComponents[i]) {\n        copyStructure.push({\n          srcImageData: imageData,\n          imageComponents: imageComponents,\n          copyFromComponent: this.visualizedComponents[i],\n          copyToComponent: i,\n        })\n      }\n    }\n\n    // Check if we need to re-copy the labelmap component\n    if (\n      visualizedComponents[numVisualizedComponents] === -1 &&\n      this.lastVisualizedComponents[numVisualizedComponents] !== -1\n    ) {\n      copyStructure.push({\n        srcImageData: labelMapData,\n        imageComponents: 1,\n        copyFromComponent: 0,\n        copyToComponent: numVisualizedComponents,\n      })\n    }\n\n    // console.log(`Copying ${copyStructure.length} components into fused image`)\n\n    let fusedIndex = 0\n    let imageIndex = 0\n    for (let tuple = 0; tuple < imageTuples; tuple++) {\n      for (let cIdx = 0; cIdx < copyStructure.length; cIdx++) {\n        imageIndex =\n          tuple * copyStructure[cIdx].imageComponents +\n          copyStructure[cIdx].copyFromComponent\n        fusedIndex =\n          tuple * fusedImageComponents + copyStructure[cIdx].copyToComponent\n        this.fusedImageData[fusedIndex] =\n          copyStructure[cIdx].srcImageData[imageIndex]\n      }\n    }\n\n    const fusedImageScalars = vtkDataArray.newInstance({\n      name: imageScalars.getName() || 'Scalars',\n      values: this.fusedImageData,\n      numberOfComponents: fusedImageComponents,\n    })\n\n    fusedImage.getPointData().setScalars(fusedImageScalars)\n    this.lastVisualizedComponents = visualizedComponents.map(idx => idx)\n    return fusedImage\n  }\n\n  @computed get haveOnlyLabelMap() {\n    return (\n      (!!this.labelMap || !!this.multiscaleLabelMap) &&\n      !!!this.image &&\n      !!!this.multiscaleImage\n    )\n  }\n  @computed get haveLabelMap() {\n    return !!this.labelMap || !!this.multiscaleLabelMap\n  }\n\n  labelMapColorUIGroup = null\n  // Sorted array of label values\n  labelMapLabels = null\n  piecewiseFunction = null\n\n  @observable lastPickedValues = {}\n\n  @observable labelMapBlend = 0.5\n  @observable labelMapLookupTable = 'glasbey'\n\n  @observable labelMapWeights = []\n  @observable labelMapToggleWeight = 0.1\n  @observable selectedLabel = 'all'\n\n  planeIndexUIGroup = null\n\n  distanceWidget = null\n  distanceUpdateInProgress = false\n  distanceEnabled = false\n\n  @observable distancePoint1 = 0.0\n  @observable distancePoint2 = 0.0\n}\n\nclass GeometriesUIStore {\n  constructor(eventEmitter) {\n    this.eventEmitter = eventEmitter\n  }\n\n  eventEmitter = null\n\n  @observable.shallow geometries = []\n\n  initialized = false\n  sources = []\n  representationProxies = []\n\n  @observable selectedGeometryIndex = 0\n  @observable names = []\n  @observable representations = []\n  @observable colorMaps = []\n  @observable colorBy = []\n  @observable colors = []\n  @observable opacities = []\n  @observable colorRanges = new Map()\n  colorRangesReactions = new Map()\n  @computed get hasScalars() {\n    return this.geometries.map(geometry => {\n      const pointDataScalars = !!geometry.getPointData().getScalars()\n      const cellDataScalars = !!geometry.getCellData().getScalars()\n\n      return pointDataScalars || cellDataScalars\n    })\n  }\n  @computed get hasOnlyDirectColors() {\n    return this.geometries.map(geometry => {\n      const pointDataScalars = geometry.getPointData().getScalars()\n      const pointDataDirectColors =\n        !!pointDataScalars &&\n        pointDataScalars.getDataType() === VtkDataTypes.UNSIGNED_CHAR &&\n        pointDataScalars.getNumberOfComponents() === 3\n      const cellDataScalars = geometry.getCellData().getScalars()\n      const cellDataDirectColors =\n        !!cellDataScalars &&\n        cellDataScalars.getDataType() === VtkDataTypes.UNSIGNED_CHAR &&\n        cellDataScalars.getNumberOfComponents() === 3\n\n      return pointDataDirectColors && cellDataDirectColors\n    })\n  }\n  @computed get colorByOptions() {\n    return this.geometries.map((geometry, index) => {\n      if (!this.hasScalars[index]) {\n        return null\n      }\n      const options = [].concat(\n        geometry\n          .getPointData()\n          .getArrays()\n          .map(a => ({\n            label: `Points: ${a.getName()}`,\n            value: `pointData:${a.getName()}`,\n          })),\n        geometry\n          .getCellData()\n          .getArrays()\n          .map(a => ({\n            label: `Cells: ${a.getName()}`,\n            value: `cellData:${a.getName()}`,\n          }))\n      )\n      return options\n    })\n  }\n  @computed get colorByDefault() {\n    return this.geometries.map((geometry, index) => {\n      if (!this.hasScalars[index]) {\n        return null\n      }\n      const pointData = geometry.getPointData()\n      if (!!pointData.getScalars()) {\n        const activeIndex = pointData.getActiveScalars()\n        const activeArray = pointData.getArrays()[activeIndex]\n        return observable({\n          label: `Points: ${activeArray.getName()}`,\n          value: `pointData:${activeArray.getName()}`,\n        })\n      }\n      const cellData = geometry.getCellData()\n      if (!!cellData.getScalars()) {\n        const activeIndex = cellData.getActiveScalars()\n        const activeArray = cellData.getArrays()[activeIndex]\n        return observable({\n          label: `Cells: ${activeArray.getName()}`,\n          value: `cellData:${activeArray.getName()}`,\n        })\n      }\n      throw new Error('Should not reach here.')\n    })\n  }\n  @computed get selectedColorRange() {\n    const geometryIndex = this.selectedGeometryIndex\n    if (!this.hasScalars[geometryIndex]) {\n      return null\n    }\n    const colorByKey = this.colorBy[geometryIndex].value\n    return this.colorRanges.get(geometryIndex).get(colorByKey)\n  }\n  @computed get selectedLookupTableProxy() {\n    const geometryIndex = this.selectedGeometryIndex\n    if (!this.hasScalars[geometryIndex]) {\n      return null\n    }\n    const proxy = this.representationProxies[geometryIndex]\n    const [colorByArrayName, location] = proxy.getColorBy()\n    return proxy.getLookupTableProxy(colorByArrayName, location)\n  }\n}\n\nclass PointSetsUIStore {\n  constructor(eventEmitter) {\n    this.eventEmitter = eventEmitter\n  }\n\n  eventEmitter = null\n\n  @observable.shallow pointSets = []\n\n  initialized = false\n  sources = []\n  representationProxies = []\n\n  @observable selectedPointSetIndex = 0\n  @observable names = []\n  @observable representations = []\n  @observable colorMaps = []\n  @observable colorBy = []\n  @observable colors = []\n  @observable opacities = []\n  @observable sizes = []\n  @observable colorRanges = new Map()\n  colorRangesReactions = new Map()\n\n  lengthPixelRatio = 0.1\n\n  @computed get hasScalars() {\n    return this.pointSets.map(pointSet => {\n      const pointData = pointSet.getPointData()\n      const hasPointDataScalars = !!pointData.getScalars()\n      return hasPointDataScalars\n    })\n  }\n  @computed get colorByOptions() {\n    return this.pointSets.map((pointSet, index) => {\n      if (!this.hasScalars[index]) {\n        return null\n      }\n      const options = [].concat(\n        pointSet\n          .getPointData()\n          .getArrays()\n          .map(a => ({\n            label: `${a.getName()}`,\n            value: `pointData:${a.getName()}`,\n          }))\n      )\n      return options\n    })\n  }\n  @computed get colorByDefault() {\n    return this.pointSets.map((pointSet, index) => {\n      if (!this.hasScalars[index]) {\n        return null\n      }\n      const pointData = pointSet.getPointData()\n      if (!!pointData.getScalars()) {\n        const activeIndex = pointData.getActiveScalars()\n        const activeArray = pointData.getArrays()[activeIndex]\n        return {\n          label: `${activeArray.getName()}`,\n          value: `pointData:${activeArray.getName()}`,\n        }\n      }\n      throw new Error('Should not reach here.')\n    })\n  }\n  @computed get selectedColorRange() {\n    const selectedIndex = this.selectedPointSetIndex\n    if (!this.hasScalars[selectedIndex]) {\n      return null\n    }\n    const colorByKey = this.colorBy[selectedIndex].value\n    return this.colorRanges.get(selectedIndex).get(colorByKey)\n  }\n  @computed get selectedLookupTableProxy() {\n    const selectedIndex = this.selectedPointSetIndex\n    if (!this.hasScalars[selectedIndex]) {\n      return null\n    }\n    const proxy = this.representationProxies[selectedIndex]\n    const [colorByArrayName, location] = proxy.getColorBy()\n    return proxy.getLookupTableProxy(colorByArrayName, location)\n  }\n}\n\nclass ViewerStore {\n  constructor(proxyManager) {\n    this.eventEmitter = new EventEmitter()\n\n    this.mainUI = new MainUIStore(this.eventEmitter)\n    this.imageUI = new ImageUIStore(this.eventEmitter)\n    this.geometriesUI = new GeometriesUIStore(this.eventEmitter)\n    this.pointSetsUI = new PointSetsUIStore(this.eventEmitter)\n\n    this.id =\n      'itk-vtk-viewer-' +\n      performance\n        .now()\n        .toString()\n        .replace('.', '')\n    this.proxyManager = proxyManager\n    this.itkVtkView = proxyManager.createProxy('Views', 'ItkVtkView')\n    this.container = document.createElement('div')\n    this.itkVtkView.setContainer(this.container)\n\n    //this.imageUI.source = proxyManager.createProxy(\n    //'Sources',\n    //'TrivialProducer',\n    //{ name: 'Image' }\n    //)\n  }\n\n  eventEmitter = null\n  container = null\n  id = 'itk-vtk-viewer'\n  proxyManager = null\n  itkVtkView = null\n  get renderWindow() {\n    return this.itkVtkView.getRenderWindow()\n  }\n\n  @computed get isBackgroundDark() {\n    const backgroundColor = this.style.backgroundColor\n    return backgroundColor[0] + backgroundColor[1] + backgroundColor[2] < 1.5\n  }\n\n  @observable style = {\n    backgroundColor: [0.5, 0.5, 0.5],\n    containerStyle: STYLE_RENDERING_VIEW_CONTAINER,\n  }\n\n  mainUI = null\n  imageUI = null\n  geometriesUI = null\n  pointSetsUI = null\n}\n\nexport default ViewerStore\n"
  },
  {
    "path": "src/createViewer.js",
    "content": "import structuredClone from 'core-js/actual/structured-clone'\nif (!('structuredClone' in window)) {\n  // Attach the polyfill as a Global function\n  window.structuredClone = structuredClone\n}\nimport { mat4 } from 'gl-matrix'\nimport { inspect } from '@xstate/inspect'\nimport { interpret } from 'xstate'\n\nimport vtkProxyManager from 'vtk.js/Sources/Proxy/Core/ProxyManager'\n\nimport ResizeSensor from 'css-element-queries/src/ResizeSensor'\n\nimport proxyConfiguration from './Rendering/VTKJS/proxyManagerConfiguration'\nimport UserInterface from './UserInterface'\nimport addKeyboardShortcuts from './UI/addKeyboardShortcuts'\nimport rgb2hex from './UserInterface/rgb2hex'\nimport hex2rgb from './UserInterface/hex2rgb'\nimport ViewerStore from './ViewerStore'\n\nimport toMultiscaleSpatialImage from './IO/toMultiscaleSpatialImage'\nimport { worldBoundsToIndexBounds } from './IO/MultiscaleSpatialImage'\nimport viewerMachineOptions from './viewerMachineOptions'\nimport createViewerMachine from './createViewerMachine'\nimport ViewerMachineContext from './Context/ViewerMachineContext'\nimport {\n  addCroppingPlanes,\n  getCropWidgetBounds,\n  updateCroppingParameters,\n} from './Rendering/VTKJS/Main/croppingPlanes'\n\nimport { reaction, toJS } from 'mobx'\nimport PQueue from 'p-queue'\n\nconst createViewer = async (\n  rootContainer,\n  {\n    image,\n    imageName = undefined,\n    labelImage,\n    fixedImage,\n    compare,\n    geometries,\n    pointSets,\n    use2D = undefined, // if undefined, use image dimension if exists\n    rotate = true,\n    config,\n    gradientOpacity,\n  }\n) => {\n  UserInterface.emptyContainer(rootContainer)\n  if (!UserInterface.checkForWebGL(rootContainer)) {\n    throw new Error('WebGL could not be loaded.')\n  }\n\n  const proxyManager = vtkProxyManager.newInstance({ proxyConfiguration })\n  window.addEventListener('resize', proxyManager.resizeAllViews)\n\n  const store = new ViewerStore(proxyManager)\n\n  const publicAPI = {}\n\n  const debug = false\n  if (debug) {\n    //const stateIFrame = document.createElement('iframe')\n    //store.container.style.height = '50%'\n    //stateIFrame.style.height = '50%'\n    //rootContainer.appendChild(stateIFrame)\n    inspect({\n      //iframe: stateIFrame,\n      iframe: false,\n    })\n  }\n\n  const eventEmitter = store.eventEmitter\n\n  function eventEmitterCallback(context /*, event*/) {\n    return (callback, onReceive) => {\n      onReceive(event => {\n        switch (event.type) {\n          case 'SET_BACKGROUND_COLOR':\n            eventEmitter.emit('backgroundColorChanged', event.data)\n            break\n          case 'TOGGLE_BACKGROUND_COLOR':\n            eventEmitter.emit(\n              'backgroundColorChanged',\n              context.main.backgroundColor\n            )\n            break\n          case 'TOGGLE_FULLSCREEN':\n            eventEmitter.emit(\n              'toggleFullscreen',\n              publicAPI.getFullscreenEnabled()\n            )\n            break\n          case 'TOGGLE_UI_COLLAPSED':\n            eventEmitter.emit('toggleUICollapsed', event.data)\n            break\n          case 'TOGGLE_ROTATE':\n            eventEmitter.emit('toggleRotate', event.data)\n            break\n          case 'TOGGLE_ANNOTATIONS':\n            eventEmitter.emit(\n              'toggleAnnotations',\n              publicAPI.getAnnotationsEnabled()\n            )\n            break\n          case 'TOGGLE_AXES':\n            eventEmitter.emit('toggleAxes', event.data)\n            break\n          case 'TOGGLE_IMAGE_INTERPOLATION':\n            eventEmitter.emit('toggleImageInterpolation', event.data)\n            break\n          case 'TOGGLE_CROPPING_PLANES':\n            eventEmitter.emit('toggleCroppingPlanes', event.data)\n            break\n          case 'RESET_CROPPING_PLANES':\n            eventEmitter.emit('resetCroppingPlanes', event.data)\n            break\n          case 'CROPPING_PLANES_CHANGED':\n            eventEmitter.emit('croppingPlanesChanged', event.data)\n            break\n          case 'VIEW_MODE_CHANGED':\n            eventEmitter.emit('viewModeChanged', event.data)\n            break\n          case 'TOGGLE_LAYER_VISIBILITY':\n            eventEmitter.emit('toggleLayerVisibility', event.data)\n            break\n          case 'RENDERED_IMAGE_ASSIGNED':\n            eventEmitter.emit('renderedImageAssigned', event.data)\n            break\n          case 'IMAGE_COMPONENT_VISIBILITY_CHANGED':\n            eventEmitter.emit('imageVisualizedComponentChanged', event.data)\n            break\n          case 'IMAGE_PIECEWISE_FUNCTION_GAUSSIANS_CHANGED':\n            eventEmitter.emit(\n              'imagePiecewiseFunctionGaussiansChanged',\n              event.data\n            )\n            break\n          case 'IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED':\n            eventEmitter.emit('imagePiecewiseFunctionPointsChanged', event.data)\n            break\n          case 'IMAGE_COLOR_RANGE_CHANGED':\n            eventEmitter.emit('imageColorRangeChanged', event.data)\n            break\n          case 'IMAGE_COLOR_RANGE_BOUNDS_CHANGED':\n            eventEmitter.emit('imageColorRangeBoundsChanged', event.data)\n            break\n          case 'IMAGE_COLOR_MAP_CHANGED':\n            eventEmitter.emit('imageColorMapChanged', event.data)\n            break\n          case 'TOGGLE_IMAGE_SHADOW':\n            eventEmitter.emit('toggleImageShadow', event.data)\n            break\n          case 'IMAGE_GRADIENT_OPACITY_CHANGED':\n            eventEmitter.emit('imageGradientOpacityChanged', event.data)\n            break\n          case 'IMAGE_GRADIENT_OPACITY_SCALE_CHANGED':\n            eventEmitter.emit('imageGradientOpacityScaleChanged', event.data)\n            break\n          case 'IMAGE_VOLUME_SAMPLE_DISTANCE_CHANGED':\n            eventEmitter.emit('imageVolumeSampleDistanceChanged', event.data)\n            break\n          case 'IMAGE_BLEND_MODE_CHANGED':\n            eventEmitter.emit('imageBlendModeChanged', event.data)\n            break\n          case 'LABEL_IMAGE_LOOKUP_TABLE_CHANGED':\n            eventEmitter.emit('labelImageLookupTableChanged', event.data)\n            break\n          case 'LABEL_IMAGE_BLEND_CHANGED':\n            eventEmitter.emit('labelImageBlendChanged', event.data)\n            break\n          case 'LABEL_IMAGE_WEIGHTS_CHANGED':\n            eventEmitter.emit('labelImageWeightsChanged', event.data)\n            break\n          case 'LABEL_IMAGE_LABEL_NAMES_CHANGED':\n            eventEmitter.emit('labelImageLabelNamesChanged', event.data)\n            break\n          case 'X_SLICE_CHANGED':\n            eventEmitter.emit('xSliceChanged', event.data)\n            break\n          case 'Y_SLICE_CHANGED':\n            eventEmitter.emit('ySliceChanged', event.data)\n            break\n          case 'Z_SLICE_CHANGED':\n            eventEmitter.emit('zSliceChanged', event.data)\n            break\n          case 'SCREENSHOT_TAKEN':\n            eventEmitter.emit('screenshotTaken', event.data)\n            break\n          case 'TAKE_SCREENSHOT':\n            break\n          default:\n            throw new Error(`Unexpected event type: ${event.type}`)\n        }\n      })\n    }\n  }\n\n  const context = new ViewerMachineContext(config)\n  const options = { ...viewerMachineOptions }\n  if (context.uiMachineOptions !== 'reference') {\n    const uiMachineOptions = context.uiMachineOptions\n    if (uiMachineOptions.href) {\n      const loadedUIMachineOptions = await import(\n        /* webpackIgnore: true */\n        uiMachineOptions.href\n      )\n      if (uiMachineOptions.export) {\n        options.ui = loadedUIMachineOptions[uiMachineOptions.export]\n      } else {\n        options.ui = loadedUIMachineOptions.default\n      }\n    } else if (context.uiMachineOptions === 'pydata-sphinx') {\n      options.ui = {\n        href:\n          'https://cdn.jsdelivr.net/npm/itk-viewer-bootstrap-ui@0/dist/bootstrapUIMachineOptions.js.es.js',\n        export: 'default',\n      }\n    } else if (context.uiMachineOptions === 'mui') {\n      options.ui = {\n        href:\n          'https://cdn.jsdelivr.net/npm/itk-viewer-material-ui@0/dist/materialUIMachineOptions.js.es.js',\n        export: 'default',\n      }\n    } else {\n      options.ui = uiMachineOptions\n    }\n  }\n\n  const imageMultiscale =\n    image &&\n    (await toMultiscaleSpatialImage(image, false, context.maxConcurrency))\n\n  const labelImageMultiscale =\n    labelImage &&\n    (await toMultiscaleSpatialImage(labelImage, true, context.maxConcurrency))\n\n  const imageOrLabelImage = imageMultiscale || labelImageMultiscale\n\n  context.use2D =\n    use2D ??\n    Boolean(imageOrLabelImage && imageOrLabelImage.imageType.dimension === 2)\n\n  context.rootContainer = rootContainer\n  // Todo: move to viewer machine\n  context.container = store.container\n  // Todo: move to VTKJS/createRenderer\n  context.itkVtkView = store.itkVtkView\n  context.proxyManager = store.proxyManager\n  context.renderWindow = store.renderWindow\n  context.id = store.id\n  const machine = createViewerMachine(options, context, eventEmitterCallback)\n  const service = interpret(machine, { devTools: debug })\n  context.service = service\n  service.start()\n\n  reaction(\n    () =>\n      !!store.geometriesUI.geometries && store.geometriesUI.geometries.slice(),\n    geometries => {\n      if (!geometries || geometries.length === 0) {\n        return\n      }\n\n      geometries.forEach((geometry, index) => {\n        if (store.geometriesUI.sources.length <= index) {\n          const uid = `GeometrySource${index}`\n          const geometrySource = proxyManager.createProxy(\n            'Sources',\n            'TrivialProducer',\n            {\n              name: uid,\n            }\n          )\n          store.geometriesUI.sources.push(geometrySource)\n          store.geometriesUI.sources[index].setInputData(geometry)\n          proxyManager.createRepresentationInAllViews(geometrySource)\n          const geometryRepresentation = proxyManager.getRepresentation(\n            geometrySource,\n            store.itkVtkView\n          )\n          store.geometriesUI.representationProxies.push(geometryRepresentation)\n\n          addCroppingPlanes(context, geometryRepresentation)\n        } else {\n          store.geometriesUI.sources[index].setInputData(geometry)\n          store.geometriesUI.representationProxies[index].setVisibility(true)\n        }\n      })\n      updateCroppingParameters(context)\n\n      if (geometries.length < store.geometriesUI.representationProxies.length) {\n        const proxiesToDisable = store.geometriesUI.representationProxies.slice(\n          geometries.length\n        )\n        proxiesToDisable.forEach(proxy => {\n          proxy.setVisibility(false)\n        })\n      }\n\n      if (!store.geometriesUI.initialized) {\n        UserInterface.createGeometriesUI(store, context.uiContainer)\n      }\n      store.geometriesUI.names = geometries.map(\n        (geometry, index) => `Geometry ${index}`\n      )\n      let representations = store.geometriesUI.representations.slice(\n        0,\n        geometries.length\n      )\n      const defaultGeometryRepresentations = new Array(geometries.length)\n      defaultGeometryRepresentations.fill('Surface')\n      representations.concat(\n        defaultGeometryRepresentations.slice(\n          0,\n          geometries.length - representations.length\n        )\n      )\n      store.geometriesUI.representations = representations\n    }\n  )\n  store.geometriesUI.geometries = geometries\n\n  reaction(\n    () => !!store.pointSetsUI.pointSets && store.pointSetsUI.pointSets.slice(),\n    pointSets => {\n      if (!pointSets || pointSets.length === 0) {\n        return\n      }\n\n      pointSets.forEach((pointSet, index) => {\n        if (store.pointSetsUI.sources.length <= index) {\n          const uid = `PointSetSource${index}`\n          const pointSetSource = proxyManager.createProxy(\n            'Sources',\n            'TrivialProducer',\n            {\n              name: uid,\n            }\n          )\n          store.pointSetsUI.sources.push(pointSetSource)\n          store.pointSetsUI.sources[index].setInputData(pointSet)\n          const pointSetRepresentationUid = `pointSetRepresentation${index}`\n          const pointSetRepresentation = proxyManager.createProxy(\n            'Representations',\n            'PointSet',\n            {\n              name: pointSetRepresentationUid,\n            }\n          )\n          pointSetRepresentation.setInput(pointSetSource)\n          pointSetRepresentation.setRadiusFactor(\n            store.pointSetsUI.lengthPixelRatio\n          )\n          store.itkVtkView.addRepresentation(pointSetRepresentation)\n          store.pointSetsUI.representationProxies.push(pointSetRepresentation)\n\n          addCroppingPlanes(context, pointSetRepresentation)\n        } else {\n          store.pointSetsUI.sources[index].setInputData(pointSet)\n          store.pointSetsUI.representationProxies[index].setVisibility(true)\n        }\n      })\n      updateCroppingParameters(context)\n\n      if (pointSets.length < store.pointSetsUI.representationProxies.length) {\n        const proxiesToDisable = store.pointSetsUI.representationProxies.slice(\n          pointSets.length\n        )\n        proxiesToDisable.forEach(proxy => {\n          proxy.setVisibility(false)\n        })\n      }\n\n      if (!store.pointSetsUI.initialized) {\n        UserInterface.createPointSetsUI(store, context.uiContainer)\n      }\n    }\n  )\n  store.pointSetsUI.pointSets = pointSets\n\n  store.itkVtkView.resize()\n  // eslint-disable-next-line no-unused-vars\n  const resizeSensor = new ResizeSensor(store.container, function() {\n    store.itkVtkView.resize()\n  })\n  proxyManager.renderAllViews()\n\n  setTimeout(() => {\n    store.itkVtkView.resetCamera()\n\n    // Estimate a reasonable point sphere radius in pixels\n    const lengthPixelRatio = store.itkVtkView.getLengthPixelRatio()\n    store.pointSetsUI.lengthPixelRatio = lengthPixelRatio\n    store.pointSetsUI.representationProxies.forEach(proxy => {\n      proxy.setRadiusFactor(lengthPixelRatio)\n    })\n  }, 1)\n\n  UserInterface.addLogo(store)\n\n  publicAPI.render = () => {\n    service.send('RENDER')\n  }\n\n  // The `store` is considered an internal implementation detail\n  // and its interface and behavior may change without changes to the major version.\n  publicAPI.getStore = () => {\n    return store\n  }\n\n  publicAPI.setPointSets = pointSets => {\n    store.pointSetsUI.pointSets = pointSets\n  }\n\n  publicAPI.setGeometries = geometries => {\n    store.geometriesUI.geometries = geometries\n  }\n\n  const eventNames = [\n    'toggleUICollapsed',\n    'backgroundColorChanged',\n    'toggleFullscreen',\n    'toggleAnnotations',\n    'toggleAxes',\n    'toggleRotate',\n    'toggleCroppingPlanes',\n    'croppingPlanesChanged',\n    'resetCroppingPlanes',\n    'viewModeChanged',\n    'xSliceChanged',\n    'ySliceChanged',\n    'zSliceChanged',\n    'toggleLayerVisibility',\n    'imagePicked',\n    'imagePiecewiseFunctionGaussiansChanged',\n    'imagePiecewiseFunctionPointsChanged',\n    'imageVisualizedComponentChanged',\n    'toggleImageInterpolation',\n    'imageColorRangeChanged',\n    'imageColorRangeBoundsChanged',\n    'imageColorMapChanged',\n    'toggleImageShadow',\n    'imageGradientOpacityChanged',\n    'imageGradientOpacityScaleChanged',\n    'imageVolumeSampleDistanceChanged',\n    'imageBlendModeChanged',\n    'labelImageLookupTableChanged',\n    'labelImageBlendChanged',\n    'labelImageLabelNamesChanged',\n    'labelImageWeightsChanged',\n    'pointSetColorChanged',\n    'pointSetOpacityChanged',\n    'pointSetSizeChanged',\n    'pointSetRepresentationChanged',\n    'screenshotTaken',\n  ]\n\n  publicAPI.getEventNames = () => eventNames\n\n  publicAPI.on = (...onArgs) => eventEmitter.on(...onArgs)\n  publicAPI.off = (...offArgs) => eventEmitter.off(...offArgs)\n  publicAPI.once = (...onceArgs) => eventEmitter.once(...onceArgs)\n\n  publicAPI.getEventEmitter = () => eventEmitter\n\n  publicAPI.getConfig = () => {\n    return context.getConfig()\n  }\n\n  publicAPI.setUICollapsed = collapse => {\n    if (collapse !== context.uiCollapsed) {\n      service.send('TOGGLE_UI_COLLAPSED')\n    }\n  }\n\n  publicAPI.getUICollapsed = () => {\n    return context.uiCollapsed\n  }\n\n  publicAPI.setRenderingViewContainerStyle = containerStyle => {\n    service.send({\n      type: 'STYLE_RENDERING_VIEW_CONTAINER',\n      data: containerStyle,\n    })\n  }\n\n  publicAPI.getRenderingViewContainerStyle = () => {\n    return { ...context.renderingViewContainerStyle }\n  }\n\n  reaction(\n    () => {\n      return store.imageUI.lastPickedValues\n    },\n    () => {\n      const lastPickedValues = store.imageUI.lastPickedValues\n      eventEmitter.emit('imagePicked', toJS(lastPickedValues))\n    }\n  )\n\n  publicAPI.setBackgroundColor = bgColor => {\n    service.send({ type: 'SET_BACKGROUND_COLOR', data: bgColor })\n  }\n\n  publicAPI.getBackgroundColor = () => {\n    return context.main.backgroundColor.slice()\n  }\n\n  publicAPI.setUnits = units => {\n    service.send({ type: 'SET_UNITS', data: units })\n  }\n\n  publicAPI.getUnits = () => {\n    return context.main.units\n  }\n\n  // Gaussians not supported\n  publicAPI.setImagePiecewiseFunctionGaussians = (\n    gaussians,\n    component,\n    name\n  ) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof component === 'undefined') {\n      component = 0\n    }\n    service.send({\n      type: 'IMAGE_PIECEWISE_FUNCTION_GAUSSIANS_CHANGED',\n      data: { name, component, gaussians },\n    })\n  }\n\n  // Gaussians not supported\n  publicAPI.getImagePiecewiseFunctionGaussians = (component, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof component === 'undefined') {\n      component = 0\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.piecewiseFunctionGaussians.get(component)\n  }\n\n  publicAPI.setImagePiecewiseFunctionPoints = (points, component, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof component === 'undefined') {\n      component = 0\n    }\n    service.send({\n      type: 'IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED',\n      data: { name, component, points },\n    })\n  }\n\n  publicAPI.getImagePiecewiseFunctionPoints = (component, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof component === 'undefined') {\n      component = 0\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.piecewiseFunctionPoints.get(component)\n  }\n\n  // Start collapsed on mobile devices or small pages\n  if (\n    (config &&\n      typeof config.uiCollapsed !== 'undefined' &&\n      window.screen.availWidth < 768) ||\n    window.screen.availHeight < 800\n  ) {\n    publicAPI.setUICollapsed(true)\n  }\n\n  publicAPI.captureImage = () => {\n    return store.itkVtkView.captureImage()\n  }\n\n  publicAPI.setAnnotationsEnabled = enabled => {\n    if (enabled !== context.main.annotationsEnabled) {\n      service.send('TOGGLE_ANNOTATIONS')\n    }\n  }\n\n  publicAPI.getAnnotationsEnabled = () => {\n    return context.main.annotationsEnabled\n  }\n\n  publicAPI.setAxesEnabled = enabled => {\n    if (enabled !== context.main.axesEnabled) {\n      service.send('TOGGLE_AXES')\n    }\n  }\n\n  publicAPI.getAxesEnabled = () => {\n    return context.main.axesEnabled\n  }\n\n  publicAPI.setRotateEnabled = enabled => {\n    if (enabled !== context.main.rotateEnabled) {\n      service.send('TOGGLE_ROTATE')\n    }\n  }\n\n  publicAPI.getRotateEnabled = () => {\n    return context.main.rotateEnabled\n  }\n\n  publicAPI.setFullscreenEnabled = enabled => {\n    if (enabled !== context.main.fullscreenEnabled) {\n      service.send('TOGGLE_FULLSCREEN')\n    }\n  }\n\n  publicAPI.getFullscreenEnabled = () => {\n    return context.main.fullscreenEnabled\n  }\n\n  publicAPI.setViewMode = mode => {\n    if (mode !== context.main.viewMode) {\n      service.send({ type: 'VIEW_MODE_CHANGED', data: mode })\n    }\n  }\n\n  publicAPI.getViewMode = () => {\n    return context.main.viewMode\n  }\n\n  publicAPI.setXSlice = position => {\n    service.send({\n      type: 'X_SLICE_CHANGED',\n      data: position,\n    })\n  }\n\n  publicAPI.getXSlice = () => {\n    return context.main.xSlice\n  }\n\n  publicAPI.setYSlice = position => {\n    service.send({\n      type: 'Y_SLICE_CHANGED',\n      data: position,\n    })\n  }\n\n  publicAPI.getYSlice = () => {\n    return context.main.ySlice\n  }\n\n  publicAPI.setZSlice = position => {\n    service.send({\n      type: 'Z_SLICE_CHANGED',\n      data: position,\n    })\n  }\n\n  publicAPI.getZSlice = () => {\n    return context.main.zSlice\n  }\n\n  publicAPI.getLayerNames = () => {\n    return Array.from(context.layers.actorContext.keys())\n  }\n\n  publicAPI.setLayerVisibility = (visible, name) => {\n    const actorContext = context.layers.actorContext.get(name)\n    if (visible !== actorContext.visible) {\n      context.service.send({ type: 'TOGGLE_LAYER_VISIBILITY', data: name })\n    }\n  }\n\n  publicAPI.getLayerVisibility = name => {\n    return context.layers.actorContext.get(name).visible\n  }\n\n  publicAPI.selectLayer = name => {\n    context.service.send({ type: 'SELECT_LAYER', data: name })\n  }\n\n  // A shared API queue lets setCompareImage wait for setImage.\n  // Otherwise imageActorContext setting events won't yet have a actor machine to receive them.\n  const apiFunctionQueue = new PQueue({ concurrency: 1 })\n  const queueApi = funcToQueue => (...args) =>\n    apiFunctionQueue.add(() => funcToQueue(...args))\n\n  // Queueing setImage syncs the order setImage(s) are called with the order image actorContexts are created, no matter the data passed.\n  // Some images take longer with toMultiscaleSpatialImage, then get sent to state machine later, even if they were called with viewer.setImage first.\n  // The last added image is the context.image.selectedImage\n  publicAPI.setImage = queueApi(async (image, imageName) => {\n    const name =\n      imageName ?? image.name ?? context.images?.selectedName ?? 'Image'\n    const multiscaleImage = await toMultiscaleSpatialImage(\n      image,\n      false,\n      context.maxConcurrency\n    )\n    multiscaleImage.name = name\n    if (context.images.actorContext.has(name)) {\n      const actorContext = context.images.actorContext.get(name)\n      actorContext.image = multiscaleImage\n      service.send({ type: 'IMAGE_ASSIGNED', data: name })\n    } else {\n      service.send({ type: 'ADD_IMAGE', data: multiscaleImage })\n    }\n  })\n\n  publicAPI.getImage = name => {\n    if (typeof name === 'undefined' && context.images.selectedName) {\n      name = context.images.selectedName\n    }\n    return context.images.actorContext.get(name).image\n  }\n\n  publicAPI.getImageInterpolationEnabled = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.interpolationEnabled\n  }\n\n  publicAPI.setImageInterpolationEnabled = (enabled, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const currentEnabled = publicAPI.getImageInterpolationEnabled(name)\n    if (enabled !== currentEnabled) {\n      service.send({ type: 'TOGGLE_IMAGE_INTERPOLATION', data: name })\n    }\n  }\n\n  publicAPI.setImageComponentVisibility = (visibility, component, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    service.send({\n      type: 'IMAGE_COMPONENT_VISIBILITY_CHANGED',\n      data: { name, component, visibility },\n    })\n  }\n\n  publicAPI.getImageComponentVisibility = (component, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.componentVisibilities[component]\n  }\n\n  publicAPI.setCroppingPlanesEnabled = enabled => {\n    if (enabled !== context.main.croppingPlanesEnabled) {\n      service.send('TOGGLE_CROPPING_PLANES')\n    }\n  }\n\n  publicAPI.getCroppingPlanesEnabled = () => {\n    return context.main.croppingPlanesEnabled\n  }\n\n  publicAPI.resetCroppingPlanes = () => {\n    service.send('RESET_CROPPING_PLANES')\n  }\n\n  publicAPI.getCroppingPlanes = () => {\n    return context.main.croppingPlanes\n  }\n\n  publicAPI.setCroppingPlanes = croppingPlanes => {\n    service.send({\n      type: 'CROPPING_PLANES_CHANGED',\n      data: croppingPlanes,\n    })\n  }\n\n  publicAPI.setImageColorRange = (range, component, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof component === 'undefined') {\n      component = 0\n    }\n    const actorContext = context.images.actorContext.get(name)\n    const currentRange = actorContext.colorRanges.get(component)\n    if (\n      typeof currentRange !== 'undefined' ||\n      currentRange[0] !== range[0] ||\n      currentRange[1] !== range[1]\n    ) {\n      service.send({\n        type: 'IMAGE_COLOR_RANGE_CHANGED',\n        data: { name, component, range },\n      })\n    }\n  }\n\n  publicAPI.getImageColorRange = (component, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof component === 'undefined') {\n      component = 0\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.colorRanges.get(component)\n  }\n\n  publicAPI.setImageColorRangeMin = (value, component, name) => {\n    const selectedComponent = component ?? 0\n    const selectedName = name ?? context.images.selectedName\n    service.send({\n      type: 'IMAGE_COLOR_RANGE_MIN_CHANGED',\n      data: { name: selectedName, component: selectedComponent, value },\n    })\n  }\n\n  publicAPI.setImageColorRangeMax = (value, component, name) => {\n    const selectedComponent = component ?? 0\n    const selectedName = name ?? context.images.selectedName\n    service.send({\n      type: 'IMAGE_COLOR_RANGE_MAX_CHANGED',\n      data: { name: selectedName, component: selectedComponent, value },\n    })\n  }\n\n  publicAPI.setImageColorRangeBounds = (range, component, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof component === 'undefined') {\n      component = 0\n    }\n    const actorContext = context.images.actorContext.get(name)\n    const currentRange = actorContext.colorRanges.get(component)\n    if (\n      typeof currentRange !== 'undefined' ||\n      currentRange[0] !== range[0] ||\n      currentRange[1] !== range[1]\n    ) {\n      service.send({\n        type: 'IMAGE_COLOR_RANGE_BOUNDS_CHANGED',\n        data: { name, component, range },\n      })\n    }\n  }\n\n  publicAPI.getImageColorRangeBounds = (component, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof component === 'undefined') {\n      component = 0\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.colorRangeBounds.get(component)\n  }\n\n  publicAPI.setImageColorMap = (colorMap, componentIndex, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof componentIndex === 'undefined') {\n      componentIndex = 0\n    }\n    const actorContext = context.images.actorContext.get(name)\n    const currentColorMap = actorContext.colorMaps.get(componentIndex)\n    if (\n      typeof currentColorMap !== 'undefined' ||\n      currentColorMap[0] !== colorMap[0] ||\n      currentColorMap[1] !== colorMap[1]\n    ) {\n      service.send({\n        type: 'IMAGE_COLOR_MAP_CHANGED',\n        data: { name, component: componentIndex, colorMap },\n      })\n    }\n  }\n\n  publicAPI.getImageColorMap = (componentIndex, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    if (typeof componentIndex === 'undefined') {\n      componentIndex = 0\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.colorMaps.get(componentIndex)\n  }\n\n  publicAPI.setLabelImage = queueApi(async (labelImage, layerImageName) => {\n    const multiscaleLabelImage = await toMultiscaleSpatialImage(\n      labelImage,\n      true,\n      context.maxConcurrency\n    )\n    if (multiscaleLabelImage.name === 'Image') {\n      multiscaleLabelImage.name = 'LabelImage'\n    }\n\n    const imageName =\n      layerImageName ?? context.images.selectedName ?? multiscaleLabelImage.name\n    const actorContext = context.images.actorContext.get(imageName)\n    if (actorContext?.labelImageName === multiscaleLabelImage.name) {\n      actorContext.labelImage = multiscaleLabelImage\n      service.send({ type: 'LABEL_IMAGE_ASSIGNED', data: imageName })\n    } else {\n      service.send({\n        type: 'ADD_LABEL_IMAGE',\n        data: { imageName, labelImage: multiscaleLabelImage },\n      })\n    }\n    publicAPI.setImageInterpolationEnabled(false, imageName)\n  })\n\n  publicAPI.getLabelImage = () => {\n    const name = context.images.selectedName\n    return context.images.actorContext.get(name).labelImage\n  }\n\n  publicAPI.setLabelImageLookupTable = (lookupTable, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    const currentLookupTable = actorContext.lookupTable\n    if (currentLookupTable !== lookupTable) {\n      service.send({\n        type: 'LABEL_IMAGE_LOOKUP_TABLE_CHANGED',\n        data: { name, lookupTable },\n      })\n    }\n  }\n\n  publicAPI.getLabelImageLookupTable = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.lookupTable\n  }\n\n  publicAPI.setLabelImageBlend = (blend, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    const currentBlend = actorContext.labelImageBlend\n    if (currentBlend !== blend) {\n      service.send({\n        type: 'LABEL_IMAGE_BLEND_CHANGED',\n        data: { name, labelImageBlend: blend },\n      })\n    }\n  }\n\n  publicAPI.getLabelImageBlend = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.labelImageBlend\n  }\n\n  publicAPI.setLabelImageLabelNames = (names, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    const currentLabelNames = actorContext.labelNames\n    if (currentLabelNames !== names) {\n      service.send({\n        type: 'LABEL_IMAGE_LABEL_NAMES_CHANGED',\n        data: { name, labelNames: names },\n      })\n    }\n  }\n\n  publicAPI.getLabelImageLabelNames = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.labelNames\n  }\n\n  publicAPI.setLabelImageWeights = (weights, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    const currentWeights = actorContext.labelImageWeights\n    if (currentWeights !== weights) {\n      service.send({\n        type: 'LABEL_IMAGE_WEIGHTS_CHANGED',\n        data: { name, labelImageWeights: weights },\n      })\n    }\n  }\n\n  publicAPI.getLabelImageWeights = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.labelImageWeights\n  }\n\n  // Moving image must have been added last.\n  // See index.md for parameter docs.\n  publicAPI.setCompareImages = queueApi(\n    async (fixedImageName, movingImageName, options) => {\n      service.send({\n        type: 'COMPARE_IMAGES',\n        data: {\n          name: movingImageName,\n          fixedImageName,\n          options,\n        },\n      })\n    }\n  )\n\n  publicAPI.getCompareImages = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    return context.images.actorContext.get(name).compare\n  }\n\n  publicAPI.setImageShadowEnabled = (enabled, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    if (enabled !== actorContext.shadowEnabled) {\n      service.send({\n        type: 'TOGGLE_IMAGE_SHADOW',\n        data: name,\n      })\n    }\n  }\n\n  publicAPI.getImageShadowEnabled = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.shadowEnabled\n  }\n\n  publicAPI.setImageGradientOpacity = (opacity, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    service.send({\n      type: 'IMAGE_GRADIENT_OPACITY_CHANGED',\n      data: { name, gradientOpacity: opacity },\n    })\n  }\n\n  publicAPI.getImageGradientOpacity = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.gradientOpacity\n  }\n\n  publicAPI.setImageGradientOpacityScale = (min, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    service.send({\n      type: 'IMAGE_GRADIENT_OPACITY_SCALE_CHANGED',\n      data: { name, gradientOpacityScale: min },\n    })\n  }\n\n  publicAPI.getImageGradientOpacityScale = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.gradientOpacityScale\n  }\n\n  publicAPI.setImageVolumeSampleDistance = (distance, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    service.send({\n      type: 'IMAGE_VOLUME_SAMPLE_DISTANCE_CHANGED',\n      data: { name, volumeSampleDistance: distance },\n    })\n  }\n\n  publicAPI.getImageVolumeSampleDistance = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.volumeSampleDistance\n  }\n\n  publicAPI.setImageBlendMode = (mode, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    service.send({\n      type: 'IMAGE_BLEND_MODE_CHANGED',\n      data: { name, blendMode: mode },\n    })\n  }\n\n  publicAPI.getImageBlendMode = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.blendMode\n  }\n\n  publicAPI.addPointSet = pointSet => {\n    if (!store.pointSetsUI.pointSets) {\n      store.pointSetsUI.pointSets = []\n    }\n    store.pointSetsUI.pointSets.push(pointSet)\n  }\n\n  reaction(\n    () => {\n      return store.pointSetsUI.colors.slice()\n    },\n    colors => {\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      const color = colors[selectedPointSetIndex]\n      eventEmitter.emit('pointSetColorChanged', selectedPointSetIndex, color)\n    }\n  )\n\n  publicAPI.setPointSetColor = (index, rgbColor) => {\n    const hexColor = rgb2hex(rgbColor)\n    if (index < store.pointSetsUI.colors.length) {\n      store.pointSetsUI.colors[index] = hexColor\n    }\n  }\n\n  publicAPI.getPointSetColor = index => {\n    const hexColor = store.pointSetsUI.colors[index]\n    const rgbColor = hex2rgb(hexColor)\n    return rgbColor\n  }\n\n  reaction(\n    () => {\n      return store.pointSetsUI.opacities.slice()\n    },\n    opacities => {\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      const opacity = opacities[selectedPointSetIndex]\n      eventEmitter.emit(\n        'pointSetOpacityChanged',\n        selectedPointSetIndex,\n        opacity\n      )\n    }\n  )\n\n  publicAPI.setPointSetOpacity = (index, opacity) => {\n    if (index < store.pointSetsUI.opacities.length) {\n      store.pointSetsUI.opacities[index] = opacity\n    }\n  }\n\n  publicAPI.getPointSetOpacity = index => {\n    return store.pointSetsUI.opacities[index]\n  }\n\n  reaction(\n    () => {\n      return store.pointSetsUI.sizes.slice()\n    },\n    sizes => {\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      const size = sizes[selectedPointSetIndex]\n      eventEmitter.emit('pointSetSizeChanged', selectedPointSetIndex, size)\n    }\n  )\n\n  publicAPI.setPointSetSize = (index, size) => {\n    if (index < store.pointSetsUI.sizes.length) {\n      store.pointSetsUI.sizes[index] = size\n    }\n  }\n\n  publicAPI.getPointSetSize = index => {\n    return store.pointSetsUI.sizes[index]\n  }\n\n  reaction(\n    () => {\n      return store.pointSetsUI.representations.slice()\n    },\n    representations => {\n      const selectedPointSetIndex = store.pointSetsUI.selectedPointSetIndex\n      const representation = representations[selectedPointSetIndex]\n      eventEmitter.emit(\n        'pointSetRepresentationChanged',\n        selectedPointSetIndex,\n        representation\n      )\n    }\n  )\n\n  publicAPI.setPointSetRepresentation = (index, representation) => {\n    if (index < store.pointSetsUI.representations.length) {\n      store.pointSetsUI.representations[index] = representation\n    }\n  }\n\n  publicAPI.setGeometryColor = (index, rgbColor) => {\n    const hexColor = rgb2hex(rgbColor)\n    store.geometriesUI.colors[index] = hexColor\n  }\n\n  publicAPI.setGeometryOpacity = (index, opacity) => {\n    store.geometriesUI.opacities[index] = opacity\n  }\n\n  publicAPI.setImageScale = targetScale => {\n    service.send({\n      type: 'SET_IMAGE_SCALE',\n      targetScale,\n    })\n  }\n\n  // The `itkVtkView` is considered an internal implementation detail\n  // and its interface and behavior may change without changes to the major version.\n  publicAPI.getViewProxy = () => {\n    return store.itkVtkView\n  }\n\n  publicAPI.setImageVolumeScatteringBlend = (scatteringBlend, name) => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n\n    service.send({\n      type: 'SET_CINEMATIC_PARAMETERS',\n      data: {\n        name: context.images.selectedName,\n        params: { scatteringBlend },\n      },\n    })\n  }\n\n  publicAPI.getImageVolumeScatteringBlend = name => {\n    if (typeof name === 'undefined') {\n      name = context.images.selectedName\n    }\n    const actorContext = context.images.actorContext.get(name)\n    return actorContext.cinematicParameters.scatteringBlend\n  }\n\n  publicAPI.setMaxConcurrency = value => {\n    context.maxConcurrency = value\n  }\n\n  publicAPI.getMaxConcurrency = () => {\n    return context.maxConcurrency\n  }\n\n  publicAPI.getLoadedScale = name => {\n    const imageName = name ?? context.images.selectedName\n    const actorContext = context.images.actorContext.get(imageName)\n    return actorContext.loadedScale\n  }\n\n  publicAPI.getCroppedImageWorldBounds = () => {\n    return getCropWidgetBounds(context)\n  }\n\n  publicAPI.getCroppedIndexBounds = async (scale, name) => {\n    const imageName = name ?? context.images.selectedName\n    const actorContext = context.images.actorContext.get(imageName)\n    if (typeof scale === 'undefined' || scale < 0) {\n      scale = actorContext.loadedScale\n    }\n    const image = actorContext.image\n    const bounds = getCropWidgetBounds(context)\n    const indexToWorld = await image.scaleIndexToWorld(scale)\n    const fullIndexBounds = image.getIndexBounds(scale)\n    return worldBoundsToIndexBounds({\n      bounds,\n      fullIndexBounds,\n      worldToIndex: mat4.invert([], indexToWorld),\n    })\n  }\n\n  addKeyboardShortcuts(context.uiContainer, service)\n\n  // must come before moving/main image\n  if (fixedImage) {\n    await publicAPI.setImage(fixedImage, 'Fixed') // must await so fixedImage is the first one\n  }\n\n  if (imageMultiscale) {\n    await publicAPI.setImage(imageMultiscale, imageName) // await for image.name to get assigned for fixedImage and setCompareImages\n  }\n\n  if (labelImageMultiscale) {\n    publicAPI.setLabelImage(labelImageMultiscale, imageMultiscale?.name)\n  }\n\n  if (fixedImage && imageMultiscale) {\n    publicAPI.setCompareImages('Fixed', imageMultiscale.name, compare)\n  }\n\n  if (!context.use2D) {\n    publicAPI.setRotateEnabled(rotate)\n  }\n\n  // check with isNaN as may be 0\n  if (!isNaN(gradientOpacity)) {\n    publicAPI.setImageGradientOpacity(gradientOpacity)\n  }\n\n  return publicAPI\n}\n\nexport default createViewer\n"
  },
  {
    "path": "src/createViewerMachine.js",
    "content": "import { forwardTo, Machine } from 'xstate'\nimport createRenderingMachine from './Rendering/createRenderingMachine'\nimport createUIMachine from './UI/createUIMachine'\n\nconst createViewerMachine = (options, context, eventEmitterCallback) => {\n  const { ui, rendering } = options\n  const renderingMachine = createRenderingMachine(rendering, context)\n  const uiMachine = createUIMachine(ui, context)\n\n  return Machine(\n    {\n      id: 'viewer',\n      strict: true,\n      initial: 'idle',\n      context,\n      states: {\n        idle: {\n          always: {\n            target: 'active',\n            actions: [\n              'createRenderingViewContainers',\n              'styleRenderingViewContainers',\n            ],\n          },\n        },\n        active: {\n          invoke: [\n            {\n              id: 'ui',\n              src: uiMachine,\n            },\n            {\n              id: 'rendering',\n              src: renderingMachine,\n            },\n            {\n              id: 'eventEmitter',\n              src: eventEmitterCallback,\n            },\n          ],\n          on: {\n            STYLE_RENDERING_VIEW_CONTAINER: {\n              actions: 'styleRenderingViewContainers',\n            },\n            SET_BACKGROUND_COLOR: {\n              actions: [forwardTo('rendering'), forwardTo('eventEmitter')],\n            },\n            TOGGLE_BACKGROUND_COLOR: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            SET_UNITS: {\n              actions: [forwardTo('rendering')],\n            },\n            TOGGLE_DARK_MODE: {\n              actions: forwardTo('ui'),\n            },\n            TOGGLE_UI_COLLAPSED: {\n              actions: [forwardTo('ui'), forwardTo('eventEmitter')],\n            },\n            TOGGLE_FULLSCREEN: {\n              actions: [forwardTo('ui'), forwardTo('eventEmitter')],\n            },\n            DISABLE_FULLSCREEN: {\n              actions: forwardTo('ui'),\n            },\n            TAKE_SCREENSHOT: {\n              actions: [forwardTo('rendering'), forwardTo('eventEmitter')],\n            },\n            TOGGLE_ROTATE: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            TOGGLE_ANNOTATIONS: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            TOGGLE_AXES: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            TOGGLE_CROPPING_PLANES: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            RESET_CROPPING_PLANES: {\n              actions: [forwardTo('rendering'), forwardTo('eventEmitter')],\n            },\n            CROPPING_PLANES_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            CROPPING_PLANES_CHANGED_BY_USER: {\n              actions: forwardTo('rendering'),\n            },\n            VIEW_MODE_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            RESET_CAMERA: {\n              actions: forwardTo('rendering'),\n            },\n            SLICING_PLANES_CHANGED: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            X_SLICE_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            Y_SLICE_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            Z_SLICE_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            SELECT_LAYER: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            TOGGLE_LAYER_VISIBILITY: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            ADD_IMAGE: {\n              actions: forwardTo('ui'),\n            },\n            IMAGE_ASSIGNED: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            UPDATE_RENDERED_IMAGE: {\n              actions: [forwardTo('rendering')],\n            },\n            START_DATA_UPDATE: { actions: forwardTo('ui') },\n            FINISH_DATA_UPDATE: { actions: forwardTo('ui') },\n            POST_RENDER: { actions: forwardTo('ui') },\n            RENDERED_IMAGE_ASSIGNED: {\n              actions: [forwardTo('ui'), forwardTo('eventEmitter')],\n            },\n            IMAGE_RENDERING_ACTIVE: {\n              actions: forwardTo('ui'),\n            },\n            ADD_LABEL_IMAGE: {\n              actions: forwardTo('ui'),\n            },\n            LABEL_IMAGE_ASSIGNED: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            SELECT_IMAGE_COMPONENT: {\n              actions: forwardTo('ui'),\n            },\n            TOGGLE_IMAGE_INTERPOLATION: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_COMPONENT_VISIBILITY_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_PIECEWISE_FUNCTION_GAUSSIANS_CHANGED: {\n              actions: [forwardTo('ui'), forwardTo('eventEmitter')],\n            },\n            IMAGE_PIECEWISE_FUNCTION_CHANGED: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            IMAGE_PIECEWISE_FUNCTION_POINTS_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_COLOR_RANGE_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_COLOR_RANGE_MIN_CHANGED: {\n              actions: [forwardTo('rendering')],\n            },\n            IMAGE_COLOR_RANGE_MAX_CHANGED: {\n              actions: [forwardTo('rendering')],\n            },\n            IMAGE_COLOR_RANGE_POINTS_CHANGED: {\n              actions: [forwardTo('rendering')],\n            },\n            IMAGE_COLOR_RANGE_BOUNDS_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_COLOR_MAP_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_COLOR_MAP_DEPENDENCIES_UPDATE: {\n              actions: forwardTo('ui'),\n            },\n            TOGGLE_IMAGE_SHADOW: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_GRADIENT_OPACITY_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_GRADIENT_OPACITY_SCALE_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_VOLUME_SAMPLE_DISTANCE_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            IMAGE_BLEND_MODE_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            UPDATE_IMAGE_HISTOGRAM: {\n              actions: [forwardTo('rendering')],\n            },\n            IMAGE_HISTOGRAM_UPDATED: {\n              actions: [forwardTo('ui')],\n            },\n            LABEL_IMAGE_LOOKUP_TABLE_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            LABEL_IMAGE_BLEND_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            LABEL_IMAGE_WEIGHTS_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            LABEL_IMAGE_LABEL_NAMES_CHANGED: {\n              actions: [\n                forwardTo('ui'),\n                forwardTo('rendering'),\n                forwardTo('eventEmitter'),\n              ],\n            },\n            LABEL_IMAGE_SELECTED_LABEL_CHANGED: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            RENDER: {\n              actions: forwardTo('rendering'),\n            },\n            UPDATE_FPS: {\n              actions: forwardTo('rendering'),\n            },\n            FPS_UPDATED: {\n              actions: forwardTo('rendering'),\n            },\n            SET_IMAGE_SCALE: {\n              actions: forwardTo('rendering'),\n            },\n            SET_CINEMATIC_PARAMETERS: {\n              actions: forwardTo('rendering'),\n            },\n            CINEMATIC_CHANGED: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            REQUEST_ANIMATION: {\n              actions: forwardTo('rendering'),\n            },\n            CANCEL_ANIMATION: {\n              actions: forwardTo('rendering'),\n            },\n            TOGGLE_DISTANCE_WIDGET: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            DISTANCE_WIDGET_VALUE_CHANGED: {\n              actions: [forwardTo('ui')],\n            },\n            SCREENSHOT_TAKEN: {\n              actions: [forwardTo('eventEmitter')],\n            },\n            SET_FIXED_IMAGE: {\n              actions: forwardTo('rendering'),\n            },\n            COMPARE_IMAGES: {\n              actions: forwardTo('rendering'),\n            },\n            COMPARE_UPDATED: {\n              actions: forwardTo('ui'),\n            },\n            ANIMATE_IMAGE_MIX: {\n              actions: forwardTo('rendering'),\n            },\n            COMPONENT_VISIBILITIES_UPDATED: {\n              actions: forwardTo('ui'),\n            },\n            WINDOW_LEVEL_TOGGLED: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            IMAGE_COLOR_RANGE_RESET: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            TOGGLE_LAYER_BBOX: {\n              actions: [forwardTo('ui'), forwardTo('rendering')],\n            },\n            DOWNLOAD_IMAGE: {\n              actions: [forwardTo('rendering')],\n            },\n          },\n        },\n      },\n    },\n    options\n  )\n}\n\nexport default createViewerMachine\n"
  },
  {
    "path": "src/imJoyCodecs.js",
    "content": "import bloscZarrDecompress from './Compression/bloscZarrDecompress.js'\nimport { ImageType, Image, bufferToTypedArray } from 'itk-wasm'\n\nasync function decodeNumcodecEncoded(numcodecEncoded) {\n  const forBloscZarr = [\n    {\n      data: numcodecEncoded.buffer,\n      metadata: {\n        compressor: numcodecEncoded.config,\n        dtype: '|u1',\n        chunks: [numcodecEncoded.nbytes],\n      },\n    },\n  ]\n  const decompressed = await bloscZarrDecompress(forBloscZarr)\n  return decompressed[0]\n}\n\nasync function decodeItkWasmImage(wasmImage) {\n  const wasmImageType = wasmImage.imageType\n  const imageType = new ImageType(\n    wasmImageType.dimension,\n    wasmImageType.componentType,\n    wasmImageType.pixelType,\n    wasmImageType.components\n  )\n\n  const image = new Image(imageType)\n  image.origin = wasmImage.origin\n  image.spacing = wasmImage.spacing\n  const directionBuffer = await decodeNumcodecEncoded(wasmImage.direction)\n  image.direction = new Float64Array(directionBuffer)\n  image.size = wasmImage.size\n  const dataBuffer = await decodeNumcodecEncoded(wasmImage.data)\n  image.data = bufferToTypedArray(imageType.componentType, dataBuffer)\n\n  return image\n}\n\nconst imJoyCodecs = [\n  { name: 'numcodec-encoded', decoder: decodeNumcodecEncoded },\n  { name: 'itkwasm-image', decoder: decodeItkWasmImage },\n]\n\nexport default imJoyCodecs\n"
  },
  {
    "path": "src/index.d.ts",
    "content": "import { Image } from 'itk-wasm'\n\ndeclare interface Store {\n  getItem(): Promise<any>\n}\ndeclare type ndarray = {\n  _rtype: 'ndarray'\n}\n\ndeclare type LoadableImage = URL | Image | Store | ndarray\n\ndeclare type ViewerOptions = {\n  image?: LoadableImage\n  labelImage?: LoadableImage\n  geometries?: [any]\n  use2D?: boolean\n  rotate?: boolean\n  config?: any\n}\n\ntype Viewer = {\n  setBackgroundColor(color: [number, number, number]): void\n  setImageColorMap(mapName: string, actor: number): void\n}\n\ndeclare namespace itkVtkViewer {\n  function createViewer(\n    rootContainer: HTMLElement,\n    options?: ViewerOptions\n  ): Promise<Viewer>\n\n  function createViewerFromLocalFiles(container: HTMLElement): Promise<Viewer>\n\n  function createViewerFromFiles(\n    el: HTMLElement,\n    files: [any],\n    use2D?: boolean\n  ): Promise<Viewer>\n\n  function createViewerFromUrl(\n    el: HTMLElement,\n    options?: { files?: [string] } & ViewerOptions\n  ): Promise<Viewer>\n\n  function processURLParameters(\n    container: HTMLElement,\n    addOnParameters?: any\n  ): Promise<Viewer | null>\n\n  function initializeEmbeddedViewers(): void\n\n  type version = string\n}\n"
  },
  {
    "path": "src/index.js",
    "content": "import axios from 'axios'\n\nimport vtkURLExtract from 'vtk.js/Sources/Common/Core/URLExtract'\nimport { readImageArrayBuffer } from 'itk-wasm'\n\nimport fetchBinaryContent from './IO/fetchBinaryContent'\nimport fetchJsonContent from './IO/fetchJsonContent'\nimport { processFiles } from './IO/processFiles'\nimport UserInterface from './UserInterface'\nimport createFileDragAndDrop from './UserInterface/createFileDragAndDrop'\nimport style from './UserInterface/ItkVtkViewer.module.css'\nimport toMultiscaleSpatialImage from './IO/toMultiscaleSpatialImage'\nimport { ConglomerateMultiscaleSpatialImage } from './IO/ConglomerateMultiscaleSpatialImage'\nimport { isZarr } from './IO/ZarrMultiscaleSpatialImage'\n\nimport ImJoyPluginAPI from './ImJoyPluginAPI.js'\nimport imJoyCodecs from './imJoyCodecs.js'\nimport packageJson from '../package.json'\nconst { version } = packageJson\n\nlet doNotInitViewers = false\n\nexport { version }\nexport { ImJoyPluginAPI }\nexport { imJoyCodecs }\nexport { default as createViewer } from './createViewer'\nimport * as utils from './utils.js'\nexport { utils }\n\n// The `UserInterface` is considered an internal implementation detail\n// and its interface and behavior may change without changes to the major version.\nexport { UserInterface }\n\n/** Returns a Promise that revolves with the Viewer created the files. */\nexport function createViewerFromLocalFiles(container) {\n  doNotInitViewers = true\n  return createFileDragAndDrop(container, processFiles)\n}\n\nexport async function createViewerFromFiles(el, files, use2D = false) {\n  return processFiles(el, { files: files, use2D })\n}\n\nasync function makeImage({ image, progressCallback, isLabelImage = false }) {\n  if (!image) return null\n\n  const imageUrlObj = new URL(image, document.location)\n\n  if (isZarr(image)) {\n    return toMultiscaleSpatialImage(imageUrlObj, isLabelImage)\n  }\n\n  const result = await readImageArrayBuffer(\n    null,\n    await fetchBinaryContent(imageUrlObj, progressCallback),\n    imageUrlObj.pathname.split('/').pop()\n  )\n  result.webWorker.terminate()\n\n  return toMultiscaleSpatialImage(result.image, isLabelImage)\n}\n\nasync function parseImageArg(image, progressCallback) {\n  if (!image) return null\n\n  const images = await Promise.all(\n    image.split(',').map(image => makeImage({ image, progressCallback }))\n  )\n\n  return images.length > 1\n    ? new ConglomerateMultiscaleSpatialImage(images)\n    : images[0]\n}\n\nexport async function createViewerFromUrl(\n  el,\n  {\n    files = [],\n    image,\n    labelImage,\n    fixedImage,\n    config,\n    labelImageNames = null,\n    rotate = true,\n    use2D = false,\n    ...rest\n  }\n) {\n  UserInterface.emptyContainer(el)\n  const progressCallback = UserInterface.createLoadingProgress(el)\n\n  let fetchedImage\n  const fileObjects = []\n  for (const url of files) {\n    const urlObj = new URL(url, document.location)\n    if (isZarr(url)) {\n      fetchedImage = await toMultiscaleSpatialImage(urlObj)\n    } else {\n      const arrayBuffer = await fetchBinaryContent(urlObj, progressCallback)\n      fileObjects.push(\n        new File([new Blob([arrayBuffer])], urlObj.pathname.split('/').pop())\n      )\n    }\n  }\n\n  // No image in files? Check image arg.\n  fetchedImage = fetchedImage ?? (await parseImageArg(image, progressCallback))\n\n  const labelImageObject = await makeImage({\n    image: labelImage,\n    progressCallback,\n    isLabelImage: true,\n  })\n\n  const fixedImageObject = await makeImage({\n    image: fixedImage,\n    progressCallback,\n  })\n\n  let viewerConfig = null\n  if (config) {\n    const response = await axios.get(config, {\n      responseType: 'json',\n    })\n    viewerConfig = response.data\n  }\n\n  let labelImageNameObject = null\n  if (labelImageNames) {\n    labelImageNameObject = await fetchJsonContent(labelImageNames)\n  }\n\n  return processFiles(el, {\n    files: fileObjects,\n    image: fetchedImage,\n    labelImage: labelImageObject,\n    fixedImage: fixedImageObject,\n    config: viewerConfig,\n    labelImageNames: labelImageNameObject,\n    rotate,\n    use2D,\n    ...rest,\n  })\n}\n\nconst parseBoolean = datasetValue =>\n  datasetValue !== undefined ? datasetValue.toLowerCase() === 'true' : undefined\n\nexport function initializeEmbeddedViewers() {\n  if (doNotInitViewers) {\n    return\n  }\n  const viewers = document.querySelectorAll('.itk-vtk-viewer')\n  let count = viewers.length\n  while (count--) {\n    const el = viewers[count]\n    if (!el.dataset.loaded) {\n      el.dataset.loaded = true\n      // Apply size to container\n      const [width, height] = (el.dataset.viewport || '500x500').split('x')\n      el.style.position = 'relative'\n      el.style.width = Number.isFinite(Number(width)) ? `${width}px` : width\n      el.style.height = Number.isFinite(Number(height)) ? `${height}px` : height\n      const files = el.dataset.url.split(',')\n      createViewerFromUrl(el, {\n        files,\n        use2D: parseBoolean(el.dataset.use2d),\n        rotate: parseBoolean(el.dataset.rotate),\n      }).then(viewer => {\n        // Background color handling\n        if (el.dataset.backgroundColor) {\n          const color = el.dataset.backgroundColor\n          const bgColor = [\n            color.slice(0, 2),\n            color.slice(2, 4),\n            color.slice(4, 6),\n          ].map(v => parseInt(v, 16) / 255)\n          viewer.setBackgroundColor(bgColor)\n        }\n\n        viewer.setUICollapsed(true)\n        viewer.render()\n        el.dataset.viewer = viewer\n      })\n    }\n  }\n}\n\nfunction createCompareOptions(userParams) {\n  if (userParams.compare) {\n    const options = Object.fromEntries(\n      ['pattern', 'swapImageOrder', 'checkerboard', 'imageMix']\n        .map(key => [key, userParams[key]])\n        .filter(([, value]) => value)\n    )\n    options.method = userParams.compare\n    return options\n  }\n  return undefined\n}\n\nexport function processURLParameters(container, addOnParameters = {}) {\n  const userParams = Object.assign(\n    {},\n    vtkURLExtract.extractURLParameters(),\n    addOnParameters\n  )\n\n  if (userParams.gradientOpacity && isNaN(userParams.gradientOpacity))\n    throw new Error('gradientOpacity URL paramter is not a number')\n\n  const myContainer = UserInterface.getRootContainer(container)\n\n  if (userParams.fullscreen) {\n    myContainer.classList.add(style.fullscreenContainer)\n  }\n\n  const files = userParams.fileToLoad?.split(',') ?? []\n\n  if (files.length || userParams.image || userParams.labelImage) {\n    return createViewerFromUrl(myContainer, {\n      files,\n      image: userParams.image,\n      labelImage: userParams.labelImage,\n      config: userParams.config,\n      labelImageNames: userParams.labelImageNames,\n      rotate: userParams.rotate ?? true,\n      use2D: !!userParams.use2D,\n      gradientOpacity: userParams.gradientOpacity,\n      fixedImage: userParams.fixedImage,\n      compare: createCompareOptions(userParams),\n    })\n  }\n  return null\n}\n\n// Ensure processing of embedded viewers\nsetTimeout(initializeEmbeddedViewers, 100)\n"
  },
  {
    "path": "src/internalUtils.js",
    "content": "import { mat4 } from 'gl-matrix'\n\nexport function arraysEqual(a, b) {\n  if (a === b) return true\n  if (a == null || b == null) return false\n  if (a.length !== b.length) return false\n  for (var i = 0; i < a.length; ++i) {\n    if (a[i] !== b[i]) return false\n  }\n  return true\n}\n\nconst makeMat4 = ({ direction, origin, spacing }) => {\n  const mat = mat4.create()\n  mat4.fromTranslation(mat, origin)\n\n  mat[0] = direction[0]\n  mat[1] = direction[1]\n  mat[2] = direction[2]\n  mat[4] = direction[3]\n  mat[5] = direction[4]\n  mat[6] = direction[5]\n  mat[8] = direction[6]\n  mat[9] = direction[7]\n  mat[10] = direction[8]\n\n  return mat4.scale(mat, mat, spacing)\n}\n\nexport const makeIndexToWorld = ({\n  direction: inDirection,\n  origin,\n  spacing,\n}) => {\n  // ITK (and VTKMath) uses row-major index axis, but gl-matrix uses column-major. Transpose.\n  const DIMENSIONS = 3\n  const direction = Array(inDirection.length)\n  for (let idx = 0; idx < DIMENSIONS; ++idx) {\n    for (let col = 0; col < DIMENSIONS; ++col) {\n      direction[col + idx * 3] = inDirection[idx + col * DIMENSIONS]\n    }\n  }\n\n  const origin3d = [...origin]\n  if (origin3d[2] === undefined) origin3d[2] = 0\n\n  const spacing3d = [...spacing]\n  if (spacing3d[2] === undefined) spacing3d[2] = 1\n\n  return makeMat4({ direction, origin: origin3d, spacing: spacing3d })\n}\n"
  },
  {
    "path": "src/itkConfig.js",
    "content": "/* eslint-disable no-undef */\nconst itkConfig = {\n  pipelineWorkerUrl:\n    __webpack_public_path__ + 'itk/web-workers/min-bundles/pipeline.worker.js',\n  imageIOUrl: __webpack_public_path__ + 'itk/image-io',\n  meshIOUrl: __webpack_public_path__ + 'itk/mesh-io',\n  pipelinesUrl: __webpack_public_path__ + 'itk/pipeline',\n}\n\nexport default itkConfig\n"
  },
  {
    "path": "src/itkConfigCDN.js",
    "content": "/* eslint-disable no-undef */\nconst itkConfig = {\n  pipelineWorkerUrl:\n    __webpack_public_path__ +\n    'itk-wasm@' +\n    __itk_version__ +\n    '/dist/web-workers/min-bundles/pipeline.worker.js',\n  imageIOUrl: __webpack_public_path__ + 'itk-image-io@' + __itk_version__,\n  meshIOUrl: __webpack_public_path__ + 'itk-mesh-io@' + __itk_version__,\n  pipelinesUrl:\n    __webpack_public_path__ +\n    'itk-vtk-viewer@' +\n    __itk_vtk_viewer_version__ +\n    '/dist/itk/pipeline',\n}\n\nexport default itkConfig\n"
  },
  {
    "path": "src/transformBounds.js",
    "content": "import { vec3 } from 'gl-matrix'\n\n// from vtk.js/Sources/Common/DataModel/BoundingBox\n// Computes the two corners with minimal and miximal coordinates\nfunction computeCornerPoints(bounds, point1, point2) {\n  point1[0] = bounds[0]\n  point1[1] = bounds[2]\n  point1[2] = bounds[4]\n\n  point2[0] = bounds[1]\n  point2[1] = bounds[3]\n  point2[2] = bounds[5]\n  return point1\n}\n\n// from vtk.js/Sources/Common/Core/Math\nfunction computeBoundsFromPoints(point1, point2, bounds) {\n  bounds[0] = Math.min(point1[0], point2[0])\n  bounds[1] = Math.max(point1[0], point2[0])\n  bounds[2] = Math.min(point1[1], point2[1])\n  bounds[3] = Math.max(point1[1], point2[1])\n  bounds[4] = Math.min(point1[2], point2[2])\n  bounds[5] = Math.max(point1[2], point2[2])\n  return bounds\n}\n\nexport const transformBounds = (transformingMat4, bounds) => {\n  const in1 = [0, 0, 0]\n  const in2 = [0, 0, 0]\n  computeCornerPoints(bounds, in1, in2)\n  const out1 = [0, 0, 0]\n  const out2 = [0, 0, 0]\n  vec3.transformMat4(out1, in1, transformingMat4)\n  vec3.transformMat4(out2, in2, transformingMat4)\n\n  return computeBoundsFromPoints(out1, out2, [])\n}\n"
  },
  {
    "path": "src/utils.js",
    "content": "import vtkITKHelper from 'vtk.js/Sources/Common/DataModel/ITKHelper'\nimport vtkCoordinate from 'vtk.js/Sources/Rendering/Core/Coordinate'\nimport vtk from 'vtk.js/Sources/vtk'\nimport ndarrayToItkImage from './IO/ndarrayToItkImage'\nimport ndarrayToPointSet from './IO/ndarrayToPointSet'\nimport toMultiscaleSpatialImage from './IO/toMultiscaleSpatialImage'\n\nexport { vtkITKHelper }\nexport { vtkCoordinate }\nexport { vtk }\nexport { ndarrayToItkImage }\nexport { ndarrayToPointSet }\nexport { toMultiscaleSpatialImage }\nexport { ConglomerateMultiscaleSpatialImage } from './IO/ConglomerateMultiscaleSpatialImage'\nexport { readFiles } from './IO/processFiles'\n"
  },
  {
    "path": "src/viewerMachineOptions.js",
    "content": "import createRenderingViewContainers from './UI/createRenderingViewContainers'\nimport styleRenderingViewContainers from './UI/styleRenderingViewContainers'\n\nimport referenceUIMachineOptions from './UI/reference-ui/dist/referenceUIMachineOptions'\nimport vtkJSRenderingMachineOptions from './Rendering/VTKJS/vtkJSRenderingMachineOptions'\n\nconst ViewerMachineOptions = {\n  actions: {\n    createRenderingViewContainers,\n    styleRenderingViewContainers,\n  },\n\n  ui: referenceUIMachineOptions,\n\n  rendering: vtkJSRenderingMachineOptions,\n}\n\nexport default ViewerMachineOptions\n"
  },
  {
    "path": "test/conglomerateTest.js",
    "content": "import test from 'tape-catch'\nimport { ConglomerateMultiscaleSpatialImage } from '../src/IO/ConglomerateMultiscaleSpatialImage'\nimport { toMultiscaleSpatialImage } from '../src/utils'\n\nconst takeSnapshot = ({ scaleInfo, imageType }) => {\n  return JSON.stringify({ scaleInfo, imageType })\n}\n\nconst IMAGE_BASELINES = [\n  {\n    paths: [\n      'base/test/data/input/astronaut.zarr',\n      'base/test/data/input/astronaut.zarr',\n    ],\n    baseline:\n      '{\"scaleInfo\":[{\"dims\":[\"t\",\"c\",\"z\",\"y\",\"x\"],\"pixelArrayMetadata\":{\"chunks\":[1,1,1,512,512],\"compressor\":{\"blocksize\":0,\"clevel\":5,\"cname\":\"lz4\",\"id\":\"blosc\",\"shuffle\":1},\"dtype\":\"<f4\",\"fill_value\":0,\"filters\":null,\"order\":\"C\",\"shape\":[1,3,1,2048,2048],\"zarr_format\":2},\"pixelArrayPath\":\"0\",\"coords\":{},\"chunkCount\":[[\"t\",1],[\"c\",3],[\"z\",1],[\"y\",4],[\"x\",4]],\"chunkSize\":[[\"t\",1],[\"c\",1],[\"z\",1],[\"y\",512],[\"x\",512]],\"arrayShape\":[[\"t\",1],[\"c\",3],[\"z\",1],[\"y\",2048],[\"x\",2048]]},{\"dims\":[\"t\",\"c\",\"z\",\"y\",\"x\"],\"pixelArrayMetadata\":{\"chunks\":[1,1,1,256,512],\"compressor\":{\"blocksize\":0,\"clevel\":5,\"cname\":\"lz4\",\"id\":\"blosc\",\"shuffle\":1},\"dtype\":\"<f4\",\"fill_value\":0,\"filters\":null,\"order\":\"C\",\"shape\":[1,3,1,1024,1024],\"zarr_format\":2},\"pixelArrayPath\":\"1\",\"coords\":{},\"chunkCount\":[[\"t\",1],[\"c\",3],[\"z\",1],[\"y\",4],[\"x\",2]],\"chunkSize\":[[\"t\",1],[\"c\",1],[\"z\",1],[\"y\",256],[\"x\",512]],\"arrayShape\":[[\"t\",1],[\"c\",3],[\"z\",1],[\"y\",1024],[\"x\",1024]]},{\"dims\":[\"t\",\"c\",\"z\",\"y\",\"x\"],\"pixelArrayMetadata\":{\"chunks\":[1,2,1,256,256],\"compressor\":{\"blocksize\":0,\"clevel\":5,\"cname\":\"lz4\",\"id\":\"blosc\",\"shuffle\":1},\"dtype\":\"<f4\",\"fill_value\":0,\"filters\":null,\"order\":\"C\",\"shape\":[1,3,1,512,512],\"zarr_format\":2},\"pixelArrayPath\":\"2\",\"coords\":{},\"chunkCount\":[[\"t\",1],[\"c\",2],[\"z\",1],[\"y\",2],[\"x\",2]],\"chunkSize\":[[\"t\",1],[\"c\",2],[\"z\",1],[\"y\",256],[\"x\",256]],\"arrayShape\":[[\"t\",1],[\"c\",3],[\"z\",1],[\"y\",512],[\"x\",512]]},{\"dims\":[\"t\",\"c\",\"z\",\"y\",\"x\"],\"pixelArrayMetadata\":{\"chunks\":[1,2,1,128,256],\"compressor\":{\"blocksize\":0,\"clevel\":5,\"cname\":\"lz4\",\"id\":\"blosc\",\"shuffle\":1},\"dtype\":\"<f4\",\"fill_value\":0,\"filters\":null,\"order\":\"C\",\"shape\":[1,3,1,256,256],\"zarr_format\":2},\"pixelArrayPath\":\"3\",\"coords\":{},\"chunkCount\":[[\"t\",1],[\"c\",2],[\"z\",1],[\"y\",2],[\"x\",1]],\"chunkSize\":[[\"t\",1],[\"c\",2],[\"z\",1],[\"y\",128],[\"x\",256]],\"arrayShape\":[[\"t\",1],[\"c\",3],[\"z\",1],[\"y\",256],[\"x\",256]]}],\"imageType\":{\"dimension\":2,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"float32\",\"components\":6}}',\n  },\n  {\n    paths: [\n      'base/test/data/input/ome-ngff-prototypes/single_image/v0.4/tczyx.ome.zarr',\n      'base/test/data/input/ome-ngff-prototypes/single_image/v0.4/tczyx.ome.zarr',\n    ],\n    baseline:\n      '{\"scaleInfo\":[{\"dims\":[\"t\",\"c\",\"z\",\"y\",\"x\"],\"pixelArrayMetadata\":{\"chunks\":[1,1,64,64,64],\"compressor\":{\"blocksize\":0,\"clevel\":5,\"cname\":\"lz4\",\"id\":\"blosc\",\"shuffle\":1},\"dimension_separator\":\"/\",\"dtype\":\"<i2\",\"fill_value\":0,\"filters\":null,\"order\":\"C\",\"shape\":[3,2,486,262,512],\"zarr_format\":2},\"name\":\"tczyx\",\"pixelArrayPath\":\"s0\",\"coords\":{},\"chunkCount\":[[\"t\",3],[\"c\",2],[\"z\",8],[\"y\",5],[\"x\",8]],\"chunkSize\":[[\"t\",1],[\"c\",1],[\"z\",64],[\"y\",64],[\"x\",64]],\"arrayShape\":[[\"t\",3],[\"c\",2],[\"z\",486],[\"y\",262],[\"x\",512]]},{\"dims\":[\"t\",\"c\",\"z\",\"y\",\"x\"],\"pixelArrayMetadata\":{\"chunks\":[1,1,64,64,64],\"compressor\":{\"blocksize\":0,\"clevel\":5,\"cname\":\"lz4\",\"id\":\"blosc\",\"shuffle\":1},\"dimension_separator\":\"/\",\"dtype\":\"<i2\",\"fill_value\":0,\"filters\":null,\"order\":\"C\",\"shape\":[3,2,243,131,256],\"zarr_format\":2},\"name\":\"tczyx\",\"pixelArrayPath\":\"s1\",\"coords\":{},\"chunkCount\":[[\"t\",3],[\"c\",2],[\"z\",4],[\"y\",3],[\"x\",4]],\"chunkSize\":[[\"t\",1],[\"c\",1],[\"z\",64],[\"y\",64],[\"x\",64]],\"arrayShape\":[[\"t\",3],[\"c\",2],[\"z\",243],[\"y\",131],[\"x\",256]]},{\"dims\":[\"t\",\"c\",\"z\",\"y\",\"x\"],\"pixelArrayMetadata\":{\"chunks\":[1,1,64,64,64],\"compressor\":{\"blocksize\":0,\"clevel\":5,\"cname\":\"lz4\",\"id\":\"blosc\",\"shuffle\":1},\"dimension_separator\":\"/\",\"dtype\":\"<i2\",\"fill_value\":0,\"filters\":null,\"order\":\"C\",\"shape\":[3,2,122,66,128],\"zarr_format\":2},\"name\":\"tczyx\",\"pixelArrayPath\":\"s2\",\"coords\":{},\"chunkCount\":[[\"t\",3],[\"c\",2],[\"z\",2],[\"y\",2],[\"x\",2]],\"chunkSize\":[[\"t\",1],[\"c\",1],[\"z\",64],[\"y\",64],[\"x\",64]],\"arrayShape\":[[\"t\",3],[\"c\",2],[\"z\",122],[\"y\",66],[\"x\",128]]}],\"imageType\":{\"dimension\":3,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"int16\",\"components\":4}}',\n  },\n  {\n    paths: [\n      'base/test/data/input/HeadMRVolume.nrrd',\n      'base/test/data/input/HeadMRVolumeLabels.nrrd',\n    ],\n    baseline:\n      '{\"scaleInfo\":[{\"dims\":[\"z\",\"y\",\"x\"],\"coords\":{\"coords\":[[\"x\",{\"0\":0,\"1\":4,\"2\":8,\"3\":12,\"4\":16,\"5\":20,\"6\":24,\"7\":28,\"8\":32,\"9\":36,\"10\":40,\"11\":44,\"12\":48,\"13\":52,\"14\":56,\"15\":60,\"16\":64,\"17\":68,\"18\":72,\"19\":76,\"20\":80,\"21\":84,\"22\":88,\"23\":92,\"24\":96,\"25\":100,\"26\":104,\"27\":108,\"28\":112,\"29\":116,\"30\":120,\"31\":124,\"32\":128,\"33\":132,\"34\":136,\"35\":140,\"36\":144,\"37\":148,\"38\":152,\"39\":156,\"40\":160,\"41\":164,\"42\":168,\"43\":172,\"44\":176,\"45\":180,\"46\":184,\"47\":188}],[\"y\",{\"0\":0,\"1\":4,\"2\":8,\"3\":12,\"4\":16,\"5\":20,\"6\":24,\"7\":28,\"8\":32,\"9\":36,\"10\":40,\"11\":44,\"12\":48,\"13\":52,\"14\":56,\"15\":60,\"16\":64,\"17\":68,\"18\":72,\"19\":76,\"20\":80,\"21\":84,\"22\":88,\"23\":92,\"24\":96,\"25\":100,\"26\":104,\"27\":108,\"28\":112,\"29\":116,\"30\":120,\"31\":124,\"32\":128,\"33\":132,\"34\":136,\"35\":140,\"36\":144,\"37\":148,\"38\":152,\"39\":156,\"40\":160,\"41\":164,\"42\":168,\"43\":172,\"44\":176,\"45\":180,\"46\":184,\"47\":188,\"48\":192,\"49\":196,\"50\":200,\"51\":204,\"52\":208,\"53\":212,\"54\":216,\"55\":220,\"56\":224,\"57\":228,\"58\":232,\"59\":236,\"60\":240,\"61\":244}],[\"z\",{\"0\":0,\"1\":4,\"2\":8,\"3\":12,\"4\":16,\"5\":20,\"6\":24,\"7\":28,\"8\":32,\"9\":36,\"10\":40,\"11\":44,\"12\":48,\"13\":52,\"14\":56,\"15\":60,\"16\":64,\"17\":68,\"18\":72,\"19\":76,\"20\":80,\"21\":84,\"22\":88,\"23\":92,\"24\":96,\"25\":100,\"26\":104,\"27\":108,\"28\":112,\"29\":116,\"30\":120,\"31\":124,\"32\":128,\"33\":132,\"34\":136,\"35\":140,\"36\":144,\"37\":148,\"38\":152,\"39\":156,\"40\":160,\"41\":164}]]},\"chunkCount\":[[\"z\",1],[\"y\",1],[\"x\",1]],\"chunkSize\":[[\"z\",42],[\"y\",62],[\"x\",48]],\"arrayShape\":[[\"z\",42],[\"y\",62],[\"x\",48]],\"ranges\":[[0,255],[0,2]],\"direction\":[[1,0,0],[0,1,0],[0,0,1]]}],\"imageType\":{\"dimension\":3,\"componentType\":\"uint16\",\"pixelType\":\"Scalar\",\"components\":2}}',\n  },\n]\n\ntest('Test ConglomerateMultiscaleSpatialImage construction', async t => {\n  for (const { paths, baseline } of IMAGE_BASELINES) {\n    const multiscaleImages = await Promise.all(\n      paths\n        .map(path => new URL(path, document.location.origin))\n        .map(image => toMultiscaleSpatialImage(image))\n    )\n    const image = new ConglomerateMultiscaleSpatialImage(multiscaleImages)\n\n    t.deepEqual(\n      takeSnapshot(image),\n      baseline,\n      `conglomerate ${paths} image matches baseline`\n    )\n  }\n\n  t.end()\n})\n"
  },
  {
    "path": "test/convertItkImageToVtkImageTest.js",
    "content": "import test from 'tape-catch'\n\nimport { readImageBlob, IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm'\n\nconst cthead1SmallBase64DataURI =\n  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAAAAABWESUoAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA/4ePzL8AAAAHdElNRQfhBQYVKw8AZTNIAAADdklEQVQ4y2WTa2wUVRiGp6W7O3POnLmc2VrstokJlrBIUBJigjfSICVCCAo/QKM/FFNRIESJQKAws3M7M2f20t3GthRKQQq0kkoXMIq9oFwCXkg0UpMakGLgR9EmJF4TNOvZhRBb31+TvM955/vO+T6Ou69pAgSwKCCAEPc/lYUhFEUkMgH2ESmbYocEEUmKLIQqBKmEgUlERQhAPhyJiDMXPFZZDmRGoP8Q5TwC4ciMpatfXE9zmT2NVRVIQiLi76cDUVRDT/m72zLUc/Srv+gNCi8jhCrupvMAQIWf1zJx58pRj7g7h/sduunhiIIkUAJ4AUBZ0LZev3TondmeS42TuaYms6kOapJUalYQAAKxt+j4qD3yxvMZ0z47NLi/ydhWA7GMinWyAH6G1Wwe/OdUz6dz33T35dPdIxdIYrPGK0qxTnYrobVtjm+3pNvPxGu9/dTRgw8/e89et0AKF1uFItS2u7ZP7fr4K3H19VbP94me/T6fXRifM6+a/QKC6N5+PWGYZhVeNn9pzvUoTVnt3/QEz81dUTONgwjis4UzvS2Z5JbY9JlPdxmEuFZzX9va0yu5WlXmRAlWd3Tmjg980vXBprJZbYPtza0dXw40ZleeP1ZbrWKOXXpsu7Grb3gnsY/27B46+e3ElVuF3w+sm7Pki2VAUxkAo1t0a7TL8YnVPZxy6KG9fX/+2qu/+9DARoAVBiDYaHjnfc/3nHOdicA1Em6WpnOdG/I6zwCA5PCzrn6uw6VO99gBnRBKGUyIMfz3BgmrHHta8cEdu04dN6wjPwy6FinaTNT8emKNzGrgBEmJLLf7T6Tf/60wpFP2oKToB/bNr+pVTWHjghQxZuTzW51C4aIZENdj8gMv+1f3I7iYwPEqrFu+z1/zzI3vHN/ziEd9P0haV39aXxXFRaBMRrCu9Vjj5o/S5C4QBCnjws+pJ9SoqpZmRlqyeNWlPa922El22PMCl5if38q9FGV+CeAaFuK4OZY5nLRoksnsPX19nL5do2GsREoAlCtr68lo4VoXNROWdXD8j7GUNV96AMPye5MtYgU/ujF/887tHy+PXLt9o9/asUipvDfWpc1QNFWKPfla8PHI5Ysnsua2l2dH1Un7WS6rKlamxx9f/MKKhkX1syoxmLqcUMVRDTNMlZGkilPsUrOsJ6wxRSel/wuAkzbenLRf4gAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNy0wNS0wNlQxNzoyNjozNC0wNDowMORO/MMAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTctMDUtMDZUMTc6MjY6MzQtMDQ6MDCVE0R/AAAAAElFTkSuQmCC'\nconst byteString = window.atob(cthead1SmallBase64DataURI.split(',')[1])\nconst mimeString = cthead1SmallBase64DataURI\n  .split(',')[0]\n  .split(':')[1]\n  .split(';')[0]\nlet intArray = new Uint8Array(byteString.length)\nfor (let ii = 0; ii < byteString.length; ++ii) {\n  intArray[ii] = byteString.charCodeAt(ii)\n}\nconst cthead1SmallBlob = new window.Blob([intArray], { type: mimeString })\n\nconst verifyImage = (t, image) => {\n  t.is(image.imageType.dimension, 2, 'dimension')\n  t.is(image.imageType.componentType, IntTypes.UInt8, 'componentType')\n  t.is(image.imageType.pixelType, PixelTypes.Scalar, 'pixelType')\n  t.is(image.imageType.components, 1, 'components')\n  t.is(image.origin[0], 0.0, 'origin[0]')\n  t.is(image.origin[1], 0.0, 'origin[1]')\n  t.is(image.spacing[0], 1.0, 'spacing[0]')\n  t.is(image.spacing[1], 1.0, 'spacing[1]')\n  t.is(getMatrixElement(image.direction, 2, 0, 0), 1.0, 'direction (0, 0)')\n  t.is(getMatrixElement(image.direction, 2, 0, 1), 0.0, 'direction (0, 1)')\n  t.is(getMatrixElement(image.direction, 2, 1, 0), 0.0, 'direction (1, 0)')\n  t.is(getMatrixElement(image.direction, 2, 1, 1), 1.0, 'direction (1, 1)')\n  t.is(image.size[0], 32, 'size[0]')\n  t.is(image.size[1], 32, 'size[1]')\n  t.is(image.data.length, 1024, 'data.length')\n  t.is(image.data[512], 12, 'data[512]')\n  t.end()\n}\n\ntest('readImageBlob reads a Blob', t => {\n  return readImageBlob(null, cthead1SmallBlob, 'cthead1Small.png').then(\n    function({ image }) {\n      verifyImage(t, image)\n    }\n  )\n})\n\ntest('convertItkImageToVtkImage results in the expected image', t => {\n  t.ok(true, 'a check passes')\n  t.end()\n})\n"
  },
  {
    "path": "test/createViewerTest.js",
    "content": "import test from 'tape-catch'\nimport axios from 'axios'\n\nimport { readImageArrayBuffer } from 'itk-wasm'\nimport testUtils from 'vtk.js/Sources/Testing/testUtils'\nimport vtk from 'vtk.js/Sources/vtk'\n\nimport createViewer from '../src/createViewer'\nimport './customElementsDefineOverride.js'\nimport referenceUIMachineOptions from '../src/UI/reference-ui'\nimport { MAX_CONCURRENCY } from '../src/Context/ViewerMachineContext'\n\nconst testImage3DPath = 'base/test/data/input/HeadMRVolume.nrrd'\nconst testLabelImage3DPath = 'base/test/data/input/HeadMRVolumeLabels.nrrd'\nconst test2ComponentImage3DPath =\n  'base/test/data/input/HeadMRVolume2Components.nrrd'\nconst testImage3DPath2 = 'base/test/data/input/mri3D.nrrd'\nconst testImage2D = 'base/test/data/input/HeadMRVolume2DTop.nrrd'\n\n// import createViewerBaseline from './data/baseline/createViewer.png'\n// import createViewerSetImageBaseline from './data/baseline/createViewerSetImage.png'\n\nconst TEST_STYLE_RENDERING_VIEW_CONTAINER = {\n  position: 'relative',\n  width: '600px',\n  height: '600px',\n  minHeight: '600px',\n  minWidth: '600px',\n  maxHeight: '600px',\n  maxWidth: '600px',\n  margin: '0',\n  padding: '0',\n  top: '0',\n  left: '0',\n  overflow: 'hidden',\n}\nconst TEST_VIEWER_STYLE = {\n  backgroundColor: [1, 1, 1],\n  containerStyle: TEST_STYLE_RENDERING_VIEW_CONTAINER,\n}\n\nconst baselineConfig = JSON.parse(\n  `{\"viewerConfigVersion\":\"0.3\",\"uiMachineOptions\":\"reference\",\"xyLowerLeft\":false,\"renderingViewContainerStyle\":{\"position\":\"relative\",\"width\":\"600px\",\"height\":\"600px\",\"minHeight\":\"600px\",\"minWidth\":\"600px\",\"maxHeight\":\"600px\",\"maxWidth\":\"600px\",\"margin\":\"0\",\"padding\":\"0\",\"top\":\"0\",\"left\":\"0\",\"overflow\":\"hidden\"},\"uiCollapsed\":true,\"main\":{\"backgroundColor\":[0.7,0.2,0.8],\"units\":\"mm\"},\"maxConcurrency\":${MAX_CONCURRENCY}}`\n)\n\nfunction makePointSet() {\n  return vtk({\n    vtkClass: 'vtkPolyData',\n    points: {\n      vtkClass: 'vtkPoints',\n      name: '_points',\n      numberOfComponents: 3,\n      dataType: 'Float32Array',\n      values: new Float32Array([\n        -0.44442534,\n        -1.1349318,\n        0.8388769,\n        2.0538256,\n        -1.9028517,\n        0.71276945,\n      ]),\n    },\n    verts: {\n      vtkClass: 'vtkCellArray',\n      name: '_verts',\n      numberOfComponents: 1,\n      dataType: 'Uint32Array',\n      size: 4,\n      values: new Uint16Array([1, 0, 1, 1]),\n    },\n  })\n}\n\ntest('Test createViewer', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n  t.plan(61)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const response = await axios.get(testImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n  const { image: itkImage, webWorker } = await readImageArrayBuffer(\n    null,\n    response.data,\n    'data.nrrd'\n  )\n  webWorker.terminate()\n\n  const labelResponse = await axios.get(testLabelImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n  const {\n    image: itkLabelImage,\n    webWorker: labelWebWorker,\n  } = await readImageArrayBuffer(null, labelResponse.data, 'data.nrrd')\n  labelWebWorker.terminate()\n\n  const uiMachineOptions = { ...referenceUIMachineOptions }\n  const originalCreateInterface =\n    referenceUIMachineOptions.actions.createInterface\n  function testCreateInterface(context) {\n    t.pass('Modified uiMachineOptions')\n    originalCreateInterface(context)\n  }\n  const testUIMachineActions = { ...uiMachineOptions.actions }\n  testUIMachineActions.createInterface = testCreateInterface\n  uiMachineOptions.actions = testUIMachineActions\n\n  const GRADIENT_OPACITY = 0.1\n  const viewer = await createViewer(viewerContainer, {\n    image: itkImage,\n    labelImage: itkLabelImage,\n    rotate: false,\n    gradientOpacity: GRADIENT_OPACITY,\n    config: { uiMachineOptions },\n  })\n  viewer.setRenderingViewContainerStyle(TEST_VIEWER_STYLE.containerStyle)\n  viewer.setBackgroundColor(TEST_VIEWER_STYLE.backgroundColor)\n\n  const VALUE = 0.3\n  viewer.setImageVolumeScatteringBlend(VALUE)\n  t.equal(\n    viewer.getImageVolumeScatteringBlend(),\n    VALUE,\n    'getImageVolumeScatteringBlend matches setImageVolumeScatteringBlend'\n  )\n\n  viewer.setUICollapsed(false)\n  let collapsed = viewer.getUICollapsed()\n  t.equal(collapsed, false, 'setUICollapsed false')\n  viewer.setUICollapsed(true)\n  collapsed = viewer.getUICollapsed()\n  t.equal(collapsed, true, 'setUICollapsed true')\n  t.equal(\n    viewer.getImageGradientOpacity(),\n    GRADIENT_OPACITY,\n    'gradientOpacity set'\n  )\n\n  const bgColor = [0.7, 0.2, 0.8]\n  viewer.once('backgroundColorChanged', () => {\n    t.pass('backgroundColorChanged event')\n  })\n  viewer.setBackgroundColor(bgColor)\n  const resultBGColor = viewer.getBackgroundColor()\n  t.same(resultBGColor, bgColor, 'background color')\n\n  viewer.setUnits('mm')\n  const resultUnits = viewer.getUnits()\n  t.same(resultUnits, 'mm', 'units')\n\n  // skip for screenshot consistency\n  //viewer.once('toggleRotate', () => {\n  //t.pass('toggleRotate event')\n  //})\n  //viewer.setRotateEnabled(true)\n  //const resultRotate = viewer.getRotateEnabled()\n  //t.same(resultRotate, true, 'rotate')\n  //viewer.setRotateEnabled(false)\n\n  viewer.once('toggleAnnotations', () => {\n    t.pass('toggleAnnotations event')\n  })\n  viewer.setAnnotationsEnabled(false)\n  const resultAnnotations = viewer.getAnnotationsEnabled()\n  t.same(resultAnnotations, false, 'annotations')\n  viewer.setAnnotationsEnabled(true)\n\n  viewer.once('toggleAxes', () => {\n    t.pass('toggleAxes event')\n  })\n  viewer.setAxesEnabled(true)\n  const resultAxes = viewer.getAxesEnabled()\n  t.same(resultAxes, true, 'axes')\n  viewer.setAxesEnabled(false)\n\n  viewer.once('toggleImageInterpolation', () => {\n    t.pass('toggleImageInterpolation event')\n  })\n  viewer.setImageInterpolationEnabled(false)\n  const resultImageInterpolation = viewer.getImageInterpolationEnabled()\n  t.same(resultImageInterpolation, false, 'interpolation')\n  viewer.setImageInterpolationEnabled(true)\n\n  viewer.once('viewModeChanged', () => {\n    t.pass('viewModeChanged event')\n  })\n  viewer.setViewMode('XPlane')\n  const resultViewMode = viewer.getViewMode()\n  t.same(resultViewMode, 'XPlane', 'view mode')\n  viewer.setViewMode('Volume')\n\n  const firstLayer = viewer.getLayerNames()[0]\n  t.same(firstLayer, 'Image', 'getLayerNames')\n\n  viewer.once('toggleLayerVisibility', () => {\n    t.pass('toggleLayerVisibility event')\n  })\n  viewer.setLayerVisibility(false, firstLayer)\n  const resultLayerVisibility = viewer.getLayerVisibility(firstLayer)\n  t.same(resultLayerVisibility, false, 'layer visibility')\n  viewer.setLayerVisibility(true, firstLayer)\n\n  viewer.selectLayer(firstLayer)\n\n  viewer.once('imageVisualizedComponentChanged', () => {\n    t.pass('imageVisualizedComponentChanged event')\n  })\n  viewer.setImageComponentVisibility(false, 0)\n  const resultImageComponentVisibility = viewer.getImageComponentVisibility(0)\n  t.same(resultImageComponentVisibility, false, 'image component visibility')\n  viewer.setImageComponentVisibility(true, 0)\n\n  viewer.setCroppingPlanesEnabled(true)\n  t.same(viewer.getCroppingPlanesEnabled(), true, 'set cropping planes enabled')\n  viewer.setCroppingPlanesEnabled(false)\n\n  const [iMin, iMax, jMin, jMax, kMin, kMax] = [0, 3, 0, 3, 0, 3]\n  const origin = [iMin, jMin, kMin]\n  // opposite corner from origin\n  const corner = [iMax, jMax, kMax]\n  const planes = [\n    // X min/max\n    { normal: [1, 0, 0], origin },\n    {\n      normal: [-1, 0, 0],\n      origin: corner,\n    },\n    // Y min/max\n    { normal: [0, 1, 0], origin },\n    {\n      normal: [0, -1, 0],\n      origin: corner,\n    },\n    // X min/max\n    { normal: [0, 0, 1], origin },\n    {\n      normal: [0, 0, -1],\n      origin: corner,\n    },\n  ]\n  viewer.setCroppingPlanes(planes)\n  t.same(viewer.getCroppingPlanes(), planes, 'set cropping planes ')\n\n  // handle non 6 array of planes\n  const plane = [{ normal: [1, 0, 0], origin }]\n  viewer.setCroppingPlanes(plane)\n\n  viewer.resetCroppingPlanes()\n  t.notSame(viewer.getCroppingPlanes(), plane, 'reset cropping planes ')\n\n  const viewProxy = viewer.getViewProxy()\n  const renderWindow = viewProxy.getOpenGLRenderWindow()\n  // Consistent baseline image size for regression testing\n  renderWindow.setSize(600, 600)\n  viewer.render()\n  setTimeout(async () => {\n    viewer.once('imageColorRangeChanged', () => {\n      t.pass('imageColorRangeChanged event')\n    })\n    const oldRange = viewer.getImageColorRange(0)\n    viewer.setImageColorRange([20, 80], 0)\n    const resultImageColorRange = viewer.getImageColorRange(0)\n    t.same(resultImageColorRange, [20, 80], 'image color range')\n    viewer.setImageColorRange(oldRange, 0)\n\n    viewer.once('imageColorRangeBoundsChanged', () => {\n      t.pass('imageColorRangeBoundsChanged event')\n    })\n    const oldBounds = viewer.getImageColorRangeBounds(0)\n    viewer.setImageColorRangeBounds([-20, 800], 0)\n    const resultImageColorRangeBounds = viewer.getImageColorRangeBounds(0)\n    t.same(resultImageColorRangeBounds, [-20, 800], 'image color range bounds')\n    viewer.setImageColorRangeBounds(oldBounds, 0)\n\n    viewer.once('imageColorMapChanged', () => {\n      t.pass('imageColorMapChanged event')\n    })\n    const oldColorMap = viewer.getImageColorMap(0)\n    viewer.setImageColorMap('2hot', 0)\n    const resultImageColorMap = viewer.getImageColorMap(0)\n    t.same(resultImageColorMap, '2hot', 'image color range')\n    viewer.setImageColorMap(oldColorMap, 0)\n\n    viewer.once('imagePiecewiseFunctionGaussiansChanged', () => {\n      t.pass('imagePiecewiseFunctionGaussiansChanged event')\n    })\n    const oldGaussians = viewer.getImagePiecewiseFunctionGaussians(0)\n    const newGaussians = [\n      { position: 0.3, height: 0.4, width: 0.5, xBias: 0.21, yBias: 0.6 },\n    ]\n    viewer.setImagePiecewiseFunctionGaussians(newGaussians, 0)\n    const resultGaussians = viewer.getImagePiecewiseFunctionGaussians(0)\n    t.same(resultGaussians, newGaussians, 'image piecewise function gaussians')\n    viewer.setImagePiecewiseFunctionGaussians(oldGaussians, 0)\n\n    viewer.once('imagePiecewiseFunctionPointsChanged', () => {\n      t.pass('imagePiecewiseFunctionPointsChanged event')\n    })\n    const newPoints = [\n      [0, 0],\n      [0.5, 0.5],\n      [1, 1],\n    ]\n    viewer.setImagePiecewiseFunctionPoints(newPoints, 0)\n    const resultPoints = viewer.getImagePiecewiseFunctionPoints(0)\n    t.same(resultPoints, newPoints, 'image piecewise function points')\n\n    viewer.once('toggleImageShadow', () => {\n      t.pass('toggleImageShadow event')\n    })\n    viewer.setImageShadowEnabled(false)\n    const resultImageShadowEnabled = viewer.getImageShadowEnabled()\n    t.same(resultImageShadowEnabled, false, 'image shadow enabled')\n    viewer.setImageShadowEnabled(true)\n\n    viewer.once('imageGradientOpacityChanged', () => {\n      t.pass('imageGradientOpacityChanged event')\n    })\n    viewer.setImageGradientOpacity(0.5)\n    const resultImageGradientOpacity = viewer.getImageGradientOpacity()\n    t.same(resultImageGradientOpacity, 0.5, 'image gradient opacity')\n    viewer.setImageGradientOpacity(0.3)\n\n    viewer.once('imageGradientOpacityScaleChanged', () => {\n      t.pass('imageGradientOpacityScaleChanged event')\n    })\n    viewer.setImageGradientOpacityScale(0.8)\n    const resultImageGradientOpacityScale = viewer.getImageGradientOpacityScale()\n    t.same(resultImageGradientOpacityScale, 0.8, 'image gradient opacity scale')\n    viewer.setImageGradientOpacity(0.5)\n\n    viewer.once('xSliceChanged', () => {\n      t.pass('xSliceChanged event')\n    })\n    const oldXSlice = viewer.getXSlice()\n    viewer.setXSlice(5)\n    const resultXSlice = viewer.getXSlice()\n    t.same(resultXSlice, 5, 'x slice')\n    viewer.setXSlice(oldXSlice)\n\n    viewer.once('ySliceChanged', () => {\n      t.pass('ySliceChanged event')\n    })\n    const oldYSlice = viewer.getYSlice()\n    viewer.setYSlice(5)\n    const resultYSlice = viewer.getYSlice()\n    t.same(resultYSlice, 5, 'y slice')\n    viewer.setYSlice(oldYSlice)\n\n    viewer.once('zSliceChanged', () => {\n      t.pass('zSliceChanged event')\n    })\n    const oldZSlice = viewer.getZSlice()\n    viewer.setZSlice(5)\n    const resultZSlice = viewer.getZSlice()\n    t.same(resultZSlice, 5, 'z slice')\n    viewer.setZSlice(oldZSlice)\n\n    viewer.once('imageVolumeSampleDistanceChanged', () => {\n      t.pass('imageVolumeSampleDistanceChanged event')\n    })\n    viewer.setImageVolumeSampleDistance(0.5)\n    const resultImageVolumeSampleDistance = viewer.getImageVolumeSampleDistance()\n    t.same(resultImageVolumeSampleDistance, 0.5, 'volume sample distance')\n    viewer.setImageVolumeSampleDistance(0.25)\n\n    viewer.once('imageBlendModeChanged', () => {\n      t.pass('imageBlendModeChanged event')\n    })\n    viewer.setImageBlendMode('Maximum')\n    const resultImageBlendMode = viewer.getImageBlendMode()\n    t.same(resultImageBlendMode, 'Maximum', 'blend mode')\n    viewer.setImageBlendMode('Composite')\n\n    viewer.once('labelImageLookupTableChanged', () => {\n      t.pass('labelImageLookupTableChanged event')\n    })\n    const oldLookupTable = viewer.getLabelImageLookupTable()\n    viewer.setLabelImageLookupTable('glasbey_warm')\n    const resultLabelImageLookupTable = viewer.getLabelImageLookupTable()\n    t.same(resultLabelImageLookupTable, 'glasbey_warm', 'image lookup table')\n    viewer.setLabelImageLookupTable(oldLookupTable)\n\n    viewer.once('labelImageBlendChanged', () => {\n      t.pass('labelImageBlendChanged event')\n    })\n    viewer.setLabelImageBlend(0.8)\n    const resultLabelImageBlend = viewer.getLabelImageBlend()\n    t.same(resultLabelImageBlend, 0.8, 'label image blend')\n    viewer.setLabelImageBlend(0.5)\n\n    viewer.once('labelImageLabelNamesChanged', () => {\n      t.pass('labelImageLabelNamesChanged event')\n    })\n    const labelNames = new Map([\n      [0, 'background'],\n      [1, 'brain'],\n      [2, 'csf'],\n    ])\n    viewer.setLabelImageLabelNames(labelNames)\n    const resultLabelImageLabelNames = viewer.getLabelImageLabelNames()\n    t.same(resultLabelImageLabelNames, labelNames, 'label image label names')\n\n    viewer.once('labelImageWeightsChanged', () => {\n      t.pass('labelImageWeightsChanged event')\n    })\n    const labelWeights = new Map([\n      [0, 0.1],\n      [1, 0.5],\n      [2, 0.9],\n    ])\n    viewer.setLabelImageWeights(labelWeights)\n    const resultLabelImageWeights = viewer.getLabelImageWeights()\n    t.same(resultLabelImageWeights, labelWeights, 'label image weights')\n\n    const config = viewer.getConfig()\n    t.same(config, baselineConfig, 'get config')\n\n    viewer.setImageScale(0)\n    t.same(true, true, 'setImageScale did not error')\n\n    const points = makePointSet()\n    await createViewer(viewerContainer, {\n      pointSets: [points],\n      rotate: false,\n    })\n\n    t.pass('test completed')\n\n    gc.releaseResources()\n    //testUtils.compareImages(\n    //screenshot,\n    //[createViewerBaseline],\n    //'Test createViewer',\n    //t,\n    //2.0,\n    //gc.releaseResources\n    //)\n  }, 10000)\n})\n\ntest('Test createViewer.setImage', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const response = await axios.get(testImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n  const { image: itkImage, webWorker } = await readImageArrayBuffer(\n    null,\n    response.data,\n    'data.nrrd'\n  )\n  webWorker.terminate()\n\n  const viewer = await createViewer(container, {\n    image: itkImage,\n    rotate: false,\n  })\n  viewer.setRenderingViewContainerStyle(TEST_VIEWER_STYLE.containerStyle)\n  viewer.setBackgroundColor(TEST_VIEWER_STYLE.backgroundColor)\n  const response2 = await axios.get(testImage3DPath2, {\n    responseType: 'arraybuffer',\n  })\n  const {\n    image: itkImage2,\n    webWorker: webWorker2,\n  } = await readImageArrayBuffer(null, response2.data, 'data.nrrd')\n  webWorker2.terminate()\n\n  viewer.setImage(itkImage2)\n  const viewProxy = viewer.getViewProxy()\n  const renderWindow = viewProxy.getOpenGLRenderWindow()\n  // Consistent baseline image size for regression testing\n  renderWindow.setSize(600, 600)\n  const representation = viewProxy.getRepresentations()[0]\n  /*const volumeMapper = */ representation.getMapper()\n  viewer.render()\n  setTimeout(() => {\n    viewer.captureImage().then(\n      (/*screenshot*/) => {\n        gc.releaseResources()\n        //testUtils.compareImages(\n        //screenshot,\n        //[createViewerSetImageBaseline],\n        //'Test createViewer.setImage',\n        //t,\n        //2.0,\n        //gc.releaseResources\n        //)\n      },\n      100\n    )\n  })\n})\n\ntest('Test createViewer with just labelImage', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const response = await axios.get(testLabelImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n  const { image: labelImage, webWorker } = await readImageArrayBuffer(\n    null,\n    response.data,\n    'data.nrrd'\n  )\n  webWorker.terminate()\n\n  const viewer = await createViewer(container, {\n    labelImage,\n    rotate: false,\n  })\n\n  t.plan(1)\n  viewer.once('renderedImageAssigned', () => {\n    t.pass('createViewer did not crash with just labelImage')\n    gc.releaseResources()\n  })\n})\n\ntest('Test setImage and setLabelImage after createViewer', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const labelImageResponse = await axios.get(testLabelImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n  const { image: labelImage, webWorker } = await readImageArrayBuffer(\n    null,\n    labelImageResponse.data,\n    'data.nrrd'\n  )\n  webWorker.terminate()\n\n  const imageResponse = await axios.get(testImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n\n  const { image, webWorker: webWorkerForImage } = await readImageArrayBuffer(\n    null,\n    imageResponse.data,\n    'data.nrrd'\n  )\n  webWorkerForImage.terminate()\n\n  const viewer = await createViewer(container, {\n    rotate: false,\n  })\n\n  viewer.setImage(image)\n  viewer.setLabelImage(labelImage)\n\n  t.plan(1)\n  viewer.once('renderedImageAssigned', () => {\n    t.pass(\n      'createViewer did not crash with with late setImage and setLabelImage'\n    )\n    gc.releaseResources()\n  })\n})\n\ntest('Test createViewer custom UI options', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const response = await axios.get(testImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n  const { image: itkImage, webWorker } = await readImageArrayBuffer(\n    null,\n    response.data,\n    'data.nrrd'\n  )\n  webWorker.terminate()\n\n  const referenceUIUrl = new URL(\n    '/base/src/UI/reference-ui/dist/referenceUIMachineOptions.js',\n    document.location.origin\n  )\n  const referenceUIMachineOptionsHref = { href: referenceUIUrl.href }\n\n  await createViewer(container, {\n    image: itkImage,\n    rotate: false,\n    config: { uiMachineOptions: referenceUIMachineOptionsHref },\n  })\n  t.pass('Viewer with UI module URL')\n\n  await createViewer(container, {\n    image: itkImage,\n    rotate: false,\n    config: {\n      uiMachineOptions: { href: referenceUIUrl.href, export: 'default' },\n    },\n  })\n  t.pass('Viewer with UI module URL, explicit export')\n\n  // If missing image.service.scaleSelector in options, test there is no warning\n  // Avoids this later occurring Error: Unable to send event to child 'scaleSelector' from service 'images'\n  const uiMachineOptionsNoImageServices = {\n    ...referenceUIMachineOptions,\n    images: { ...referenceUIMachineOptions.images },\n  }\n  delete uiMachineOptionsNoImageServices.images.services\n\n  let isWarningLogged = false\n  const consoleWarn = console.warn\n  console.warn = message => {\n    if (message.includes(\"Warning: No service found for invocation '\")) {\n      isWarningLogged = true\n    }\n  }\n  await createViewer(container, {\n    image: itkImage,\n    rotate: false,\n    config: {\n      uiMachineOptions: uiMachineOptionsNoImageServices,\n    },\n  })\n  console.warn = consoleWarn\n\n  t.same(\n    isWarningLogged,\n    false,\n    'custom options with no images.services has no warning'\n  )\n\n  gc.releaseResources()\n})\n\nconst makeImages = async paths => {\n  return Promise.all(\n    paths.map(async path => {\n      const response = await axios.get(path, {\n        responseType: 'arraybuffer',\n      })\n      const { image, webWorker } = await readImageArrayBuffer(\n        null,\n        response.data,\n        'data.nrrd'\n      )\n      webWorker.terminate()\n      return image\n    })\n  )\n}\n\ntest('Test createViewer setCompareImage with checkerboard', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const [image, fixedImage] = await makeImages([\n    testImage3DPath,\n    testLabelImage3DPath,\n  ])\n\n  const viewer = await createViewer(container, {\n    rotate: false,\n  })\n  viewer.setImage(fixedImage, 'fixed')\n  await viewer.setImage(image, 'moving')\n  const compareOptions = {\n    method: 'checkerboard',\n    pattern: [10, 5, 2],\n  }\n  viewer.setCompareImages('fixed', 'moving', compareOptions)\n\n  t.plan(1)\n  viewer.once('renderedImageAssigned', () => {\n    const { method } = viewer.getCompareImages('moving')\n\n    t.same(method, compareOptions.method, 'compare method matches')\n    gc.releaseResources()\n  })\n})\n\ntest('Test createViewer setCompareImage with checkerboard and 2 component image', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const [image, fixedImage] = await makeImages([\n    testImage3DPath,\n    test2ComponentImage3DPath,\n  ])\n\n  const viewer = await createViewer(container, {\n    fixedImage,\n    rotate: false,\n  })\n  await viewer.setImage(image, 'moving')\n  const compareOptions = {\n    method: 'checkerboard',\n    pattern: [10, 5, 2],\n  }\n  viewer.setCompareImages('Fixed', 'moving', compareOptions)\n\n  t.plan(1)\n  viewer.once('renderedImageAssigned', () => {\n    t.pass(\n      'createViewer did not crash right after setFixedImage and setCheckerboard'\n    )\n    gc.releaseResources()\n  })\n})\n\ntest('Test setCompareImage with checkerboard and 2D image', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const [image, fixedImage] = await makeImages([testImage2D, testImage2D])\n\n  const compareOptions = {\n    method: 'checkerboard',\n  }\n  const viewer = await createViewer(container, {\n    image,\n    fixedImage,\n    compare: compareOptions,\n    rotate: false,\n  })\n  t.plan(1)\n  viewer.once('renderedImageAssigned', () => {\n    // first rendered image is just the image, not the fused compare image\n    viewer.once('renderedImageAssigned', () => {\n      t.pass('createViewer did not crash right after compare.')\n      gc.releaseResources()\n    })\n  })\n})\n\ntest('Test cyan-magenta compare', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const [image, fixedImage] = await makeImages([\n    testImage3DPath,\n    test2ComponentImage3DPath,\n  ])\n\n  const viewer = await createViewer(container, {\n    fixedImage,\n    rotate: false,\n  })\n  await viewer.setImage(image, 'moving')\n  const compareOptions = {\n    method: 'cyan-magenta',\n  }\n  viewer.setCompareImages('Fixed', 'moving', compareOptions)\n\n  t.plan(1)\n  viewer.once('renderedImageAssigned', () => {\n    t.pass('createViewer did not crash right after compare.')\n    gc.releaseResources()\n  })\n})\n\ntest('Test blend compare', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const [image, fixedImage] = await makeImages([testImage2D, testImage2D])\n  const compareOptions = {\n    method: 'blend',\n    imageMix: 0.25,\n  }\n  const viewer = await createViewer(container, {\n    image,\n    fixedImage,\n    compare: compareOptions,\n    rotate: false,\n  })\n\n  t.plan(1)\n  viewer.once('renderedImageAssigned', () => {\n    t.pass('createViewer did not crash right after compare.')\n    gc.releaseResources()\n  })\n})\n"
  },
  {
    "path": "test/customElementsDefineOverride.js",
    "content": "// Avoids error importing config UIs multiple times in tests when\n// customElements.define will be called multiple times by Material-Web components\n\nfunction safeDecorator(fn) {\n  return function(...args) {\n    try {\n      return fn.apply(this, args)\n    } catch (error) {\n      if (\n        error instanceof DOMException &&\n        [\n          'has already been used with this registry', // Chrome\n          'has already been defined as a custom element', // Firefox\n        ].some(msg => error.message.includes(msg))\n      ) {\n        return false\n      }\n      throw error\n    }\n  }\n}\n\ncustomElements.define = safeDecorator(customElements.define)\n"
  },
  {
    "path": "test/downloadData.mjs",
    "content": "// To update the testing data, add new data test at ./test/data, then:\n//\n// // Add your token from https://web3.storage, if not present on this system\n// npx w3 token\n//\n// npx w3 put ./test/data/ --no-wrap -n itk-vtk-viewer-testing-data-topic-name -H\n//\n// And update the resulting CID below.\n//\nconst IPFS_CID = 'bafybeihm5fr5s5s2g63pxsndmiswiayk6oz2h2kde5m32pqm7ejml24l6e'\n\nimport fs from 'fs'\n\nimport { config, getClient } from '@web3-storage/w3/lib.js'\nimport { writeFiles } from 'ipfs-car/unpack/fs'\n\nasync function downloadData(cid, token, outputDir) {\n  const client = getClient({ token })\n  const res = await client.get(cid)\n  await writeFiles(res.unixFsIterator(), outputDir)\n}\n\nconst testDataDir = './test/data'\nif (!fs.existsSync(testDataDir)) {\n  console.log('Test data not found. Downloading.')\n  // eslint-disable-next-line no-undef\n  let token = process.env.WEB3STORAGE_TOKEN\n  if (!token) {\n    token = config.get('token')\n  }\n  await downloadData(IPFS_CID, token, testDataDir)\n} else {\n  console.log('Test data found.')\n}\n"
  },
  {
    "path": "test/imjoyTest.js",
    "content": "import test from 'tape-catch'\nimport axios from 'axios'\n\nimport { readImageArrayBuffer } from 'itk-wasm'\nimport testUtils from 'vtk.js/Sources/Testing/testUtils'\n\nconst testImage3DPath = 'base/test/data/input/HeadMRVolume.nrrd'\n\nimport * as imjoyCore from 'imjoy-core'\nimport ndarray from 'ndarray'\n\nconst TEST_STYLE_RENDERING_VIEW_CONTAINER = {\n  position: 'relative',\n  width: '600px',\n  height: '600px',\n  minHeight: '600px',\n  minWidth: '600px',\n  maxHeight: '600px',\n  maxWidth: '600px',\n  margin: '0',\n  padding: '0',\n  top: '0',\n  left: '0',\n  overflow: 'hidden',\n}\nfunction applyStyle(el, style) {\n  Object.keys(style).forEach(key => {\n    el.style[key] = style[key]\n  })\n}\nfunction encodeArray(array) {\n  return {\n    _rtype: 'ndarray',\n    _rdtype: array.dtype,\n    _rshape: array.shape,\n    _rvalue: array.data.buffer,\n  }\n}\n\nconst testConfig = JSON.parse(\n  '{\"viewerConfigVersion\":\"0.2\",\"xyLowerLeft\":true,\"renderingViewContainerStyle\":{\"position\":\"relative\",\"width\":\"600px\",\"height\":\"600px\",\"minHeight\":\"600px\",\"minWidth\":\"600px\",\"maxHeight\":\"600px\",\"maxWidth\":\"600px\",\"margin\":\"0\",\"padding\":\"0\",\"top\":\"0\",\"left\":\"0\",\"overflow\":\"hidden\"},\"main\":{\"backgroundColor\":[0.7,0.2,0.8],\"units\":\"mm\"}}'\n)\n\ntest('Test ImJoy Plugin', async t => {\n  t.plan(7)\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const response = await axios.get(testImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n  const { image: itkImage, webWorker } = await readImageArrayBuffer(\n    null,\n    response.data,\n    'data.nrrd'\n  )\n  webWorker.terminate()\n  const array = ndarray(itkImage.data, itkImage.size.slice().reverse())\n\n  const imjoy_api = {\n    showMessage(plugin, info /*,duration*/) {\n      console.log(info)\n    },\n  }\n  const imjoy = new imjoyCore.ImJoy({\n    imjoy_api,\n  })\n  imjoy.event_bus.on('show_message', console.log)\n  imjoy.event_bus.on('add_window', async w => {\n    viewerContainer.id = w.window_id\n    applyStyle(viewerContainer, TEST_STYLE_RENDERING_VIEW_CONTAINER)\n  })\n  await imjoy.start({ workspace: 'default' })\n  console.log('ImJoy started')\n\n  const points = ndarray(new Float32Array([1, 0, 0, 0, 1, 0]), [2, 3])\n  const pointSets = [encodeArray(points)]\n  const viewerIndex = new URL('/base/dist/index.html', document.location.origin)\n  let viewer = await imjoy.pm.createWindow(null, {\n    src: viewerIndex.href,\n    data: { pointSets },\n    config: testConfig,\n  })\n  const points2D = ndarray(new Float32Array([1, 0, 0, 1]), [2, 2])\n  const pointSets2D = [encodeArray(points2D)]\n  await viewer.setPointSets(pointSets2D)\n  t.pass('setPointSets ndarray')\n\n  const uiMachineOptions = {\n    href: new URL(\n      '/base/test/testUINoPlaneSlidersBundle.js',\n      document.location.origin\n    ).href,\n  }\n  testConfig.uiMachineOptions = uiMachineOptions\n  viewer = await imjoy.pm.createWindow(null, {\n    src: viewerIndex.href,\n    data: { image: itkImage, uiMachineOptions },\n    config: testConfig,\n  })\n  await viewer.setImage(encodeArray(array))\n  t.pass('setImage ndarray')\n\n  const bgColor = [0.2, 0.8, 0.7]\n  await viewer.setBackgroundColor(bgColor)\n  const resultBGColor = await viewer.getBackgroundColor()\n  t.same(bgColor, resultBGColor, 'background color')\n\n  await viewer.setImage(itkImage)\n  t.pass('setImage itk.js Image')\n\n  const imageURL = new URL(testImage3DPath, document.location.origin)\n  await viewer.setImage(imageURL)\n  t.pass('setImage URL')\n\n  const image = await viewer.captureImage()\n  t.same(\n    image.startsWith('data:image/png;base64,'),\n    true,\n    'captured image format'\n  )\n\n  imjoy.destroy()\n  console.log('ImJoy destroyed')\n\n  t.pass('test completed')\n  gc.releaseResources()\n})\n"
  },
  {
    "path": "test/itkConfigBrowserTest.js",
    "content": "const itkConfig = {\n  pipelineWorkerUrl: '/base/dist/itk/web-workers/bundles/pipeline.worker.js', // eslint-disable-line no-undef\n  imageIOUrl: '/base/dist/itk/image-io', // eslint-disable-line no-undef\n  meshIOUrl: '/base/dist/itk/mesh-io', // eslint-disable-line no-undef\n  pipelinesUrl: '/base/dist/itk/pipeline', // eslint-disable-line no-undef\n}\n\nmodule.exports = itkConfig\n"
  },
  {
    "path": "test/multiscaleSpatialImageTest.js",
    "content": "import test from 'tape-catch'\nimport ZarrMultiscaleSpatialImage from '../src/IO/ZarrMultiscaleSpatialImage'\nimport { takeSnapshot } from './zarrImageBaselines'\n\nconst IMAGE_BASELINES = [\n  [\n    'base/test/data/input/astronaut.zarr',\n    [\n      Number.MAX_VALUE,\n      -Number.MAX_VALUE, // X\n      Number.MAX_VALUE,\n      -Number.MAX_VALUE, // Y\n      Number.MAX_VALUE,\n      -Number.MAX_VALUE, // Z\n    ],\n    '{\"imageType\":{\"dimension\":2,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"float32\",\"components\":3},\"origin\":[0,0],\"spacing\":[8,8],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":1},\"size\":[256,256],\"ranges\":[[0,0.9763471484184265],[0,0.9741398692131042],[0,0.9760480523109436]],\"data\":[0.6908552050590515,0.6688187122344971,0.674207329750061,0.27221277356147766,0.2442161589860916,0.30864495038986206,0.04838373512029648,0.021947167813777924,0.11139355599880219,0.12586522102355957,0.08368028700351715,0.2073654979467392,0.29955506324768066,0.26995500922203064,0.3033413887023926,0.4970903694629669,0.46638235449790955,0.4774773120880127,0.6510546803474426,0.6293986439704895,0.6291141510009766,0.652686595916748,0.6369064450263977,0.6407243609428406,0.6563014984130859,0.645758330821991,0.6505763530731201,0.6664388179779053,0.6574797630310059,0.6628299951553345,0.6745269298553467,0.6657060384750366,0.6709856390953064,0.702728271484375,0.6728822588920593,0.6759136915206909,0.3145504593849182,0.27835237979888916,0.33366164565086365,0.12892097234725952,0.08835494518280029,0.16398540139198303,0.18125581741333008,0.09787159413099289,0.20692530274391174,0.32659101486206055,0.250407338142395,0.27853235602378845,0.5059590339660645,0.4235151708126068,0.41403526067733765,0.64797443151474,0.5656358003616333,0.5444427728652954,0.650419294834137,0.5713972449302673,0.5587600469589233,0.6266179084777832,0.5702376365661621,0.5665257573127747,0.6173701882362366,0.57239830493927,0.5740906596183777,0.6674000024795532,0.6029467582702637,0.594350278377533,1.0168959424516899e-11,1.3201037485366385e-11,7.667253984489086e-12,6.150961359176199e-13,6.375242673183068e-13,1.862368982988305e-12,2.6472281398209896e-13,2.687519803055982e-13,1.9147365442305497e-13,8.121141834103313e-15,7.599267894640993e-15,1.278036429805526e-14,1.6719174311674578e-7,1.4385383906301286e-7,1.528643451820244e-7,0.0015648636035621166,0.0013919497141614556,0.0013295512180775404,0.10193789750337601,0.09551996737718582,0.08835914731025696,0.20549945533275604,0.19322900474071503,0.15210646390914917,0.15297368168830872,0.13750818371772766,0.10394243896007538,0.22972600162029266,0.21356536448001862,0.18998141586780548,0.17018358409404755,0.15841108560562134,0.15074452757835388]}',\n  ],\n  [\n    'base/test/data/input/astronaut.zarr',\n    [\n      100,\n      -Number.MAX_VALUE, // X\n      Number.MAX_VALUE,\n      200, // Y\n      Number.MAX_VALUE,\n      -Number.MAX_VALUE, // Z\n    ],\n    '{\"imageType\":{\"dimension\":2,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"float32\",\"components\":3},\"origin\":[0,200],\"spacing\":[8,8],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":1},\"size\":[14,231],\"ranges\":[[0.027741413563489914,0.9305924773216248],[0.009815634228289127,0.8219987154006958],[0.03106931783258915,0.8618532419204712]],\"data\":[0.8434163331985474,0.8005973696708679,0.8331800699234009,0.7815706133842468,0.7346546649932861,0.7513733506202698,0.6643561124801636,0.6075320243835449,0.5917041301727295,0.6853213310241699,0.6227045059204102,0.6025393605232239,0.6865707039833069,0.6216851472854614,0.6030192971229553,0.6473481059074402,0.5493790507316589,0.5326882004737854,0.4837162494659424,0.21639575064182281,0.23379985988140106,0.4325582981109619,0.05030425265431404,0.11512165516614914,0.4712345004081726,0.052832502871751785,0.11249638348817825,0.5143463015556335,0.06659615784883499,0.09130306541919708,0.4708518385887146,0.0675983726978302,0.10576199740171432,0.6128345131874084,0.5687515735626221,0.5649264454841614,0.6761928796768188,0.6405994892120361,0.616477906703949,0.7017715573310852,0.6674644947052002,0.6350312829017639,0.7152020335197449,0.6786738038063049,0.6512665748596191,0.7224043011665344,0.684797465801239,0.6600486636161804,0.727691113948822,0.6899614334106445,0.666928231716156,0.7366620898246765,0.6999374032020569,0.677337646484375,0.43325045704841614,0.38873860239982605,0.527625560760498,0.1498635858297348,0.09285452961921692,0.3016122281551361,0.1429762840270996,0.08937985450029373,0.3059288561344147,0.08375998586416245,0.03814108297228813,0.1900119036436081,0.4801272451877594,0.11964694410562515,0.1514689326286316,0.46954914927482605,0.082619309425354,0.0762876570224762,0.5867084860801697,0.1747123748064041,0.034656163305044174,0.614237904548645,0.16455063223838806,0.033633943647146225,0.6534176468849182,0.19214867055416107,0.07890287041664124,0.5566028952598572,0.1690547615289688,0.08912341296672821,0.4563755393028259,0.13142666220664978,0.07666008919477463,0.5841031670570374,0.20222604274749756,0.11976894736289978,0.7241355180740356,0.29688942432403564,0.1723022609949112,0.6470702886581421,0.2434939593076706,0.12110405415296555,0.346635103225708,0.11826460063457489,0.09175870567560196]}',\n  ],\n  [\n    'base/test/data/input/ome-ngff-prototypes/single_image/v0.4/zyx.ome.zarr',\n    [\n      1000,\n      2000, // X\n      1000,\n      2000, // Y\n      Number.MAX_VALUE,\n      -Number.MAX_VALUE, // Z\n    ],\n    '{\"imageType\":{\"dimension\":3,\"pixelType\":\"Scalar\",\"componentType\":\"uint8\",\"components\":1},\"name\":\"zyx\",\"origin\":[768,768,0],\"spacing\":[256,256,256],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":0,\"4\":1,\"5\":0,\"6\":0,\"7\":0,\"8\":1},\"size\":[6,6,151],\"ranges\":[[0,199]],\"data\":[0,0,0,0,0,0,4,8,7,13,28,15,15,26,41,38,106,85,49,70,68,60,116,109,78,101,91,102,164,117,123,140,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}',\n  ],\n]\n\ntest('Test ZarrMultiscaleSpatialImage world bounded chunk assembly', async t => {\n  for (const [path, bounds, baseline] of IMAGE_BASELINES) {\n    const storeURL = new URL(path, document.location.origin)\n    const zarrImage = await ZarrMultiscaleSpatialImage.fromUrl(storeURL)\n    const itkImage = await zarrImage.getImage(\n      zarrImage.scaleInfo.length - 1,\n      bounds\n    )\n\n    t.deepEqual(\n      takeSnapshot(itkImage),\n      baseline,\n      `${path} image matches baseline`\n    )\n  }\n\n  t.end()\n})\n"
  },
  {
    "path": "test/pipelineTest.js",
    "content": "import test from 'tape-catch'\nimport axios from 'axios'\n\nimport { readImageArrayBuffer } from 'itk-wasm'\nimport testUtils from 'vtk.js/Sources/Testing/testUtils'\n\nimport createViewer from '../src/createViewer'\nimport './customElementsDefineOverride.js'\n\nconst testImage3DPath = 'base/test/data/input/HeadMRVolume.nrrd'\nconst testLabelImage3DPath =\n  'base/test/data/input/HeadMRVolumeLabelsSmaller.nrrd'\n\ntest('Test createViewer with smaller size label image', async t => {\n  const gc = testUtils.createGarbageCollector(t)\n\n  const container = document.querySelector('body')\n  const viewerContainer = gc.registerDOMElement(document.createElement('div'))\n  container.appendChild(viewerContainer)\n\n  const imageResponse = await axios.get(testImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n  const { image, webWorker: imageWorker } = await readImageArrayBuffer(\n    null,\n    imageResponse.data,\n    'data.nrrd'\n  )\n  imageWorker.terminate()\n\n  const labelResponse = await axios.get(testLabelImage3DPath, {\n    responseType: 'arraybuffer',\n  })\n  const {\n    image: labelImage,\n    webWorker: labelWorker,\n  } = await readImageArrayBuffer(null, labelResponse.data, 'data.nrrd')\n  labelWorker.terminate()\n\n  const viewer = await createViewer(container, {\n    image,\n    labelImage,\n    rotate: false,\n  })\n\n  t.plan(1)\n  viewer.once('renderedImageAssigned', () => {\n    t.pass('createViewer did not crash with smaller label image')\n    gc.releaseResources()\n  })\n})\n"
  },
  {
    "path": "test/processFilesTest.js",
    "content": "import test from 'tape-catch'\nimport axios from 'axios'\n\nimport { FloatTypes, PixelTypes } from 'itk-wasm'\n\nconst testVtiPath = 'base/test/data/input/test.vti'\n\nimport { readFiles } from '../src/IO/processFiles'\n\nconst verifyImage = (t, image) => {\n  t.is(image.imageType.dimension, 3, 'dimension')\n  t.is(image.imageType.componentType, FloatTypes.Float32, 'componentType')\n  t.is(image.imageType.pixelType, PixelTypes.Scalar, 'pixelType')\n  t.is(image.imageType.components, 1, 'components')\n  t.is(image.origin[0], 0.0, 'origin[0]')\n  t.is(image.origin[1], 0.0, 'origin[1]')\n  t.is(image.origin[2], 0.0, 'origin[2]')\n  t.is(image.spacing[0], 1.0, 'spacing[0]')\n  t.is(image.spacing[1], 1.0, 'spacing[1]')\n  t.is(image.spacing[2], 1.0, 'spacing[2]')\n  t.is(image.size[0], 10, 'size[0]')\n  t.is(image.size[1], 10, 'size[1]')\n  t.is(image.size[2], 10, 'size[2]')\n  t.is(image.data.length, 1000, 'data.length')\n  t.is(image.data[512], 0.9276729822158813, 'data[512]')\n  t.end()\n}\n\ntest('Test reading a vti image file', async t => {\n  const response = await axios.get(testVtiPath, {\n    responseType: 'blob',\n  })\n  const vtiFile = new File([response.data], 'test.vti')\n  const result = await readFiles({ files: [vtiFile] })\n  verifyImage(t, result.image)\n})\n"
  },
  {
    "path": "test/run.sh",
    "content": "#!/bin/bash\n\n# Source: https://github.com/thewtex/docker-opengl/tree/webgl\n\ncontainer=webgl\nimage=thewtex/opengl:ubuntu2004\nport=6080\nextra_run_args=\"\"\nquiet=\"\"\ndebug=\"\"\n\nshow_help() {\ncat << EOF\nUsage: ${0##*/} [-h] [-q] [-c CONTAINER] [-i IMAGE] [-p PORT] [-r DOCKER_RUN_FLAGS]\n\nThis script is a convenience script to run Docker images based on\nthewtex/opengl. It:\n\n- Makes sure docker is available\n- On Windows and Mac OSX, creates a docker machine if required\n- Informs the user of the URL to access the container with a web browser\n- Stops and removes containers from previous runs to avoid conflicts\n- Mounts the present working directory to /home/user/work on Linux and Mac OSX\n- Prints out the graphical app output log following execution\n- Exits with the same return code as the graphical app\n\nOptions:\n\n  -h             Display this help and exit.\n  -c             Container name to use (default ${container}).\n  -i             Image name (default ${image}).\n  -p             Port to expose HTTP server (default ${port}). If an empty\n                 string, the port is not exposed.\n  -r             Extra arguments to pass to 'docker run'. E.g. --env=\"APP=test/my-test-command.sh\"\n  -d             Debug by exposing the graphical environment with noVNC.\n  -q             Do not output informational messages.\nEOF\n}\n\nwhile [ $# -gt 0 ]; do\n\tcase \"$1\" in\n\t\t-h)\n\t\t\tshow_help\n\t\t\texit 0\n\t\t\t;;\n\t\t-c)\n\t\t\tcontainer=$2\n\t\t\tshift\n\t\t\t;;\n\t\t-i)\n\t\t\timage=$2\n\t\t\tshift\n\t\t\t;;\n\t\t-p)\n\t\t\tport=$2\n\t\t\tshift\n\t\t\t;;\n\t\t-r)\n\t\t\textra_run_args=\"$extra_run_args $2\"\n\t\t\tshift\n\t\t\t;;\n\t\t-d)\n\t\t\tdebug=0\n\t\t\tshift\n\t\t\t;;\n\t\t-q)\n\t\t\tquiet=1\n\t\t\t;;\n\t\t*)\n\t\t\tshow_help >&2\n\t\t\texit 1\n\t\t\t;;\n\tesac\n\tshift\ndone\n\n\nwhich docker 2>&1 >/dev/null\nif [ $? -ne 0 ]; then\n\techo \"Error: the 'docker' command was not found.  Please install docker.\"\n\texit 1\nfi\n\nos=$(uname)\nif [ \"${os}\" != \"Linux\" ]; then\n\tvm=$(docker-machine active 2> /dev/null || echo \"default\")\n\tif ! docker-machine inspect \"${vm}\" &> /dev/null; then\n\t\tif [ -z \"$quiet\" ]; then\n\t\t\techo \"Creating machine ${vm}...\"\n\t\tfi\n\t\tdocker-machine -D create -d virtualbox --virtualbox-memory 2048 ${vm}\n\tfi\n\tdocker-machine start ${vm} > /dev/null\n    eval $(docker-machine env $vm --shell=sh)\nfi\n\nip=$(docker-machine ip ${vm} 2> /dev/null || echo \"localhost\")\nurl=\"http://${ip}:$port\"\n\ncleanup() {\n\tdocker stop $container >/dev/null\n\tdocker rm $container >/dev/null\n}\n\nrunning=$(docker ps -a -q --filter \"name=${container}\")\nif [ -n \"$running\" ]; then\n\tif [ -z \"$quiet\" ]; then\n\t\techo \"Stopping and removing the previous session...\"\n\t\techo \"\"\n\tfi\n\tcleanup\nfi\n\nif [ -z \"$quiet\" ]; then\n\techo \"\"\n\techo \"Setting up the graphical application container...\"\n\techo \"\"\n\tif [ -n \"$port\" ]; then\n\t\techo \"Point your web browser to ${url}\"\n\t\techo \"\"\n\tfi\nfi\n\npwd_dir=\"$(pwd)\"\nmount_local=\"\"\nif [ \"${os}\" = \"Linux\" ] || [ \"${os}\" = \"Darwin\" ]; then\n\tmount_local=\" -v ${pwd_dir}:/home/user/work \"\nfi\nport_arg=\"\"\nif [ -n \"$port\" ]; then\n\tport_arg=\"-p $port:6080\"\nfi\ndebug_arg=\"\"\nif [ -n \"$debug\" ]; then\n   debug_arg=--env=APP=\"\"\nfi\n\ndocker run \\\n  -d \\\n  --name $container \\\n  --privileged \\\n  --workdir /home/user/work \\\n  ${mount_local} \\\n  $port_arg \\\n  --env=\"APP=npm run test -- --browsers Chrome --dockered\" \\\n  $extra_run_args \\\n  $debug_arg \\\n  $image >/dev/null\n\nprint_app_output() {\n\tdocker cp $container:/var/log/supervisor/graphical-app-launcher.log - \\\n\t\t| tar xO\n\tresult=$(docker cp $container:/tmp/graphical-app.return_code - \\\n\t\t| tar xO)\n\tcleanup\n\texit $result\n}\n\ntrap \"docker stop $container >/dev/null && print_app_output\" SIGINT SIGTERM\n\ndocker wait $container >/dev/null\n\nprint_app_output\n\n# vim: noexpandtab shiftwidth=4 tabstop=4 softtabstop=0\n"
  },
  {
    "path": "test/test-ui-rollup.config.js",
    "content": "// Configuration for bundling the ReferenceUI and derivatives\nimport autoprefixer from 'autoprefixer'\nimport postcss from 'rollup-plugin-postcss'\nimport svgo from 'rollup-plugin-svgo'\nimport { nodeResolve } from '@rollup/plugin-node-resolve'\nimport commonjs from '@rollup/plugin-commonjs'\nimport { babel } from '@rollup/plugin-babel'\nimport ignore from 'rollup-plugin-ignore'\nimport typescript from '@rollup/plugin-typescript'\n\nexport default {\n  input: 'test/testUINoPlaneSliders.js',\n  output: { file: 'test/testUINoPlaneSlidersBundle.js', format: 'es' },\n  plugins: [\n    typescript({\n      tsconfig: 'src/UI/reference-ui/tsconfig.json',\n      compilerOptions: {\n        declaration: false,\n        declarationMap: false,\n      },\n    }),\n    // ignore crypto module\n    ignore(['crypto']),\n    commonjs({\n      transformMixedEsModules: true,\n    }),\n    babel({\n      include: ['src/UI/reference-ui/src/**', 'test/testUINoPlaneSliders.js'],\n      extensions: ['.js'],\n      exclude: 'node_modules/**',\n      skipPreflightCheck: true,\n      babelHelpers: 'bundle',\n    }),\n    svgo({ raw: true }),\n    postcss({\n      modules: true,\n      plugins: [autoprefixer],\n    }),\n    nodeResolve({\n      preferBuiltins: false,\n      browser: true,\n    }),\n  ],\n}\n"
  },
  {
    "path": "test/testUINoPlaneSliders.js",
    "content": "import './customElementsDefineOverride.js'\nimport referenceUIMachineOptions from '../src/UI/reference-ui/src/referenceUIMachineOptions.js'\n\nimport style from '../src/UI/reference-ui/src/ItkVtkViewer.module.css'\n\nimport createScreenshotButton from '../src/UI/reference-ui/src/Main/createScreenshotButton.js'\nimport createFullscreenButton from '../src/UI/reference-ui/src/Main/createFullscreenButton.js'\nimport createRotateButton from '../src/UI/reference-ui/src/Main/createRotateButton.js'\nimport createAnnotationsButton from '../src/UI/reference-ui/src/Main/createAnnotationsButton.js'\nimport createAxesButton from '../src/UI/reference-ui/src/Main/createAxesButton.js'\nimport createViewPlanesToggle from '../src/UI/reference-ui/src/Main/createViewPlanesToggle.js'\nimport createPlaneSliders from '../src/UI/reference-ui/src/Main/createPlaneSliders.js'\nimport createBackgroundColorButton from '../src/UI/reference-ui/src/Main/createBackgroundColorButton.js'\nimport createCroppingButtons from '../src/UI/reference-ui/src/Main/createCroppingButtons.js'\nimport createViewModeButtons from '../src/UI/reference-ui/src/Main/createViewModeButtons.js'\nimport createResetCameraButton from '../src/UI/reference-ui/src/Main/createResetCameraButton.js'\n\nfunction modifiedCreateMainInterface(context) {\n  const mainUIGroup = document.createElement('div')\n  mainUIGroup.setAttribute('class', style.uiGroup)\n  context.uiGroups.set('main', mainUIGroup)\n\n  const mainUIRow1 = document.createElement('div')\n  mainUIRow1.setAttribute('class', style.mainUIRow)\n  mainUIGroup.appendChild(mainUIRow1)\n\n  createScreenshotButton(context, mainUIRow1)\n  // Leave out the fullscreen button\n  //createFullscreenButton(context, mainUIRow1)\n  //if (!context.use2D) {\n  //createRotateButton(context, mainUIRow1)\n  //}\n  //createAnnotationsButton(context, mainUIRow1)\n  createAxesButton(context, mainUIRow1)\n  createViewPlanesToggle(context, mainUIRow1)\n  // Leave out the plane sliders\n  // createPlaneSliders(context)\n\n  createBackgroundColorButton(context, mainUIRow1)\n  const mainUIRow2 = document.createElement('div')\n  mainUIRow2.setAttribute('class', style.mainUIRow)\n\n  if (context.use2D) {\n    createCroppingButtons(context, mainUIRow1)\n    createViewModeButtons(context, mainUIRow2)\n    createResetCameraButton(context, mainUIRow1)\n  } else {\n    createCroppingButtons(context, mainUIRow2)\n    createViewModeButtons(context, mainUIRow2)\n    createResetCameraButton(context, mainUIRow2)\n    mainUIGroup.appendChild(mainUIRow2)\n  }\n\n  context.uiContainer.appendChild(mainUIGroup)\n}\n\nconst uiMachineOptions = { ...referenceUIMachineOptions }\nconst testUIMainActions = { ...uiMachineOptions.main.actions }\ntestUIMainActions.createMainInterface = modifiedCreateMainInterface\n\nconst testUIMain = { ...uiMachineOptions.main }\ntestUIMain.actions = testUIMainActions\nuiMachineOptions.main = testUIMain\n\nexport default uiMachineOptions\n"
  },
  {
    "path": "test/tests.js",
    "content": "import './convertItkImageToVtkImageTest.js'\nimport './createViewerTest.js'\nimport './pipelineTest.js'\nimport './imjoyTest.js'\nimport './processFilesTest.js'\nimport './zarrTest.js'\nimport './conglomerateTest.js'\nimport './multiscaleSpatialImageTest.js'\n"
  },
  {
    "path": "test/zarrImageBaselines.js",
    "content": "const SAMPLE_SIZE = 33\nexport const takeSnapshot = ({ data, ...rest }) => {\n  const innerOffset = data.length / 2\n  const baseline = {\n    ...rest,\n    data: [\n      ...data.slice(0, SAMPLE_SIZE),\n      ...data.slice(innerOffset, innerOffset + SAMPLE_SIZE),\n      ...data.slice(-SAMPLE_SIZE),\n    ],\n  }\n  return JSON.stringify(baseline)\n}\n\nconst IMAGE_BASELINES = [\n  {\n    path: 'base/test/data/input/astronaut.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":2,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"float32\",\"components\":3},\"origin\":[0,0],\"spacing\":[8,8],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":1},\"size\":[256,256],\"ranges\":[[0,0.9763471484184265],[0,0.9741398692131042],[0,0.9760480523109436]],\"data\":[0.6908552050590515,0.6688187122344971,0.674207329750061,0.27221277356147766,0.2442161589860916,0.30864495038986206,0.04838373512029648,0.021947167813777924,0.11139355599880219,0.12586522102355957,0.08368028700351715,0.2073654979467392,0.29955506324768066,0.26995500922203064,0.3033413887023926,0.4970903694629669,0.46638235449790955,0.4774773120880127,0.6510546803474426,0.6293986439704895,0.6291141510009766,0.652686595916748,0.6369064450263977,0.6407243609428406,0.6563014984130859,0.645758330821991,0.6505763530731201,0.6664388179779053,0.6574797630310059,0.6628299951553345,0.6745269298553467,0.6657060384750366,0.6709856390953064,0.702728271484375,0.6728822588920593,0.6759136915206909,0.3145504593849182,0.27835237979888916,0.33366164565086365,0.12892097234725952,0.08835494518280029,0.16398540139198303,0.18125581741333008,0.09787159413099289,0.20692530274391174,0.32659101486206055,0.250407338142395,0.27853235602378845,0.5059590339660645,0.4235151708126068,0.41403526067733765,0.64797443151474,0.5656358003616333,0.5444427728652954,0.650419294834137,0.5713972449302673,0.5587600469589233,0.6266179084777832,0.5702376365661621,0.5665257573127747,0.6173701882362366,0.57239830493927,0.5740906596183777,0.6674000024795532,0.6029467582702637,0.594350278377533,1.0168959424516899e-11,1.3201037485366385e-11,7.667253984489086e-12,6.150961359176199e-13,6.375242673183068e-13,1.862368982988305e-12,2.6472281398209896e-13,2.687519803055982e-13,1.9147365442305497e-13,8.121141834103313e-15,7.599267894640993e-15,1.278036429805526e-14,1.6719174311674578e-7,1.4385383906301286e-7,1.528643451820244e-7,0.0015648636035621166,0.0013919497141614556,0.0013295512180775404,0.10193789750337601,0.09551996737718582,0.08835914731025696,0.20549945533275604,0.19322900474071503,0.15210646390914917,0.15297368168830872,0.13750818371772766,0.10394243896007538,0.22972600162029266,0.21356536448001862,0.18998141586780548,0.17018358409404755,0.15841108560562134,0.15074452757835388]}',\n  },\n  {\n    path:\n      'base/test/data/input/ome-ngff-prototypes/single_image/v0.4/cyx.ome.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":2,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"uint16\",\"components\":4},\"name\":\"cyx\",\"origin\":[0,0],\"spacing\":[4,4],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":1},\"size\":[256,232],\"ranges\":[[525,6345],[2061,18828],[972,3957],[1352,2986]],\"data\":[539,2120,1266,1554,550,2170,1141,1607,539,2067,1118,1522,543,2103,995,1428,539,2176,1004,1684,549,2118,1006,1556,547,2290,984,1467,540,2097,1021,1478,542,574,3233,1303,1862,573,3283,1349,1990,583,3304,1329,2004,577,3384,1322,1881,587,3459,1420,2104,583,3419,1366,2012,582,3266,1441,2126,582,3366,1490,2007,585,1628,542,2608,1114,1568,548,2561,1043,1622,545,2563,1058,1580,550,2626,1108,1821,548,2514,1081,1647,542,2552,1112,1639,545,2506,1026,1599,549,2517,1027,1586]}',\n  },\n  {\n    path:\n      'base/test/data/input/ome-ngff-prototypes/single_image/v0.4/tczyx.ome.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":3,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"int16\",\"components\":2},\"name\":\"tczyx\",\"origin\":[0,0,0],\"spacing\":[2.5999999046325684,2.5999999046325684,4],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":0,\"4\":1,\"5\":0,\"6\":0,\"7\":0,\"8\":1},\"size\":[128,66,122],\"ranges\":[[0,5115],[0,280]],\"data\":[6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}',\n  },\n  {\n    path:\n      'base/test/data/input/ome-ngff-prototypes/single_image/v0.4/zyx.ome.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":3,\"pixelType\":\"Scalar\",\"componentType\":\"uint8\",\"components\":1},\"name\":\"zyx\",\"origin\":[0,0,0],\"spacing\":[256,256,256],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":0,\"4\":1,\"5\":0,\"6\":0,\"7\":0,\"8\":1},\"size\":[121,98,151],\"ranges\":[[0,238]],\"data\":[146,147,147,146,145,145,145,145,145,145,142,140,140,142,143,143,143,143,141,140,137,133,131,129,128,127,126,125,124,121,118,115,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,124,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}',\n  },\n  {\n    path:\n      'base/test/data/input/ome-ngff-prototypes/single_image/v0.1/zyx.ome.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":3,\"pixelType\":\"Scalar\",\"componentType\":\"uint8\",\"components\":1},\"name\":\"zyx\",\"origin\":[0,0,0],\"spacing\":[3.9917354583740234,4.010204315185547,3.993377447128296],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":0,\"4\":1,\"5\":0,\"6\":0,\"7\":0,\"8\":1},\"size\":[121,98,151],\"ranges\":[[0,238]],\"data\":[146,147,147,146,145,145,145,145,145,145,142,140,140,142,143,143,143,143,141,140,137,133,131,129,128,127,126,125,124,121,118,115,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,124,126,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}',\n  },\n  {\n    path:\n      'base/test/data/input/ome-ngff-prototypes/single_image/v0.1/tczyx.ome.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":3,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"int16\",\"components\":2},\"name\":\"tczyx\",\"origin\":[0,0,0],\"spacing\":[4,3.9696969985961914,3.9836065769195557],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":0,\"4\":1,\"5\":0,\"6\":0,\"7\":0,\"8\":1},\"size\":[128,66,122],\"ranges\":[[0,5115],[0,280]],\"data\":[6,6,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}',\n  },\n  {\n    path:\n      'base/test/data/input/ome-ngff-prototypes/single_image/v0.1/cyx.ome.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":2,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"uint16\",\"components\":4},\"name\":\"cyx\",\"origin\":[0,0],\"spacing\":[4,4.008620738983154],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":1},\"size\":[256,232],\"ranges\":[[525,6345],[2061,18828],[972,3957],[1352,2986]],\"data\":[539,2120,1266,1554,550,2170,1141,1607,539,2067,1118,1522,543,2103,995,1428,539,2176,1004,1684,549,2118,1006,1556,547,2290,984,1467,540,2097,1021,1478,542,574,3233,1303,1862,573,3283,1349,1990,583,3304,1329,2004,577,3384,1322,1881,587,3459,1420,2104,583,3419,1366,2012,582,3266,1441,2126,582,3366,1490,2007,585,1628,542,2608,1114,1568,548,2561,1043,1622,545,2563,1058,1580,550,2626,1108,1821,548,2514,1081,1647,542,2552,1112,1639,545,2506,1026,1599,549,2517,1027,1586]}',\n  },\n  {\n    path:\n      'base/test/data/input/ome-ngff-prototypes/single_image/v0.4/yx.ome.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":2,\"pixelType\":\"Scalar\",\"componentType\":\"uint16\",\"components\":1},\"name\":\"yx\",\"origin\":[0,0],\"spacing\":[4,4],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":1},\"size\":[256,232],\"ranges\":[[525,6345]],\"data\":[539,550,539,543,539,549,547,540,542,537,540,541,532,548,543,543,541,545,540,543,546,544,545,545,548,553,544,549,546,545,551,547,553,574,573,583,577,587,583,582,582,585,594,584,584,585,594,583,597,598,596,598,592,593,588,597,598,598,598,608,607,600,592,612,599,607,570,560,555,554,558,561,553,554,557,550,554,566,553,546,554,544,555,548,550,542,551,549,548,549,553,542,548,545,550,548,542,545,549]}',\n  },\n  {\n    path: 'base/test/data/input/idr/5025551.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":2,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"uint8\",\"components\":27},\"origin\":[0,0],\"spacing\":[16,16],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":1},\"size\":[168,168],\"ranges\":[[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255],[0,255]],\"data\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,22,29,0,0,0,0,0,0,0,56,0,0,0,0,0,55,0,42,30,36,0,46,0,6,4,23,212,28,0,0,0,0,0,197,0,119,16,145,0,0,7,0,0,0,0,17,0,0,0,0,0,0,0,85,83,0,0,60,36,0,0,0,156,1,151,0]}',\n  },\n]\n\nconst RESOURCE_ERROR_CAUSING_DOCKER = [\n  {\n    path: 'base/test/data/input/idr/6001240.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":3,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"uint16\",\"components\":2},\"origin\":[0,0,0],\"spacing\":[4.04477596282959,4.044117450714111,1],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":0,\"4\":1,\"5\":0,\"6\":0,\"7\":0,\"8\":1},\"size\":[67,68,236],\"ranges\":[[5,4095],[24,2092]],\"data\":[8,28,8,28,9,27,9,28,9,27,9,27,10,29,9,27,9,28,9,26,10,28,9,26,8,27,9,28,10,26,7,27,10,8,27,8,31,9,28,10,28,8,27,9,28,8,28,10,27,19,28,68,27,23,29,9,26,9,27,7,27,8,28,8,27,8,37,9,28,9,34,23,44,7,27,8,31,9,28,10,28,9,28,7,28,9,27,8,39,7,28,8,27,9,34,8,30,9,45]}',\n  },\n  {\n    path: 'base/test/data/input/idr/6001240_v3.zarr',\n    baseline:\n      '{\"imageType\":{\"dimension\":3,\"pixelType\":\"VariableLengthVector\",\"componentType\":\"uint16\",\"components\":2},\"origin\":[0,0,0],\"spacing\":[1,1,1],\"direction\":{\"0\":1,\"1\":0,\"2\":0,\"3\":0,\"4\":1,\"5\":0,\"6\":0,\"7\":0,\"8\":1},\"size\":[67,68,236],\"ranges\":[[5,4095],[24,2092]],\"data\":[8,28,8,28,9,27,9,28,9,27,9,27,10,29,9,27,9,28,9,26,10,28,9,26,8,27,9,28,10,26,7,27,10,8,27,8,31,9,28,10,28,8,27,9,28,8,28,10,27,19,28,68,27,23,29,9,26,9,27,7,27,8,28,8,27,8,37,9,28,9,34,23,44,7,27,8,31,9,28,10,28,9,28,7,28,9,27,8,39,7,28,8,27,9,34,8,30,9,45]}',\n  },\n]\n\nexport const getBaselines = () =>\n  // eslint-disable-next-line no-undef\n  __karma__.config.args.includes('--dockered')\n    ? IMAGE_BASELINES\n    : [...IMAGE_BASELINES, ...RESOURCE_ERROR_CAUSING_DOCKER]\n"
  },
  {
    "path": "test/zarrTest.js",
    "content": "import { IntTypes, PixelTypes } from 'itk-wasm'\nimport test from 'tape-catch'\n\nconst testZarrV1 = 'base/test/data/input/64x64-fake-v0.1.zarr/0'\nconst testZarrV4 = 'base/test/data/input/64x64-fake-v0.4.zarr/0'\n\nimport HttpStore from '../src/IO/HttpStore'\nimport ZarrStoreParser from '../src/IO/ZarrStoreParser'\nimport toMultiscaleSpatialImage from '../src/IO/toMultiscaleSpatialImage'\nimport ZarrMultiscaleSpatialImage, {\n  computeTransform,\n  isZarr,\n} from '../src/IO/ZarrMultiscaleSpatialImage'\nimport { getBaselines, takeSnapshot } from './zarrImageBaselines'\n\nconst verifyImage = (t, image, msgPrefix = '') => {\n  const imageTypeBaseline = {\n    dimension: 2,\n    pixelType: PixelTypes.Scalar,\n    componentType: IntTypes.UInt8,\n    components: 1,\n  }\n  t.deepEqual(image.imageType, imageTypeBaseline, msgPrefix + ' image type set')\n  t.deepEqual(image.origin, [0, 0], msgPrefix + ' image origin set')\n  t.deepEqual(image.spacing, [1, 1], msgPrefix + ' image spacing set')\n  t.deepEqual(image.size, [64, 64], msgPrefix + ' image size set')\n  t.equal(image.data.length, 4096, msgPrefix + ' image data length set')\n}\n\ntest('Test isZarr', t => {\n  t.true(isZarr('foo.zarr'), 'no suffix')\n  t.true(isZarr('foo.zarr/0'), '/0 suffix')\n  t.true(isZarr('foo.zarr/asdf'), '/asdf suffix')\n  t.true(isZarr('foo/zarr/asdf'), 'no dot before zarr')\n  t.true(\n    isZarr(\n      'https://dandiarchive.s3.amazonaws.com/zarr/3d313fc2-0204-496d-bfa1-5c90951ee640'\n    ),\n    'real url'\n  )\n\n  t.true(isZarr('https://site.com/zarr/a/b'), 'deep nested image')\n  t.true(\n    isZarr('https://site.com/foo.zarr/a/b'),\n    'deep nested image with zarr as extension'\n  )\n\n  t.false(isZarr('zarr.asdf'), 'not when .asdf extension')\n  t.false(\n    isZarr('barzarr.asdf'),\n    'not when .asdf extension withfilename barzarr'\n  )\n  t.false(\n    isZarr('barzarr.asdf/asdf'),\n    'not when .asdf extension and has suffix'\n  )\n  t.false(isZarr('foo.zarrX'), '.zarrX extension, not .zarr')\n\n  t.end()\n})\n\ntest('Test ZarrStoreParser', async t => {\n  const storeURL = new URL(testZarrV4, document.location.origin)\n\n  const httpStore = new HttpStore(storeURL)\n\n  const zarrStoreParser = new ZarrStoreParser(httpStore)\n\n  const topZattrsBaseline = {\n    multiscales: [\n      {\n        axes: [\n          {\n            name: 'y',\n            type: 'space',\n            units: 'micrometer',\n          },\n          {\n            name: 'x',\n            type: 'space',\n            units: 'micrometer',\n          },\n        ],\n        datasets: [\n          {\n            path: '0',\n            coordinateTransformations: [\n              {\n                scale: [1, 1],\n                type: 'scale',\n              },\n            ],\n          },\n        ],\n        name: 'testimage',\n        version: '0.4',\n      },\n    ],\n  }\n\n  const topZattrs = await zarrStoreParser.getItem('.zattrs')\n  t.deepEqual(topZattrs, topZattrsBaseline, 'getItem top .zattrs')\n\n  const arrayBaseline = {\n    chunks: [64, 64],\n    compressor: {\n      clevel: 5,\n      blocksize: 0,\n      shuffle: 1,\n      cname: 'lz4',\n      id: 'blosc',\n    },\n    dtype: '>u1',\n    fill_value: 0,\n    filters: null,\n    order: 'C',\n    shape: [64, 64],\n    zarr_format: 2,\n    dimension_separator: '/',\n  }\n\n  const firstArrayPath = topZattrs.multiscales[0].datasets[0].path\n  const arrayMetadataPath = `${firstArrayPath}/.zarray`\n  const arrayMetadata = await zarrStoreParser.getItem(arrayMetadataPath)\n\n  t.deepEqual(arrayMetadata, arrayBaseline, 'getItem .zarray')\n\n  const { dimension_separator: separator } = arrayMetadata\n  const firstChunkPath = `${firstArrayPath}${separator}0${separator}0`\n  const firstChunk = await zarrStoreParser.getItem(firstChunkPath)\n\n  t.equal(firstChunk.byteLength, 128, 'getItem of chunk data has bytes')\n\n  t.end()\n})\n\ntest('Test ZarrMultiscaleSpatialImage metadata fetching', async t => {\n  const versionTests = [\n    [testZarrV1, 'v0.1'],\n    [testZarrV4, 'v0.4'],\n  ].map(async ([filePath, version]) => {\n    const storeURL = new URL(filePath, document.location.origin)\n    const zarrImage = await ZarrMultiscaleSpatialImage.fromUrl(storeURL)\n\n    t.equal(zarrImage.scaleInfo.length, 1, `${version} number of scales`)\n\n    const viewerImage = await zarrImage.getImage(0)\n\n    verifyImage(t, viewerImage, version)\n  })\n\n  await Promise.all(versionTests)\n\n  t.end()\n})\n\ntest('Test ZarrMultiscaleSpatialImage chunk assembly', async t => {\n  for (const { path, baseline } of getBaselines()) {\n    const storeURL = new URL(path, document.location.origin)\n    const zarrImage = await ZarrMultiscaleSpatialImage.fromUrl(storeURL)\n    const itkImage = await zarrImage.getImage(zarrImage.scaleInfo.length - 1)\n\n    t.deepEqual(\n      takeSnapshot(itkImage),\n      baseline,\n      `${path} image matches baseline`\n    )\n  }\n\n  t.end()\n})\n\ntest('Test toMultiscaleSpatialImage from store', async t => {\n  const storeURL = new URL(testZarrV4, document.location.origin)\n  const zarrImage = await toMultiscaleSpatialImage(new HttpStore(storeURL))\n  const viewerImage = await zarrImage.getImage(0)\n\n  verifyImage(t, viewerImage)\n\n  t.end()\n})\n\ntest('Test ngff metadata coordinate transformations image and dataset interaction', t => {\n  const { scale, translation } = computeTransform(\n    {\n      coordinateTransformations: [\n        {\n          scale: [1, 2, 5],\n          type: 'scale',\n        },\n      ],\n    },\n    {\n      coordinateTransformations: [\n        {\n          translation: [1, 1, 2],\n          type: 'translation',\n        },\n      ],\n    },\n    3\n  )\n\n  t.deepEqual(scale, [1, 2, 5], 'dataset scale computed')\n  t.deepEqual(translation, [1, 2, 10], 'dataset translation computed')\n  t.end()\n})\n\ntest('Test ngff metadata coordinate transformations missing image coordinateTransformations', t => {\n  const { scale, translation } = computeTransform(\n    {},\n    {\n      coordinateTransformations: [\n        {\n          translation: [3, 3, 3],\n          type: 'translation',\n        },\n        {\n          scale: [2, 2, 2],\n          type: 'scale',\n        },\n      ],\n    },\n    3\n  )\n\n  t.deepEqual(scale, [2, 2, 2], 'dataset scale computed')\n  t.deepEqual(translation, [6, 6, 6], 'dataset translation computed')\n  t.end()\n})\n\ntest('Test ngff metadata coordinate transformations stacking', t => {\n  const { scale, translation } = computeTransform(\n    {},\n    {\n      coordinateTransformations: [\n        {\n          scale: [1, 1, 2],\n          type: 'scale',\n        },\n        {\n          translation: [1, 1, 2],\n          type: 'translation',\n        },\n        {\n          scale: [2, 1, 1],\n          type: 'scale',\n        },\n        {\n          translation: [1, 1, 2],\n          type: 'translation',\n        },\n      ],\n    },\n    3\n  )\n\n  t.deepEqual(scale, [2, 1, 2], 'dataset scale computed')\n  t.deepEqual(translation, [3, 2, 4], 'dataset translation computed')\n  t.end()\n})\n\nconst REAL_TRANSFORMATIONS = {\n  coordinateTransformations: [\n    {\n      scale: [10, 1, 1, 1, 1],\n      type: 'scale',\n    },\n    {\n      translation: [2, 0, 0, 0, 2],\n      type: 'translation',\n    },\n  ],\n  datasets: [\n    {\n      coordinateTransformations: [\n        {\n          scale: [1, 1, 1.0, 0.65, 0.65],\n          type: 'scale',\n        },\n      ],\n      path: 's0',\n    },\n    {\n      coordinateTransformations: [\n        {\n          scale: [1, 1, 2.0, 1.3, 1.3],\n          type: 'scale',\n        },\n      ],\n      path: 's1',\n    },\n    {\n      coordinateTransformations: [\n        {\n          scale: [1, 1, 4.0, 2.6, 2.6],\n          type: 'scale',\n        },\n      ],\n      path: 's2',\n    },\n  ],\n}\n\ntest('Test ngff metadata coordinate transformations with real JSON', t => {\n  const imageMetadata = REAL_TRANSFORMATIONS\n  const datasetMetadata = REAL_TRANSFORMATIONS.datasets[2]\n  const { scale, translation } = computeTransform(\n    imageMetadata,\n    datasetMetadata,\n    5\n  )\n\n  t.deepEqual(scale, [10, 1, 4.0, 2.6, 2.6], 'dataset scale computed')\n  t.deepEqual(translation, [2, 0, 0, 0, 2], 'dataset translation computed')\n  t.end()\n})\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"ESNext\",\n    \"module\": \"ESNext\",\n    \"lib\": [\"ESNext\", \"DOM\"],\n    \"moduleResolution\": \"Node\",\n    \"strict\": true,\n    \"sourceMap\": true,\n    \"resolveJsonModule\": true,\n    \"esModuleInterop\": true,\n    \"noEmit\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noImplicitReturns\": true\n  },\n  \"include\": [\"src/**/*\"],\n  \"exclude\": [\"src/UI/reference-ui/src/**\"]\n}\n"
  },
  {
    "path": "webpack.config.js",
    "content": "/* eslint-env node */\nconst webpack = require('webpack')\nconst path = require('path')\n\nconst CopyPlugin = require('copy-webpack-plugin')\nconst { GenerateSW } = require('workbox-webpack-plugin')\nconst WebPackBar = require('webpackbar')\n\nconst entry = path.join(__dirname, './src/index.js')\n\nconst vtkRules = require('vtk.js/Utilities/config/dependency.js').webpack.core\n  .rules\nconst cssRules = require('vtk.js/Utilities/config/dependency.js').webpack.css\n  .rules\n\nconst packageJSON = require('./package.json')\nconst cdnPath = 'https://cdn.jsdelivr.net/npm/'\nconst itkConfigCDN = path.resolve(__dirname, 'src', 'itkConfigCDN.js')\nconst itkConfig = path.resolve(__dirname, 'src', 'itkConfig.js')\n\nconst devServer = {\n  port: 8082,\n  devMiddleware: {\n    writeToDisk: true,\n  },\n  // serve test data, allowing this: data-url=\"test-data/astronaut.zarr\"\n  static: [\n    {\n      publicPath: '/test-data',\n      directory: path.join(__dirname, 'test', 'data', 'input'),\n      staticOptions: {\n        dotfiles: 'allow',\n      },\n    },\n    {\n      directory: path.join(__dirname, 'examples'),\n    },\n  ],\n  headers: {\n    'Access-Control-Allow-Origin': '*',\n    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',\n    'Access-Control-Allow-Headers':\n      'X-Requested-With, content-type, Authorization',\n  },\n}\n\nconst fallback = {\n  path: false,\n  url: false,\n  module: false,\n  fs: false,\n  stream: require.resolve('stream-browserify'),\n  crypto: false,\n}\n\n// Should be same in karma.conf.js\nconst moduleConfigRules = [\n  { test: /\\.js$/, loader: 'babel-loader', dependency: { not: ['url'] } },\n  {\n    test: /\\.worker.js$/,\n    use: [{ loader: 'worker-loader', options: { inline: 'no-fallback' } }],\n  },\n  {\n    test: /\\.(png|jpg)$/,\n    type: 'asset',\n    parser: { dataUrlCondition: { maxSize: 128 * 1024 } },\n  }, // 128kb\n  { test: /\\.svg$/, type: 'asset/source' },\n].concat(vtkRules, cssRules)\n\nconst performance = {\n  maxAssetSize: 20000000,\n  maxEntrypointSize: 20000000,\n}\n\nmodule.exports = (env, argv) => [\n  {\n    name: 'itkVtkViewer.js progressive web app',\n    module: {\n      rules: moduleConfigRules.concat([\n        {\n          test: entry,\n          loader: 'expose-loader',\n          options: { exposes: 'itkVtkViewer' },\n        },\n      ]),\n    },\n    devtool: argv.mode === 'development' ? 'eval-source-map' : 'source-map',\n    output: {\n      filename: 'itkVtkViewer.js',\n    },\n    resolve: {\n      alias: {\n        '../itkConfig.js': itkConfig,\n        '../../itkConfig.js': itkConfig,\n      },\n      fallback,\n    },\n    plugins: [\n      new CopyPlugin({\n        patterns: [\n          {\n            from: path.join(\n              __dirname,\n              'node_modules',\n              'itk-wasm',\n              'dist',\n              'web-workers'\n            ),\n            to: path.join(__dirname, 'dist', 'itk', 'web-workers'),\n          },\n          {\n            from: path.join(__dirname, 'node_modules', 'itk-image-io'),\n            to: path.join(__dirname, 'dist', 'itk', 'image-io'),\n          },\n          {\n            from: path.join(__dirname, 'node_modules', 'itk-mesh-io'),\n            to: path.join(__dirname, 'dist', 'itk', 'mesh-io'),\n          },\n          {\n            from: path.join(\n              __dirname,\n              'src',\n              'Compression',\n              'blosc-zarr',\n              'web-build'\n            ),\n            to: path.join(__dirname, 'dist', 'itk', 'pipeline'),\n          },\n          {\n            from: path.join(\n              __dirname,\n              'src',\n              'IO',\n              'Downsample',\n              'emscripten-build'\n            ),\n            to: path.join(__dirname, 'dist', 'itk', 'pipeline'),\n          },\n          {\n            from: path.join(\n              __dirname,\n              'src',\n              'IO',\n              'ResampleLabelImage',\n              'emscripten-build'\n            ),\n            to: path.join(__dirname, 'dist', 'itk', 'pipeline'),\n          },\n          {\n            from: path.join(\n              __dirname,\n              'src',\n              'IO',\n              'Compare',\n              'emscripten-build'\n            ),\n            to: path.join(__dirname, 'dist', 'itk', 'pipeline'),\n          },\n        ],\n      }),\n      // workbox plugin should be last plugin.  Don't create in development to avoid warning with devServer --watch\n      argv.mode !== 'development'\n        ? new GenerateSW({\n            cacheId: 'itk-vtk-viewer-',\n            cleanupOutdatedCaches: true,\n            maximumFileSizeToCacheInBytes: 10000000,\n            include: [/(\\.js|\\.html|\\.jpg|\\.png)$/],\n            exclude: ['serviceWorker.js', /workbox-.*\\.js/],\n            swDest: path.join(__dirname, 'dist', 'serviceWorker.js'),\n            runtimeCaching: [\n              {\n                urlPattern: /(\\.js|\\.png|\\.wasm)$/,\n                handler: 'StaleWhileRevalidate',\n                options: {\n                  cacheName: 'itk-vtk-viewer-StaleWhileRevalidate',\n                  expiration: {\n                    maxEntries: 50,\n                    maxAgeSeconds: 7 * 24 * 60 * 60 * 2,\n                  },\n                },\n              },\n            ],\n          })\n        : undefined,\n      new WebPackBar(),\n    ].filter(Boolean), // filter removes optional workbox placeholder\n    performance,\n    devServer,\n  },\n  {\n    name: 'itkVtkViewerCDN.js <script> tag',\n    module: {\n      rules: moduleConfigRules.concat([\n        {\n          test: entry,\n          loader: 'expose-loader',\n          options: { exposes: 'itkVtkViewer' },\n        },\n      ]),\n    },\n    output: {\n      filename: 'itkVtkViewerCDN.js',\n      publicPath: cdnPath,\n      library: {\n        name: 'itkVtkViewer',\n        type: 'umd',\n        umdNamedDefine: true,\n      },\n    },\n    resolve: {\n      modules: [path.resolve(__dirname, 'node_modules')],\n      alias: {\n        '../itkConfig.js': itkConfigCDN,\n        '../../itkConfig.js': itkConfigCDN,\n      },\n      fallback,\n    },\n    plugins: [\n      new webpack.DefinePlugin({\n        __itk_version__: JSON.stringify(packageJSON.dependencies['itk-wasm']),\n        __itk_vtk_viewer_version__: JSON.stringify(packageJSON.version),\n      }),\n    ],\n    performance,\n  },\n]\n"
  }
]