[
  {
    "path": ".all-contributorsrc",
    "content": "{\n  \"projectName\": \"node-formidable\",\n  \"projectOwner\": \"node-formidable\",\n  \"repoType\": \"github\",\n  \"repoHost\": \"https://github.com\",\n  \"imageSize\": 100,\n  \"contributorsPerLine\": 6,\n  \"commitConvention\": \"angular\",\n  \"commit\": true,\n  \"skipCi\": true,\n  \"files\": [\n    \"README.md\"\n  ],\n  \"contributors\": [\n    {\n      \"login\": \"felixge\",\n      \"name\": \"Felix Geisendörfer\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/15000?s=460&v=4\",\n      \"profile\": \"https://twitter.com/felixge\",\n      \"contributions\": [\n        \"code\",\n        \"design\",\n        \"ideas\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"tunnckoCore\",\n      \"name\": \"Charlike Mike Reagent\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/5038030?v=4\",\n      \"profile\": \"https://tunnckoCore.com\",\n      \"contributions\": [\n        \"bug\",\n        \"infra\",\n        \"design\",\n        \"code\",\n        \"doc\",\n        \"example\",\n        \"ideas\",\n        \"maintenance\",\n        \"test\"\n      ]\n    },\n    {\n      \"login\": \"kedarv\",\n      \"name\": \"Kedar\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/1365665?v=4\",\n      \"profile\": \"https://github.com/kedarv\",\n      \"contributions\": [\n        \"code\",\n        \"test\",\n        \"question\",\n        \"bug\"\n      ]\n    },\n    {\n      \"login\": \"GrosSacASac\",\n      \"name\": \"Walle Cyril\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/5721194?v=4\",\n      \"profile\": \"https://github.com/GrosSacASac\",\n      \"contributions\": [\n        \"question\",\n        \"bug\",\n        \"code\",\n        \"financial\",\n        \"ideas\",\n        \"maintenance\"\n      ]\n    },\n    {\n      \"login\": \"xarguments\",\n      \"name\": \"Xargs\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/40522463?v=4\",\n      \"profile\": \"https://github.com/xarguments\",\n      \"contributions\": [\n        \"question\",\n        \"bug\",\n        \"code\",\n        \"maintenance\"\n      ]\n    },\n    {\n      \"login\": \"Amit-A\",\n      \"name\": \"Amit-A\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/7987238?v=4\",\n      \"profile\": \"https://github.com/Amit-A\",\n      \"contributions\": [\n        \"question\",\n        \"bug\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"charmander\",\n      \"name\": \"Charmander\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/1889843?v=4\",\n      \"profile\": \"https://charmander.me/\",\n      \"contributions\": [\n        \"question\",\n        \"bug\",\n        \"code\",\n        \"ideas\",\n        \"maintenance\"\n      ]\n    },\n    {\n      \"login\": \"DylanPiercey\",\n      \"name\": \"Dylan Piercey\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/4985201?v=4\",\n      \"profile\": \"https://twitter.com/dylan_piercey\",\n      \"contributions\": [\n        \"ideas\"\n      ]\n    },\n    {\n      \"login\": \"ad-m\",\n      \"name\": \"Adam Dobrawy\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/3618479?v=4\",\n      \"profile\": \"http://ochrona.jawne.info.pl\",\n      \"contributions\": [\n        \"bug\",\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"amitrohatgi\",\n      \"name\": \"amitrohatgi\",\n      \"avatar_url\": \"https://avatars3.githubusercontent.com/u/12177021?v=4\",\n      \"profile\": \"https://github.com/amitrohatgi\",\n      \"contributions\": [\n        \"ideas\"\n      ]\n    },\n    {\n      \"login\": \"fengxinming\",\n      \"name\": \"Jesse Feng\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/6262382?v=4\",\n      \"profile\": \"https://github.com/fengxinming\",\n      \"contributions\": [\n        \"bug\"\n      ]\n    },\n    {\n      \"login\": \"quantumsheep\",\n      \"name\": \"Nathanael Demacon\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/7271496?v=4\",\n      \"profile\": \"https://qtmsheep.com\",\n      \"contributions\": [\n        \"question\",\n        \"code\",\n        \"review\"\n      ]\n    },\n    {\n      \"login\": \"MunMunMiao\",\n      \"name\": \"MunMunMiao\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/18216142?v=4\",\n      \"profile\": \"https://github.com/MunMunMiao\",\n      \"contributions\": [\n        \"bug\"\n      ]\n    },\n    {\n      \"login\": \"gabipetrovay\",\n      \"name\": \"Gabriel Petrovay\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/1170398?v=4\",\n      \"profile\": \"https://github.com/gabipetrovay\",\n      \"contributions\": [\n        \"bug\",\n        \"code\"\n      ]\n    },\n    {\n      \"login\": \"Elzair\",\n      \"name\": \"Philip Woods\",\n      \"avatar_url\": \"https://avatars0.githubusercontent.com/u/2352818?v=4\",\n      \"profile\": \"https://github.com/Elzair\",\n      \"contributions\": [\n        \"code\",\n        \"ideas\"\n      ]\n    },\n    {\n      \"login\": \"dmolim\",\n      \"name\": \"Dmitry Ivonin\",\n      \"avatar_url\": \"https://avatars2.githubusercontent.com/u/7090374?v=4\",\n      \"profile\": \"https://github.com/dmolim\",\n      \"contributions\": [\n        \"doc\"\n      ]\n    },\n    {\n      \"login\": \"masterkain\",\n      \"name\": \"Claudio Poli\",\n      \"avatar_url\": \"https://avatars1.githubusercontent.com/u/12844?v=4\",\n      \"profile\": \"https://audiobox.fm\",\n      \"contributions\": [\n        \"code\"\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org/\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\ntab_width = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": ".eslintignore",
    "content": "# Ignore everything!\n*\n\n# de-ignores: add here what you want to be committed\n!*.*js*\n!*.ts*\n!*.md*\n\n!**/src\n!**/src/**\n\n!**/test\n!**/test/**\n\n!**/*tests*\n!**/*tests*/**\n\n!**/benchmark*\n!**/benchmark*/**\n\n!**/example*\n!**/example*/**\n\n# re-ignores: add here what you want to be ignored again\ntest/tmp\n"
  },
  {
    "path": ".eslintrc.cjs",
    "content": "'use strict';\n\nconst airbnbBase = require('eslint-config-airbnb-base');\n\n// eslint-disable-next-line import/no-dynamic-require\nconst bestPractices = require(airbnbBase.extends[0]);\n\nconst ignoredProps = bestPractices.rules[\n  'no-param-reassign'\n][1].ignorePropertyModificationsFor.concat(\n  'err',\n  'x',\n  '_',\n  'opts',\n  'options',\n  'settings',\n  'config',\n  'cfg',\n);\n\n// Additional rules that are specific and overriding previous\nconst additionalChanges = {\n  strict: 'off',\n\n  // Enforce using named functions when regular function is used,\n  // otherwise use arrow functions\n  'func-names': ['error', 'always'],\n  // Always use parens (for consistency).\n  // https://eslint.org/docs/rules/arrow-parens\n  'arrow-parens': ['error', 'always', { requireForBlockBody: true }],\n  'prefer-arrow-callback': [\n    'error',\n    { allowNamedFunctions: true, allowUnboundThis: true },\n  ],\n  // http://eslint.org/docs/rules/max-params\n  'max-params': ['error', { max: 3 }],\n  // http://eslint.org/docs/rules/max-statements\n  'max-statements': ['error', { max: 20 }],\n  // http://eslint.org/docs/rules/max-statements-per-line\n  'max-statements-per-line': ['error', { max: 1 }],\n  // http://eslint.org/docs/rules/max-nested-callbacks\n  'max-nested-callbacks': ['error', { max: 4 }],\n  // http://eslint.org/docs/rules/max-depth\n  'max-depth': ['error', { max: 4 }],\n  // enforces no braces where they can be omitted\n  // https://eslint.org/docs/rules/arrow-body-style\n  // Never enable for object literal.\n  'arrow-body-style': [\n    'error',\n    'as-needed',\n    { requireReturnForObjectLiteral: false },\n  ],\n  // Allow functions to be use before define because:\n  // 1) they are hoisted,\n  // 2) because ensure read flow is from top to bottom\n  // 3) logically order of the code.\n  // 4) the only addition is 'typedefs' option, see overrides for TS files\n  'no-use-before-define': [\n    'error',\n    {\n      functions: false,\n      classes: true,\n      variables: true,\n    },\n  ],\n  // Same as AirBnB, but adds `opts`, `options`, `x` and `err` to exclusions!\n  // disallow reassignment of function parameters\n  // disallow parameter object manipulation except for specific exclusions\n  // rule: https://eslint.org/docs/rules/no-param-reassign.html\n  'no-param-reassign': [\n    'error',\n    {\n      props: true,\n      ignorePropertyModificationsFor: ignoredProps,\n    },\n  ],\n\n  // disallow declaration of variables that are not used in the code\n  'no-unused-vars': [\n    'error',\n    {\n      ignoreRestSiblings: true, // airbnb's default\n      vars: 'all', // airbnb's default\n      varsIgnorePattern: '^(?:$$|xx|_|__|[iI]gnor(?:e|ing|ed))',\n      args: 'after-used', // airbnb's default\n      argsIgnorePattern: '^(?:$$|xx|_|__|[iI]gnor(?:e|ing|ed))',\n\n      // catch blocks are handled by Unicorns\n      caughtErrors: 'none',\n      // caughtErrorsIgnorePattern: '^(?:$$|xx|_|__|[iI]gnor(?:e|ing|ed))',\n    },\n  ],\n};\n\nconst importRules = {\n  'import/namespace': ['error', { allowComputed: true }],\n  'import/no-absolute-path': 'error',\n  'import/no-webpack-loader-syntax': 'error',\n  'import/no-self-import': 'error',\n\n  // Enable this sometime in the future when Node.js has ES2015 module support\n  // 'import/no-cycle': 'error',\n\n  // Disabled as it doesn't work with TypeScript\n  // 'import/newline-after-import': 'error',\n\n  'import/no-amd': 'error',\n  'import/no-duplicates': 'error',\n\n  // Enable this sometime in the future when Node.js has ES2015 module support\n  // 'import/unambiguous': 'error',\n\n  // Enable this sometime in the future when Node.js has ES2015 module support\n  // 'import/no-commonjs': 'error',\n\n  // Looks useful, but too unstable at the moment\n  // 'import/no-deprecated': 'error',\n\n  'import/no-extraneous-dependencies': 'off',\n  'import/no-mutable-exports': 'error',\n  'import/no-named-as-default-member': 'error',\n  'import/no-named-as-default': 'error',\n\n  // Disabled because it's buggy and it also doesn't work with TypeScript\n  // 'import/no-unresolved': [\n  // \t'error',\n  // \t{\n  // \t\tcommonjs: true\n  // \t}\n  // ],\n\n  'import/order': 'error',\n  'import/no-unassigned-import': [\n    'error',\n    { allow: ['@babel/polyfill', '@babel/register'] },\n  ],\n\n  'import/prefer-default-export': 'off',\n\n  // Ensure more web-compat\n  // ! note that it doesn't work in CommonJS\n  // https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md\n  'import/extensions': 'off',\n\n  // ? Always use named exports. Enable?\n  // 'import/no-default-export': 'error',\n\n  // ? enable?\n  'import/exports-last': 'off',\n\n  // todo: Enable in future.\n  // Ensures everything is tested (all exports should be used).\n  // For cases when you don't want or can't test, add eslint-ignore comment!\n  // see: https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unused-modules.md\n  'import/no-unused-modules': 'off',\n\n  'import/no-useless-path-segments': ['error', { noUselessIndex: false }],\n};\n\nmodule.exports = {\n  env: {\n    es6: true,\n    es2020: true,\n    jest: true,\n    node: true,\n    commonjs: true,\n  },\n  extends: ['eslint:recommended', 'airbnb-base', 'plugin:prettier/recommended'],\n  plugins: ['prettier'],\n  rules: {\n    ...additionalChanges,\n    ...importRules,\n  },\n};\n"
  },
  {
    "path": ".github/.kodiak.toml",
    "content": "# .kodiak.toml\n# Minimal config. version is the only required field.\nversion = 1\n\n[merge] \nautomerge_label = \"ship it\"\nrequire_automerge_label = true\nblock_on_neutral_required_check_runs = true\nblocking_labels = [\"wip\", \"do not merge\"]\ndelete_branch_on_merge = true\nnotify_on_conflict = true\noptimistic_updates = false\nprioritize_ready_to_merge = true\n\n[merge.message]\ntitle = \"pull_request_title\"\nbody = \"pull_request_body\"\nbody_type = \"markdown\"\ninclude_pr_number = true\ninclude_coauthors = true\ninclude_pull_request_url = true\ncut_body_after = \"<!-- COMMIT_BODY_TEXT_BEGIN -->\"\ncut_body_before = \"<!-- COMMIT_BODY_TEXT_END -->\"\n\n[merge.automerge_dependencies]\n# only auto merge \"minor\" and \"patch\" version upgrades.\n# do not automerge \"major\" version upgrades.\nversions = [\"minor\", \"patch\"]\nusernames = [\"dependabot\", \"renovate\"]\n\n[approve]\nauto_approve_usernames = [\"dependabot\", \"renovate\"]\n\n[update]\nalways = true\nrequire_automerge_label = true\n"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# Versions and updates, dependabot.yml\n\nversion: 2\nupdates:\n\n  # Maintain dependencies for GitHub Actions\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n\n  # Maintain dependencies for npm\n  - package-ecosystem: \"npm\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n      time: \"02:00\"\n    # No one cares about dependency labels, they should be auto-merged\n    labels: []\n    allow:\n      # Allow both direct and indirect updates for all packages\n      - dependency-type: \"all\"\n    rebase-strategy: \"auto\"\n    # reviewers: []\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ master ]\n  schedule:\n    - cron: '0 2 * * *'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'javascript' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]\n        # Learn more about CodeQL language support at https://git.io/codeql-language-support\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v5\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v3\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v3\n"
  },
  {
    "path": ".github/workflows/main.yml",
    "content": "name: ci\n\n# on:\n#   push:\n#     branches: [ master ]\n#   pull_request:\n#     branches: [ master ]\n\n# jobs:\n#   # lint:\n#   #   name: Lint\n#   #   runs-on: ubuntu-latest\n#   #   steps:\n#   #     - uses: actions/checkout@v5\n\n#   #     - name: Set up Node.js\n#   #       uses: actions/setup-node@v5\n#   #       with:\n#   #         node-version: '20'\n#   #         cache: 'npm'\n\n#   #     - name: Install dependencies\n#   #       run: npm install\n\n#   #     - name: Run lint\n#   #       run: npm run lint\n\n#   test:\n#     name: Test on ${{ matrix.os }}\n#     runs-on: ${{ matrix.os }}\n#     strategy:\n#       fail-fast: false\n#       matrix:\n#         os: [ubuntu-latest, macos-latest]\n#         node-version: ['lts/*']\n\n#     steps:\n#       - uses: actions/checkout@v5\n\n#       - name: Set up Node.js ${{ matrix.node-version }}\n#         uses: actions/setup-node@v5\n#         with:\n#           node-version: ${{ matrix.node-version }}\n#           cache: 'npm'\n\n#       - name: Install dependencies\n#         run: npm install\n\n#       - name: Run tests\n#         run: npm test\n\non:\n  push:\n    branches:\n      - '*'\n  pull_request:\n    branches:\n      - '*'\n\njobs:\n  build-and-test:\n    name: Test on ${{ matrix.os }} with Node.js ${{matrix.node-version}}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [ubuntu-latest, macos-latest]\n        node-version: [18, 20, 22, 'lts/*']\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v5\n\n      - uses: pnpm/action-setup@v4\n        name: Install pnpm\n        with:\n          run_install: false\n\n      - name: Setup Node.js ${{ matrix.node-version }}\n        uses: actions/setup-node@v5\n        with:\n          node-version: ${{ matrix.node-version }}\n          cache: pnpm\n\n      - name: Install dependencies\n        run: pnpm install\n\n      - name: Run tests\n        run: pnpm test\n"
  },
  {
    "path": ".gitignore",
    "content": "# Ignore everything!\n*\n*~*\n\n# de-ignores: add here what you want to be committed\n!logo.png\n!logo.jpg\n!test-legacy\n!tool\n\n!*.*js*\n!*.ts*\n!*.md*\n!.*rc\n!.*ignore\n!LICENSE\n!.editorconfig\n\n!package.json\n!yarn.lock\n!pnpm-lock.yaml\n\n!**/src\n!**/src/**\n\n!**/test\n!**/test/**\n!**/test-node\n!**/test-node/**\n\n!**/*tests*\n!**/*tests*/**\n\n!**/.github\n!**/.github/**\n\n!**/example*\n!**/example*/**\n\n!**/benchmark*\n!**/benchmark*/**\n\n# re-ignores: add here what you want to be ignored again\ntest/tmp\n\n# !src/*.js\n# !src/*.ts\n# !test\n# !test/*.js\n# !test/*.ts\n# !test/**/*.js\n# !test/**/*.ts\n# !*/__tests__\n\n\n# *.tsbuildinfo\n# .*cache\n# *.cache\n\n# test/tmp\n# *.upload\n# *.un~\n\n# # Build environment\n# dist\n\n# # Package managers lockfiles\n# package-lock.json\n# shrinkwrap.json\n\n# # Logs\n# logs\n# *.log\n# *~\n\n# # Runtime data\n# pids\n# *.pid\n# *.seed\n# *.pid.lock\n\n# # Directory for instrumented libs generated by jscoverage/JSCover\n# lib-cov\n\n# # Coverage directory used by tools like istanbul\n# /coverage\n\n# # nyc test coverage\n# .nyc_output\n\n# # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n# .grunt\n\n# # Bower dependency directory (https://bower.io/)\n# bower_components\n\n# # node-waf configuration\n# .lock-wscript\n\n# # Compiled binary addons (https://nodejs.org/api/addons.html)\n# build/Release\n\n# # Dependency directories\n# node_modules/\n# jspm_packages/\n\n# # TypeScript v1 declaration files\n# typings/\n\n# # Optional npm cache directory\n# .npm\n\n# # Optional eslint cache\n# .eslintcache\n\n# # Optional REPL history\n# .node_repl_history\n\n# # Output of 'npm pack'\n# *.tgz\n\n# # Yarn Integrity file\n# .yarn-integrity\n\n# # dotenv environment variables file\n# .env\n\n# # next.js build output\n# .next\nbenchmark/testuploads/\n"
  },
  {
    "path": ".prettierignore",
    "content": "# Ignore everything!\n*\n\n# de-ignores: add here what you want to be committed\n\n!*.*js*\n!*.ts*\n!*.md*\n!*.y*ml\n\n!**/src\n!**/src/**\n\n!**/test\n!**/test/**\n\n!**/*tests*\n!**/*tests*/**\n\n!**/.github\n!**/.github/**\n\n!**/benchmark*\n!**/benchmark*/**/*.js\n\n!**/example*\n!**/example*/**\n\n# re-ignores: add here what you want to be ignored again\ntest/tmp\n\ntest/fixture/file\ntest/fixture/http\n\n*.upload\n\nCHANGELOG.md\n\n# CHANGELOG.md\n# LICENSE*\n# dist\n\n# test/tmp\n# test/fixture/http\n# test/fixture/file\n# test/fixture/multi*\n# test/tools\n\n# # fixtures\n# # __fixture__\n# # __fixtures__\n# *.map\n# *.lock\n# *.js.snap\n# coverage\n# *.ico\n# *.png\n# *.svg\n# *.jpeg\n# *.jpg\n\n# !.all-contributorsrc\n# !.*rc.js\n# !.verb*.md\n# patches\n# **/static/**/*.css\n\n# *.tsbuildinfo\n# .*cache\n# *.cache\n\n# # Package managers lockfiles\n# package-lock.json\n# shrinkwrap.json\n# pnpm-lock.json\n\n# # Logs\n# logs\n# *.log\n# *~\n\n# # Runtime data\n# pids\n# *.pid\n# *.seed\n# *.pid.lock\n\n# # Directory for instrumented libs generated by jscoverage/JSCover\n# lib-cov\n\n# # Coverage directory used by tools like istanbul\n# coverage\n\n# # nyc test coverage\n# .nyc_output\n\n# # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)\n# .grunt\n\n# # Bower dependency directory (https://bower.io/)\n# bower_components\n\n# # node-waf configuration\n# .lock-wscript\n\n# # Compiled binary addons (https://nodejs.org/api/addons.html)\n# build/Release\n\n# # Dependency directories\n# node_modules/\n# jspm_packages/\n\n# # TypeScript v1 declaration files\n# typings/\n\n# # Optional npm cache directory\n# .npm\n\n# # Optional eslint cache\n# .eslintcache\n\n# # Optional REPL history\n# .node_repl_history\n\n# # Output of 'npm pack'\n# *.tgz\n\n# # Yarn Integrity file\n# .yarn-integrity\n\n# # dotenv environment variables file\n# .env\n\n# # next.js build output\n# .next\n"
  },
  {
    "path": ".prettierrc.js",
    "content": "'use strict';\n\nconst config = require('@tunnckocore/prettier-config');\n\nmodule.exports = {\n  ...config,\n  overrides: [\n    {\n      files: ['**/*.md*'],\n      options: {\n        proseWrap: 'always',\n        printWidth: 80,\n      },\n    },\n    {\n      files: ['**/.all-contributorsrc'],\n      options: {\n        parser: 'json-stringify',\n        singleQuote: false,\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n### 3.5.4\n\n- fix the `os.machine` breaking some dependents, fix [#994](https://github.com/node-formidable/formidable/issues/994)\n- add Node 16, 18, 20, 22 to CI/CD\n\n### 3.5.3\n\n- security report by ZAST.AI help for some vulnerabilities addressing (primarily the random names generation)\n- update failing tests\n- update CI/CD workflows and actions;\n- update CodeQL github action for security analysis\n- update readme, links and badges\n- update to use cuid2 (battle-tested `@paralleldrive/cuid2` package) for better random names - should not be breaking anything since it's still 25 characters long, but a lot safer and faster.\n\n### 3.5.2\n\n * fix: ([#982](https://github.com/node-formidable/formidable/pull/982)) make it easier to import hexoid with webpack\n\n### 3.5.1\n\n * fix: ([#945](https://github.com/node-formidable/formidable/pull/945)) multipart parser fix: flush or fail always (don't hang)\n\n\n### 3.5.0\n\n * feature: ([#944](https://github.com/node-formidable/formidable/pull/944)) Dual package: Can be imported as ES module and required as commonjs module\n\n\n### 3.4.0\n\n * feature: ([#940](https://github.com/node-formidable/formidable/pull/940)) form.parse returns a promise if no callback is provided\n * it resolves with an array `[fields, files]`\n\n\n### 3.3.2\n\n * feature: ([#855](https://github.com/node-formidable/formidable/pull/855)) add options.createDirsFromUploads, see README for usage\n * form.parse is an async function (ignore the promise)\n * benchmarks: add e2e becnhmark with as many request as possible per second\n    * npm run to display all the commands\n * mark as latest on npm\n\n### 3.2.5\n\n * fix: ([#881](https://github.com/node-formidable/formidable/pull/881)) fail earlier when maxFiles is exceeded\n\n### 3.2.4\n\n * fix: ([#857](https://github.com/node-formidable/formidable/pull/857)) improve keep extension\n * The code from before 3.2.4 already removed some characters from the file extension. But not always. So it was inconsistent.\n * The new code cuts the file extension at the first invalid character (invalid in a file extension).\n * The characters that are considered invalid inside a file extension are all except the . numbers and a-Z.\n * This change only has an effect if filename option is not used and keepextension option is used\n\n\n### 3.2.3\n\n * fix: ([#852](https://github.com/node-formidable/formidable/pull/852)) end event is emitted once\n\n### 3.2.2\n\n * refactor: ([#801](https://github.com/node-formidable/formidable/pull/801))\n\n### 3.2.1\n\n\n * fix: do not let empty file on error ([#796](https://github.com/node-formidable/formidable/pull/796))\n * it was probably due to the fact that .destroy on a file stream does not always complete on time\n\n### 3.2.0\n\n\n * feat: maxFileSize option is now per file (as the name suggests) ([#791](https://github.com/node-formidable/formidable/pull/791))\n * feat: add maxFiles option, default Infinity\n * feat: add maxTotalFileSize, default is maxFileSize (for backwards compatibility)\n * fix: minFileSize is per file\n * fix: allowEmptyFiles fix in cases where one file is not empty\n * fix: allowEmptyFiles false option by default\n * fix: rename wrongly named error\n * refactor: rename wrongly named maxFileSize into maxTotalFileSize\n\n### 3.1.5\n\n * fix: PersistentFile.toString ([#796](https://github.com/node-formidable/formidable/pull/796))\n\n### 3.1.4\n\n * fix: add missing pluginFailed error ([#794](https://github.com/node-formidable/formidable/pull/794))\n * refactor: use explicit node imports (#786)\n\n### 3.1.1\n\n * feat: handle top level json array, string and number\n\n### 3.1.0\n\n * feat: add firstValues, readBooleans helpers\n\n### 3.0.0\n\n * feat: remove options.multiples ([#730](https://github.com/node-formidable/formidable/pull/730))\n * use modern URLSearchParams https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams internally\n * files and fields values are always arrays\n * fields with [] in the name do not receive special treatment\n * remove unused qs and querystring dependency\n * feat: Use ES modules ([#727](https://github.com/node-formidable/formidable/pull/727))\n * options.enabledPlugins must contain the plugin themselves instead of the plugins names\n\n\n### 2.0.0\n\n * feat: files are detected if a mimetype is present (previously it was based on filename)\n * feat: add options.filter ([#716](https://github.com/node-formidable/formidable/pull/716))\n * feat: add code and httpCode to most errors ([#686](https://github.com/node-formidable/formidable/pull/686))\n * rename: option.hash into option.hashAlgorithm ([#689](https://github.com/node-formidable/formidable/pull/689))\n * rename: file.path into file.filepath ([#689](https://github.com/node-formidable/formidable/pull/689))\n * rename: file.type into file.mimetype ([#689](https://github.com/node-formidable/formidable/pull/689))\n * refactor: split file.name into file.newFilename and file.originalFilename ([#689](https://github.com/node-formidable/formidable/pull/689))\n * feat: prevent directory traversal attacks by default ([#689](https://github.com/node-formidable/formidable/pull/689))\n * meta: stop including test files in npm ([7003c](https://github.com/node-formidable/formidable/commit/7003cd6133f90c384081accb51743688d5e1f4be))\n * fix: handle invalid filenames ([d0a34](https://github.com/node-formidable/formidable/commit/d0a3484b048b8c177e62d66aecb03f5928f7a857))\n * feat: add fileWriteStreamHandler option\n * feat: add allowEmptyFiles and minFileSize options\n * feat: Array support for fields and files ([#380](https://github.com/node-formidable/node-formidable/pull/380), [#340](https://github.com/node-formidable/node-formidable/pull/340), [#367](https://github.com/node-formidable/node-formidable/pull/367), [#33](https://github.com/node-formidable/node-formidable/issues/33), [#498](https://github.com/node-formidable/node-formidable/issues/498), [#280](https://github.com/node-formidable/node-formidable/issues/280), [#483](https://github.com/node-formidable/node-formidable/issues/483))\n * possible partial fix of [#386](https://github.com/node-formidable/node-formidable/pull/386) with #380 (need tests and better implementation)\n * refactor: use hasOwnProperty in check against files/fields ([#522](https://github.com/node-formidable/node-formidable/pull/522))\n * meta: do not promote `IncomingForm` and add `exports.default` ([#529](https://github.com/node-formidable/node-formidable/pull/529))\n * meta: Improve examples and tests ([#523](https://github.com/node-formidable/node-formidable/pull/523))\n * refactor: First step of Code quality improvements ([#525](https://github.com/node-formidable/node-formidable/pull/525))\n * chore(funding): remove patreon & add npm funding field ([#525](https://github.com/node-formidable/node-formidable/pull/532)\n * feat: use Modern Streams API ([#531](https://github.com/node-formidable/node-formidable/pull/531))\n * fix: urlencoded parsing to emit end [#543](https://github.com/node-formidable/node-formidable/pull/543), introduced in [#531](https://github.com/node-formidable/node-formidable/pull/531)\n * fix(tests): include multipart and qs parser unit tests, part of [#415](https://github.com/node-formidable/node-formidable/issues/415)\n * fix: reorganize exports + move parsers to `src/parsers/`\n * fix: update docs and examples [#544](https://github.com/node-formidable/node-formidable/pull/544) ([#248](https://github.com/node-formidable/node-formidable/issues/248), [#335](https://github.com/node-formidable/node-formidable/issues/335), [#371](https://github.com/node-formidable/node-formidable/issues/371), [#372](https://github.com/node-formidable/node-formidable/issues/372), [#387](https://github.com/node-formidable/node-formidable/issues/387), partly [#471](https://github.com/node-formidable/node-formidable/issues/471), [#535](https://github.com/node-formidable/node-formidable/issues/535))\n * feat: introduce Plugins API, fix silent failing tests ([#545](https://github.com/node-formidable/node-formidable/pull/545), [#391](https://github.com/node-formidable/node-formidable/pull/391), [#407](https://github.com/node-formidable/node-formidable/pull/407), [#386](https://github.com/node-formidable/node-formidable/pull/386), [#374](https://github.com/node-formidable/node-formidable/pull/374), [#521](https://github.com/node-formidable/node-formidable/pull/521), [#267](https://github.com/node-formidable/node-formidable/pull/267))\n * fix: exposing file writable stream errors ([#520](https://github.com/node-formidable/node-formidable/pull/520), [#316](https://github.com/node-formidable/node-formidable/pull/316), [#469](https://github.com/node-formidable/node-formidable/pull/469), [#470](https://github.com/node-formidable/node-formidable/pull/470))\n * feat: custom file (re)naming, thru options.filename ([#591](https://github.com/node-formidable/node-formidable/pull/591), [#84](https://github.com/node-formidable/node-formidable/issues/84), [#86](https://github.com/node-formidable/node-formidable/issues/86), [#94](https://github.com/node-formidable/node-formidable/issues/94), [#154](https://github.com/node-formidable/node-formidable/issues/154), [#158](https://github.com/node-formidable/node-formidable/issues/158), [#488](https://github.com/node-formidable/node-formidable/issues/488), [#595](https://github.com/node-formidable/node-formidable/issues/595))\n\n\n\n### v1.2.1 (2018-03-20)\n\n * `maxFileSize` option with default of 200MB (Charlike Mike Reagent, Nima Shahri)\n * Simplified buffering in JSON parser to avoid denial of service attack (Kornel)\n * Fixed upload file cleanup on aborted requests (liaoweiqiang)\n * Fixed error handling of closed _writeStream (Vitalii)\n\n### v1.1.1 (2017-01-15)\n\n * Fix DeprecationWarning about os.tmpDir() (Christian)\n * Update `buffer.write` order of arguments for Node 7 (Kornel Lesiński)\n * JSON Parser emits error events to the IncomingForm (alessio.montagnani)\n * Improved Content-Disposition parsing (Sebastien)\n * Access WriteStream of fs during runtime instead of include time (Jonas Amundsen)\n * Use built-in toString to convert buffer to hex (Charmander)\n * Add hash to json if present (Nick Stamas)\n * Add license to package.json (Simen Bekkhus)\n\n### v1.0.14 (2013-05-03)\n\n* Add failing hash tests. (Ben Trask)\n* Enable hash calculation again (Eugene Girshov)\n* Test for immediate data events (Tim Smart)\n* Re-arrange IncomingForm#parse (Tim Smart)\n\n### v1.0.13\n\n* Only update hash if update method exists (Sven Lito)\n* According to travis v0.10 needs to go quoted (Sven Lito)\n* Bumping build node versions (Sven Lito)\n* Additional fix for empty requests (Eugene Girshov)\n* Change the default to 1000, to match the new Node behaviour. (OrangeDog)\n* Add ability to control maxKeys in the querystring parser. (OrangeDog)\n* Adjust test case to work with node 0.9.x (Eugene Girshov)\n* Update package.json (Sven Lito)\n* Path adjustment according to eb4468b (Markus Ast)\n\n### v1.0.12\n\n* Emit error on aborted connections (Eugene Girshov)\n* Add support for empty requests (Eugene Girshov)\n* Fix name/filename handling in Content-Disposition (jesperp)\n* Tolerate malformed closing boundary in multipart (Eugene Girshov)\n* Ignore preamble in multipart messages (Eugene Girshov)\n* Add support for application/json (Mike Frey, Carlos Rodriguez)\n* Add support for Base64 encoding (Elmer Bulthuis)\n* Add File#toJSON (TJ Holowaychuk)\n* Remove support for Node.js 0.4 & 0.6 (Andrew Kelley)\n* Documentation improvements (Sven Lito, Andre Azevedo)\n* Add support for application/octet-stream (Ion Lupascu, Chris Scribner)\n* Use os.tmpdir() to get tmp directory (Andrew Kelley)\n* Improve package.json (Andrew Kelley, Sven Lito)\n* Fix benchmark script (Andrew Kelley)\n* Fix scope issue in incoming_forms (Sven Lito)\n* Fix file handle leak on error (OrangeDog)\n\n---\n\n[First commit, #3270eb4b1f8b (May 4th, 2010)](https://github.com/node-formidable/formidable/commit/3270eb4b1f8bb667b8c12f64c36a4e7b854216d8)\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2011-present Felix Geisendörfer, and contributors.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <img alt=\"npm formidable package logo\" src=\"https://raw.githubusercontent.com/node-formidable/formidable/master/logo.png\" />\n</p>\n\n# formidable [![npm version][npmv-img]][npmv-url] [![MIT license][license-img]][license-url] [![Libera Manifesto][libera-manifesto-img]][libera-manifesto-url] [![Twitter][twitter-img]][twitter-url]\n\n> A Node.js module for parsing form data, especially file uploads.\n\n[![Code style][codestyle-img]][codestyle-url]\n[![linux build status][linux-build-img]][build-url]\n[![macos build status][macos-build-img]][build-url]\n<!-- [![codecoverage][codecov-img]][codecov-url] -->\n\nIf you have any _how-to_ kind of questions, please read the [Contributing\nGuide][contributing-url] and [Code of Conduct][code_of_conduct-url]\ndocuments.<br /> For bugs reports and feature requests, [please create an\nissue][open-issue-url] or ping [@wgw_eth / @wgw_lol][twitter-url]\nat Twitter.\n\n[![Conventional Commits][ccommits-img]][ccommits-url]\n[![Minimum Required Nodejs][nodejs-img]][npmv-url]\n[![Buy me a Kofi][kofi-img]][kofi-url]\n[![Make A Pull Request][prs-welcome-img]][prs-welcome-url]\n<!-- [![Tidelift Subscription][tidelift-img]][tidelift-url] -->\n<!-- [![Renovate App Status][renovateapp-img]][renovateapp-url] -->\n\nThis project is [semantically versioned](https://semver.org) and if you want support in migrating between versions you can schedule us for training or support us through donations, so we can prioritize.\n\n> [!CAUTION]\n> As of April 2025, old versions like v1 and v2 are still the most used, while they are deprecated for years -- they are also vulnerable to attacks if you are not implementing it properly. **Please upgrade!** We are here to help, and AI Editors & Agents could help a lot in such codemod-like migrations.\n\n> [!TIP]\n> If you are starting a fresh project, you can check out the `formidable-mini` which is a super minimal version of Formidable (not quite configurable yet, but when it does it could become the basis for `formidable@v4`), using web standards like FormData API and File API, and you can use it to stream uploads directly to S3 or other such services.\n\n<!-- This project is [semantically versioned](https://semver.org) and available as\npart of the [Tidelift Subscription][tidelift-url] for professional grade\nassurances, enhanced support and security.\n[Learn more.](https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise)\n\n_The maintainers of `formidable` and thousands of other packages are working\nwith Tidelift to deliver commercial support and maintenance for the Open Source\ndependencies you use to build your applications. Save time, reduce risk, and\nimprove code health, while paying the maintainers of the exact dependencies you\nuse._ -->\n\n[![][npm-weekly-img]][npmv-url] [![][npm-monthly-img]][npmv-url]\n[![][npm-yearly-img]][npmv-url] [![][npm-alltime-img]][npmv-url]\n\n## Project Status: Maintained\n\n> [!NOTE]\n> Check [VERSION NOTES](https://github.com/node-formidable/formidable/blob/master/VERSION_NOTES.md) for more information on v1, v2, and v3 plans, NPM dist-tags and branches._\n\nThis module was initially developed by\n[**@felixge**](https://github.com/felixge) for\n[Transloadit](http://transloadit.com/), a service focused on uploading and\nencoding images and videos. It has been battle-tested against hundreds of GBs of\nfile uploads from a large variety of clients and is considered production-ready\nand is used in production for years.\n\nCurrently, we are few maintainers trying to deal with it. :) More contributors\nare always welcome! :heart: Jump on\n[issue #412](https://github.com/felixge/node-formidable/issues/412) which is\nclosed, but if you are interested we can discuss it and add you after strict\nrules, like enabling Two-Factor Auth in your npm and GitHub accounts.\n\n## Highlights\n\n- [Fast (~900-2500 mb/sec)](#benchmarks) & streaming multipart parser\n- Automatically writing file uploads to disk (optional, see\n  [`options.fileWriteStreamHandler`](#options))\n- [Plugins API](#useplugin-plugin) - allowing custom parsers and plugins\n- Low memory footprint\n- Graceful error handling\n- Very high test coverage\n\n## Install\n\nThis package is a dual ESM/commonjs package.\n\n> [!NOTE]\n> This project requires `Node.js >= 20`. Install it using [yarn](https://yarnpkg.com) or [npm](https://npmjs.com).<br /> _We highly recommend to use Yarn when you think to contribute to this project._\n\nThis is a low-level package, and if you're using a high-level framework it _may_\nalready be included. Check the examples below and the [examples/](https://github.com/node-formidable/formidable/tree/master/examples) folder.\n\n```\n# v2\nnpm install formidable@v2\n\n# v3\nnpm install formidable\nnpm install formidable@v3\n```\n\n_**Note:** Future not ready releases will be published on `*-next` dist-tags for the corresponding version._\n\n\n## Examples\n\nFor more examples look at the `examples/` directory.\n\n### with Node.js http module\n\nParse an incoming file upload, with the\n[Node.js's built-in `http` module](https://nodejs.org/api/http.html).\n\n```js\nimport http from 'node:http';\nimport formidable, {errors as formidableErrors} from 'formidable';\n\nconst server = http.createServer(async (req, res) => {\n  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {\n    // parse a file upload\n    const form = formidable({});\n    let fields;\n    let files;\n    try {\n        [fields, files] = await form.parse(req);\n    } catch (err) {\n        // example to check for a very specific error\n        if (err.code === formidableErrors.maxFieldsExceeded) {\n\n        }\n        console.error(err);\n        res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });\n        res.end(String(err));\n        return;\n    }\n    res.writeHead(200, { 'Content-Type': 'application/json' });\n    res.end(JSON.stringify({ fields, files }, null, 2));\n    return;\n  }\n\n  // show a file upload form\n  res.writeHead(200, { 'Content-Type': 'text/html' });\n  res.end(`\n    <h2>With Node.js <code>\"http\"</code> module</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>File: <input type=\"file\" name=\"multipleFiles\" multiple=\"multiple\" /></div>\n      <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `);\n});\n\nserver.listen(8080, () => {\n  console.log('Server listening on http://localhost:8080/ ...');\n});\n```\n\n### with Express.js\n\nThere are multiple variants to do this, but Formidable just need Node.js Request\nstream, so something like the following example should work just fine, without\nany third-party [Express.js](https://ghub.now.sh/express) middleware.\n\nOr try the\n[examples/with-express.js](https://github.com/node-formidable/formidable/blob/master/examples/with-express.js)\n\n```js\nimport express from 'express';\nimport formidable from 'formidable';\n\nconst app = express();\n\napp.get('/', (req, res) => {\n  res.send(`\n    <h2>With <code>\"express\"</code> npm package</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>File: <input type=\"file\" name=\"someExpressFiles\" multiple=\"multiple\" /></div>\n      <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `);\n});\n\napp.post('/api/upload', (req, res, next) => {\n  const form = formidable({});\n\n  form.parse(req, (err, fields, files) => {\n    if (err) {\n      next(err);\n      return;\n    }\n    res.json({ fields, files });\n  });\n});\n\napp.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n```\n\n### with Koa and Formidable\n\nOf course, with [Koa v1, v2 or future v3](https://ghub.now.sh/koa) the things\nare very similar. You can use `formidable` manually as shown below or through\nthe [koa-better-body](https://ghub.now.sh/koa-better-body) package which is\nusing `formidable` under the hood and support more features and different\nrequest bodies, check its documentation for more info.\n\n_Note: this example is assuming Koa v2. Be aware that you should pass `ctx.req`\nwhich is Node.js's Request, and **NOT** the `ctx.request` which is Koa's Request\nobject - there is a difference._\n\n```js\nimport Koa from 'Koa';\nimport formidable from 'formidable';\n\nconst app = new Koa();\n\napp.on('error', (err) => {\n  console.error('server error', err);\n});\n\napp.use(async (ctx, next) => {\n  if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') {\n    const form = formidable({});\n\n    // not very elegant, but that's for now if you don't want to use `koa-better-body`\n    // or other middlewares.\n    await new Promise((resolve, reject) => {\n      form.parse(ctx.req, (err, fields, files) => {\n        if (err) {\n          reject(err);\n          return;\n        }\n\n        ctx.set('Content-Type', 'application/json');\n        ctx.status = 200;\n        ctx.state = { fields, files };\n        ctx.body = JSON.stringify(ctx.state, null, 2);\n        resolve();\n      });\n    });\n    await next();\n    return;\n  }\n\n  // show a file upload form\n  ctx.set('Content-Type', 'text/html');\n  ctx.status = 200;\n  ctx.body = `\n    <h2>With <code>\"koa\"</code> npm package</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n    <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n    <div>File: <input type=\"file\" name=\"koaFiles\" multiple=\"multiple\" /></div>\n    <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `;\n});\n\napp.use((ctx) => {\n  console.log('The next middleware is called');\n  console.log('Results:', ctx.state);\n});\n\napp.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n```\n\n## Benchmarks\n\nThe benchmark is quite old, from the old codebase. But maybe quite true though.\nPreviously the numbers was around ~500 mb/sec. Currently with moving to the new\nNode.js Streams API it's faster. You can clearly see the differences between the\nNode versions.\n\n_Note: a lot better benchmarking could and should be done in future._\n\nBenchmarked on 8GB RAM, Xeon X3440 (2.53 GHz, 4 cores, 8 threads)\n\n```\n~/github/node-formidable master\n❯ nve --parallel 8 10 12 13 node benchmark/bench-multipart-parser.js\n\n ⬢  Node 8\n\n1261.08 mb/sec\n\n ⬢  Node 10\n\n1113.04 mb/sec\n\n ⬢  Node 12\n\n2107.00 mb/sec\n\n ⬢  Node 13\n\n2566.42 mb/sec\n```\n\n![benchmark January 29th, 2020](./benchmark/2020-01-29_xeon-x3440.png)\n\n## API\n\n### Formidable / IncomingForm\n\nAll shown are equivalent.\n\n_Please pass [`options`](#options) to the function/constructor, not by assigning\nthem to the instance `form`_\n\n```js\nimport formidable from 'formidable';\nconst form = formidable(options);\n```\n\n### Options\n\nSee it's defaults in [src/Formidable.js DEFAULT_OPTIONS](./src/Formidable.js)\n(the `DEFAULT_OPTIONS` constant).\n\n- `options.encoding` **{string}** - default `'utf-8'`; sets encoding for\n  incoming form fields,\n- `options.uploadDir` **{string}** - default `os.tmpdir()`; the directory for\n  placing file uploads in. You can move them later by using `fs.rename()`.\n- `options.keepExtensions` **{boolean}** - default `false`; to include the\n  extensions of the original files or not\n- `options.allowEmptyFiles` **{boolean}** - default `false`; allow upload empty\n  files\n- `options.minFileSize` **{number}** - default `1` (1byte); the minium size of\n  uploaded file.\n- `options.maxFiles` **{number}** - default `Infinity`;\n  limit the amount of uploaded files, set Infinity for unlimited\n- `options.maxFileSize` **{number}** - default `200 * 1024 * 1024` (200mb);\n  limit the size of each uploaded file.\n- `options.maxTotalFileSize` **{number}** - default `options.maxFileSize`;\n  limit the size of the batch of uploaded files.\n- `options.maxFields` **{number}** - default `1000`; limit the number of fields, set Infinity for unlimited\n- `options.maxFieldsSize` **{number}** - default `20 * 1024 * 1024` (20mb);\n  limit the amount of memory all fields together (except files) can allocate in\n  bytes.\n- `options.hashAlgorithm` **{string | false}** - default `false`; include checksums calculated\n  for incoming files, set this to some hash algorithm, see\n  [crypto.createHash](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options)\n  for available algorithms\n- `options.fileWriteStreamHandler` **{function}** - default `null`, which by\n  default writes to host machine file system every file parsed; The function\n  should return an instance of a\n  [Writable stream](https://nodejs.org/api/stream.html#stream_class_stream_writable)\n  that will receive the uploaded file data. With this option, you can have any\n  custom behavior regarding where the uploaded file data will be streamed for.\n  If you are looking to write the file uploaded in other types of cloud storages\n  (AWS S3, Azure blob storage, Google cloud storage) or private file storage,\n  this is the option you're looking for. When this option is defined the default\n  behavior of writing the file in the host machine file system is lost.\n- `options.filename` **{function}** - default `undefined` Use it to control\n  newFilename. Must return a string. Will be joined with options.uploadDir.\n\n- `options.filter` **{function}** - default function that always returns true.\n  Use it to filter files before they are uploaded. Must return a boolean. Will not make the form.parse error\n\n- `options.createDirsFromUploads` **{boolean}** - default false. If true, makes direct folder uploads possible. Use `<input type=\"file\" name=\"folders\" webkitdirectory directory multiple>` to create a form to upload folders. Has to be used with the options `options.uploadDir` and `options.filename` where `options.filename` has to return a string with the character `/` for folders to be created. The base will be `options.uploadDir`.\n\n\n#### `options.filename`  **{function}** function (name, ext, part, form) -> string\n\nwhere part can be decomposed as\n\n```js\nconst { originalFilename, mimetype} = part;\n```\n\n_**Note:** If this size of combined fields, or size of some file is exceeded, an\n`'error'` event is fired._\n\n```js\n// The amount of bytes received for this form so far.\nform.bytesReceived;\n```\n\n```js\n// The expected number of bytes in this form.\nform.bytesExpected;\n```\n\n#### `options.filter`  **{function}** function ({name, originalFilename, mimetype}) -> boolean\n\nBehaves like Array.filter: Returning false will simply ignore the file and go to the next.\n\n```js\nconst options = {\n  filter: function ({name, originalFilename, mimetype}) {\n    // keep only images\n    return mimetype && mimetype.includes(\"image\");\n  }\n};\n```\n\n**Note:** use an outside variable to cancel all uploads upon the first error\n\n**Note:** use form.emit('error') to make form.parse error\n\n```js\nlet cancelUploads = false;// create variable at the same scope as form\nconst options = {\n  filter: function ({name, originalFilename, mimetype}) {\n    // keep only images\n    const valid = mimetype && mimetype.includes(\"image\");\n    if (!valid) {\n      form.emit('error', new formidableErrors.default('invalid type', 0, 400)); // optional make form.parse error\n      cancelUploads = true; //variable to make filter return false after the first problem\n    }\n    return valid && !cancelUploads;\n  }\n};\n```\n\n\n### .parse(request, ?callback)\n\nParses an incoming Node.js `request` containing form data. If `callback` is not provided a promise is returned.\n\n```js\nconst form = formidable({ uploadDir: __dirname });\n\nform.parse(req, (err, fields, files) => {\n  console.log('fields:', fields);\n  console.log('files:', files);\n});\n\n// with Promise\nconst [fields, files] = await form.parse(req);\n```\n\nYou may overwrite this method if you are interested in directly accessing the\nmultipart stream. Doing so will disable any `'field'` / `'file'` events\nprocessing which would occur otherwise, making you fully responsible for\nhandling the processing.\n\nAbout `uploadDir`, given the following directory structure\n```\nproject-name\n├── src\n│   └── server.js\n│\n└── uploads\n    └── image.jpg\n```\n\n`__dirname` would be the same directory as the source file itself (src)\n\n\n```js\n `${__dirname}/../uploads`\n```\n\nto put files in uploads.\n\nOmitting `__dirname` would make the path relative to the current working directory. This would be the same if server.js is launched from src but not project-name.\n\n\n`null` will use default which is `os.tmpdir()`\n\nNote: If the directory does not exist, the uploaded files are __silently discarded__. To make sure it exists:\n\n```js\nimport {createNecessaryDirectoriesSync} from \"filesac\";\n\n\nconst uploadPath = `${__dirname}/../uploads`;\ncreateNecessaryDirectoriesSync(`${uploadPath}/x`);\n```\n\n\nIn the example below, we listen on couple of events and direct them to the\n`data` listener, so you can do whatever you choose there, based on whether its\nbefore the file been emitted, the header value, the header name, on field, on\nfile and etc.\n\nOr the other way could be to just override the `form.onPart` as it's shown a bit\nlater.\n\n```js\nform.once('error', console.error);\n\nform.on('fileBegin', (formname, file) => {\n  form.emit('data', { name: 'fileBegin', formname, value: file });\n});\n\nform.on('file', (formname, file) => {\n  form.emit('data', { name: 'file', formname, value: file });\n});\n\nform.on('field', (fieldName, fieldValue) => {\n  form.emit('data', { name: 'field', key: fieldName, value: fieldValue });\n});\n\nform.once('end', () => {\n  console.log('Done!');\n});\n\n// If you want to customize whatever you want...\nform.on('data', ({ name, key, value, buffer, start, end, formname, ...more }) => {\n  if (name === 'partBegin') {\n  }\n  if (name === 'partData') {\n  }\n  if (name === 'headerField') {\n  }\n  if (name === 'headerValue') {\n  }\n  if (name === 'headerEnd') {\n  }\n  if (name === 'headersEnd') {\n  }\n  if (name === 'field') {\n    console.log('field name:', key);\n    console.log('field value:', value);\n  }\n  if (name === 'file') {\n    console.log('file:', formname, value);\n  }\n  if (name === 'fileBegin') {\n    console.log('fileBegin:', formname, value);\n  }\n});\n```\n\n### .use(plugin: Plugin)\n\nA method that allows you to extend the Formidable library. By default we include\n4 plugins, which essentially are adapters to plug the different built-in parsers.\n\n**The plugins added by this method are always enabled.**\n\n_See [src/plugins/](./src/plugins/) for more detailed look on default plugins._\n\nThe `plugin` param has such signature:\n\n```typescript\nfunction(formidable: Formidable, options: Options): void;\n```\n\nThe architecture is simple. The `plugin` is a function that is passed with the\nFormidable instance (the `form` across the README examples) and the options.\n\n**Note:** the plugin function's `this` context is also the same instance.\n\n```js\nconst form = formidable({ keepExtensions: true });\n\nform.use((self, options) => {\n  // self === this === form\n  console.log('woohoo, custom plugin');\n  // do your stuff; check `src/plugins` for inspiration\n});\n\nform.parse(req, (error, fields, files) => {\n  console.log('done!');\n});\n```\n\n**Important to note**, is that inside plugin `this.options`, `self.options` and\n`options` MAY or MAY NOT be the same. General best practice is to always use the\n`this`, so you can later test your plugin independently and more easily.\n\nIf you want to disable some parsing capabilities of Formidable, you can disable\nthe plugin which corresponds to the parser. For example, if you want to disable\nmultipart parsing (so the [src/parsers/Multipart.js](./src/parsers/Multipart.js)\nwhich is used in [src/plugins/multipart.js](./src/plugins/multipart.js)), then\nyou can remove it from the `options.enabledPlugins`, like so\n\n```js\nimport formidable, {octetstream, querystring, json} from \"formidable\";\nconst form = formidable({\n  hashAlgorithm: 'sha1',\n  enabledPlugins: [octetstream, querystring, json],\n});\n```\n\n**Be aware** that the order _MAY_ be important too. The names corresponds 1:1 to\nfiles in [src/plugins/](./src/plugins) folder.\n\nPull requests for new built-in plugins MAY be accepted - for example, more\nadvanced querystring parser. Add your plugin as a new file in `src/plugins/`\nfolder (lowercased) and follow how the other plugins are made.\n\n### form.onPart\n\nIf you want to use Formidable to only handle certain parts for you, you can do\nsomething similar. Or see\n[#387](https://github.com/node-formidable/node-formidable/issues/387) for\ninspiration, you can for example validate the mime-type.\n\n```js\nconst form = formidable();\n\nform.onPart = (part) => {\n  part.on('data', (buffer) => {\n    // do whatever you want here\n  });\n};\n```\n\nFor example, force Formidable to be used only on non-file \"parts\" (i.e., html\nfields)\n\n```js\nconst form = formidable();\n\nform.onPart = function (part) {\n  // let formidable handle only non-file parts\n  if (part.originalFilename === '' || !part.mimetype) {\n    // used internally, please do not override!\n    form._handlePart(part);\n  }\n};\n```\n\n### File\n\n```ts\nexport interface File {\n  // The size of the uploaded file in bytes.\n  // If the file is still being uploaded (see `'fileBegin'` event),\n  // this property says how many bytes of the file have been written to disk yet.\n  file.size: number;\n\n  // The path this file is being written to. You can modify this in the `'fileBegin'` event in\n  // case you are unhappy with the way formidable generates a temporary path for your files.\n  file.filepath: string;\n\n  // The name this file had according to the uploading client.\n  file.originalFilename: string | null;\n\n  // calculated based on options provided\n  file.newFilename: string | null;\n\n  // The mime type of this file, according to the uploading client.\n  file.mimetype: string | null;\n\n  // A Date object (or `null`) containing the time this file was last written to.\n  // Mostly here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).\n  file.mtime: Date | null;\n\n  file.hashAlgorithm: false | |'sha1' | 'md5' | 'sha256'\n  // If `options.hashAlgorithm` calculation was set, you can read the hex digest out of this var (at the end it will be a string)\n  file.hash: string | object | null;\n}\n```\n\n#### file.toJSON()\n\nThis method returns a JSON-representation of the file, allowing you to\n`JSON.stringify()` the file which is useful for logging and responding to\nrequests.\n\n### Events\n\n#### `'progress'`\n\nEmitted after each incoming chunk of data that has been parsed. Can be used to\nroll your own progress bar. **Warning** Use this only for server side progress bar. On the client side better use `XMLHttpRequest` with `xhr.upload.onprogress =`\n\n```js\nform.on('progress', (bytesReceived, bytesExpected) => {});\n```\n\n#### `'field'`\n\nEmitted whenever a field / value pair has been received.\n\n```js\nform.on('field', (name, value) => {});\n```\n\n#### `'fileBegin'`\n\nEmitted whenever a new file is detected in the upload stream. Use this event if\nyou want to stream the file to somewhere else while buffering the upload on the\nfile system.\n\n```js\nform.on('fileBegin', (formName, file) => {\n    // accessible here\n    // formName the name in the form (<input name=\"thisname\" type=\"file\">) or http filename for octetstream\n    // file.originalFilename http filename or null if there was a parsing error\n    // file.newFilename generated hexoid or what options.filename returned\n    // file.filepath default pathname as per options.uploadDir and options.filename\n    // file.filepath = CUSTOM_PATH // to change the final path\n});\n```\n\n#### `'file'`\n\nEmitted whenever a field / file pair has been received. `file` is an instance of\n`File`.\n\n```js\nform.on('file', (formname, file) => {\n    // same as fileBegin, except\n    // it is too late to change file.filepath\n    // file.hash is available if options.hash was used\n});\n```\n\n#### `'error'`\n\nEmitted when there is an error processing the incoming form. A request that\nexperiences an error is automatically paused, you will have to manually call\n`request.resume()` if you want the request to continue firing `'data'` events.\n\nMay have `error.httpCode` and `error.code` attached.\n\n```js\nform.on('error', (err) => {});\n```\n\n#### `'aborted'`\n\nEmitted when the request was aborted by the user. Right now this can be due to a\n'timeout' or 'close' event on the socket. After this event is emitted, an\n`error` event will follow. In the future there will be a separate 'timeout'\nevent (needs a change in the node core).\n\n```js\nform.on('aborted', () => {});\n```\n\n#### `'end'`\n\nEmitted when the entire request has been received, and all contained files have\nfinished flushing to disk. This is a great place for you to send your response.\n\n```js\nform.on('end', () => {});\n```\n\n\n### Helpers\n\n#### firstValues\n\nGets first values of fields, like pre 3.0.0 without multiples pass in a list of optional exceptions where arrays of strings is still wanted (`<select multiple>` for example)\n\n```js\nimport { firstValues } from 'formidable/src/helpers/firstValues.js';\n\n// ...\nform.parse(request, async (error, fieldsMultiple, files) => {\n    if (error) {\n        //...\n    }\n    const exceptions = ['thisshouldbeanarray'];\n    const fieldsSingle = firstValues(form, fieldsMultiple, exceptions);\n    // ...\n```\n\n#### readBooleans\n\nHtml form input type=\"checkbox\" only send the value \"on\" if checked,\nconvert it to booleans for each input that is expected to be sent as a checkbox, only use after firstValues or similar was called.\n\n```js\nimport { firstValues } from 'formidable/src/helpers/firstValues.js';\nimport { readBooleans } from 'formidable/src/helpers/readBooleans.js';\n\n// ...\nform.parse(request, async (error, fieldsMultiple, files) => {\n    if (error) {\n        //...\n    }\n    const fieldsSingle = firstValues(form, fieldsMultiple);\n\n    const expectedBooleans = ['checkbox1', 'wantsNewsLetter', 'hasACar'];\n    const fieldsWithBooleans = readBooleans(fieldsSingle, expectedBooleans);\n    // ...\n```\n\n## Changelog\n\n[./CHANGELOG.md](./CHANGELOG.md)\n\n## Ports & Credits\n\n- [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++\n  parser based on formidable\n- [Ryan Dahl](https://x.com/rough__sea) for his work on\n  [http-parser](http://github.com/ry/http-parser) which heavily inspired the\n  initial `multipart_parser.js`.\n\n## Contributing\n\nIf the documentation is unclear or has a typo, please click on the page's `Edit`\nbutton (pencil icon) and suggest a correction. If you would like to help us fix\na bug or add a new feature, please check our [Contributing\nGuide][contributing-url]. Pull requests are welcome!\n\nThanks goes to these wonderful people\n([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tr>\n    <td align=\"center\"><a href=\"https://twitter.com/felixge\"><img src=\"https://avatars3.githubusercontent.com/u/15000?s=460&v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Felix Geisendörfer</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=felixge\" title=\"Code\">💻</a> <a href=\"#design-felixge\" title=\"Design\">🎨</a> <a href=\"#ideas-felixge\" title=\"Ideas, Planning, & Feedback\">🤔</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=felixge\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://tunnckoCore.com\"><img src=\"https://avatars3.githubusercontent.com/u/5038030?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Charlike Mike Reagent</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3AtunnckoCore\" title=\"Bug reports\">🐛</a> <a href=\"#infra-tunnckoCore\" title=\"Infrastructure (Hosting, Build-Tools, etc)\">🚇</a> <a href=\"#design-tunnckoCore\" title=\"Design\">🎨</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore\" title=\"Code\">💻</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore\" title=\"Documentation\">📖</a> <a href=\"#example-tunnckoCore\" title=\"Examples\">💡</a> <a href=\"#ideas-tunnckoCore\" title=\"Ideas, Planning, & Feedback\">🤔</a> <a href=\"#maintenance-tunnckoCore\" title=\"Maintenance\">🚧</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore\" title=\"Tests\">⚠️</a></td>\n    <td align=\"center\"><a href=\"https://github.com/kedarv\"><img src=\"https://avatars1.githubusercontent.com/u/1365665?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Kedar</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=kedarv\" title=\"Code\">💻</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=kedarv\" title=\"Tests\">⚠️</a> <a href=\"#question-kedarv\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Akedarv\" title=\"Bug reports\">🐛</a></td>\n    <td align=\"center\"><a href=\"https://github.com/GrosSacASac\"><img src=\"https://avatars0.githubusercontent.com/u/5721194?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Walle Cyril</b></sub></a><br /><a href=\"#question-GrosSacASac\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3AGrosSacASac\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=GrosSacASac\" title=\"Code\">💻</a> <a href=\"#financial-GrosSacASac\" title=\"Financial\">💵</a> <a href=\"#ideas-GrosSacASac\" title=\"Ideas, Planning, & Feedback\">🤔</a> <a href=\"#maintenance-GrosSacASac\" title=\"Maintenance\">🚧</a></td>\n    <td align=\"center\"><a href=\"https://github.com/xarguments\"><img src=\"https://avatars2.githubusercontent.com/u/40522463?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Xargs</b></sub></a><br /><a href=\"#question-xarguments\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Axarguments\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=xarguments\" title=\"Code\">💻</a> <a href=\"#maintenance-xarguments\" title=\"Maintenance\">🚧</a></td>\n    <td align=\"center\"><a href=\"https://github.com/Amit-A\"><img src=\"https://avatars1.githubusercontent.com/u/7987238?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Amit-A</b></sub></a><br /><a href=\"#question-Amit-A\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3AAmit-A\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=Amit-A\" title=\"Code\">💻</a></td>\n  </tr>\n  <tr>\n    <td align=\"center\"><a href=\"https://charmander.me/\"><img src=\"https://avatars1.githubusercontent.com/u/1889843?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Charmander</b></sub></a><br /><a href=\"#question-charmander\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Acharmander\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=charmander\" title=\"Code\">💻</a> <a href=\"#ideas-charmander\" title=\"Ideas, Planning, & Feedback\">🤔</a> <a href=\"#maintenance-charmander\" title=\"Maintenance\">🚧</a></td>\n    <td align=\"center\"><a href=\"https://twitter.com/dylan_piercey\"><img src=\"https://avatars2.githubusercontent.com/u/4985201?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Dylan Piercey</b></sub></a><br /><a href=\"#ideas-DylanPiercey\" title=\"Ideas, Planning, & Feedback\">🤔</a></td>\n    <td align=\"center\"><a href=\"http://ochrona.jawne.info.pl\"><img src=\"https://avatars1.githubusercontent.com/u/3618479?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Adam Dobrawy</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Aad-m\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=ad-m\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://github.com/amitrohatgi\"><img src=\"https://avatars3.githubusercontent.com/u/12177021?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>amitrohatgi</b></sub></a><br /><a href=\"#ideas-amitrohatgi\" title=\"Ideas, Planning, & Feedback\">🤔</a></td>\n    <td align=\"center\"><a href=\"https://github.com/fengxinming\"><img src=\"https://avatars2.githubusercontent.com/u/6262382?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Jesse Feng</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Afengxinming\" title=\"Bug reports\">🐛</a></td>\n    <td align=\"center\"><a href=\"https://qtmsheep.com\"><img src=\"https://avatars1.githubusercontent.com/u/7271496?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Nathanael Demacon</b></sub></a><br /><a href=\"#question-quantumsheep\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=quantumsheep\" title=\"Code\">💻</a> <a href=\"https://github.com/node-formidable/node-formidable/pulls?q=is%3Apr+reviewed-by%3Aquantumsheep\" title=\"Reviewed Pull Requests\">👀</a></td>\n  </tr>\n  <tr>\n    <td align=\"center\"><a href=\"https://github.com/MunMunMiao\"><img src=\"https://avatars1.githubusercontent.com/u/18216142?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>MunMunMiao</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3AMunMunMiao\" title=\"Bug reports\">🐛</a></td>\n    <td align=\"center\"><a href=\"https://github.com/gabipetrovay\"><img src=\"https://avatars0.githubusercontent.com/u/1170398?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Gabriel Petrovay</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Agabipetrovay\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=gabipetrovay\" title=\"Code\">💻</a></td>\n    <td align=\"center\"><a href=\"https://github.com/Elzair\"><img src=\"https://avatars0.githubusercontent.com/u/2352818?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Philip Woods</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=Elzair\" title=\"Code\">💻</a> <a href=\"#ideas-Elzair\" title=\"Ideas, Planning, & Feedback\">🤔</a></td>\n    <td align=\"center\"><a href=\"https://github.com/dmolim\"><img src=\"https://avatars2.githubusercontent.com/u/7090374?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Dmitry Ivonin</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=dmolim\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://audiobox.fm\"><img src=\"https://avatars1.githubusercontent.com/u/12844?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Claudio Poli</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=masterkain\" title=\"Code\">💻</a></td>\n  </tr>\n</table>\n\n<!-- markdownlint-enable -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nFrom a [Felix blog post](https://felixge.de/2013/03/11/the-pull-request-hack/):\n\n- [Sven Lito](https://github.com/svnlto) for fixing bugs and merging patches\n- [egirshov](https://github.com/egirshov) for contributing many improvements to the node-formidable multipart parser\n- [Andrew Kelley](https://github.com/superjoe30) for also helping with fixing bugs and making improvements\n- [Mike Frey](https://github.com/mikefrey) for contributing JSON support\n\n## License\n\nFormidable is licensed under the [MIT License][license-url].\n\n<!-- badges -->\n<!-- prettier-ignore-start -->\n\n[codestyle-url]: https://github.com/airbnb/javascript\n[codestyle-img]: https://badgen.net/badge/code%20style/airbnb%20%2B%20prettier/ff5a5f?icon=airbnb&cache=300\n[codecov-url]: https://codecov.io/gh/node-formidable/formidable\n[codecov-img]: https://badgen.net/codecov/c/github/node-formidable/formidable/master?icon=codecov\n[npmv-canary-img]: https://badgen.net/npm/v/formidable/canary?icon=npm\n[npmv-dev-img]: https://badgen.net/npm/v/formidable/dev?icon=npm\n[npmv-img]: https://badgen.net/npm/v/formidable?icon=npm\n[npmv-url]: https://npmjs.com/package/formidable\n[license-img]: https://badgen.net/npm/license/formidable\n[license-url]: https://github.com/node-formidable/formidable/blob/master/LICENSE\n[chat-img]: https://badgen.net/badge/chat/on%20gitter/46BC99?icon=gitter\n[chat-url]: https://gitter.im/node-formidable/Lobby\n[libera-manifesto-url]: https://liberamanifesto.com\n[libera-manifesto-img]: https://badgen.net/badge/libera/manifesto/grey\n[renovateapp-url]: https://renovatebot.com\n[renovateapp-img]: https://badgen.net/badge/renovate/enabled/green?cache=300\n[prs-welcome-img]: https://badgen.net/badge/PRs/welcome/green?cache=300\n[prs-welcome-url]: http://makeapullrequest.com\n[twitter-url]: https://twitter.com/wgw_eth\n[twitter-img]: https://badgen.net/badge/twitter/follow/wgw_eth?icon=twitter&color=1da1f2&cache=30\n\n[npm-weekly-img]: https://badgen.net/npm/dw/formidable?icon=npm&cache=300\n[npm-monthly-img]: https://badgen.net/npm/dm/formidable?icon=npm&cache=300\n[npm-yearly-img]: https://badgen.net/npm/dy/formidable?icon=npm&cache=300\n[npm-alltime-img]: https://badgen.net/npm/dt/formidable?icon=npm&cache=300&label=total%20downloads\n\n[nodejs-img]: https://badgen.net/badge/node/>=%2010.13/green?cache=300\n\n[ccommits-url]: https://conventionalcommits.org/\n[ccommits-img]: https://badgen.net/badge/conventional%20commits/v1.0.0/green?cache=300\n\n[contributing-url]: https://github.com/node-formidable/.github/blob/master/CONTRIBUTING.md\n[code_of_conduct-url]: https://github.com/node-formidable/.github/blob/master/CODE_OF_CONDUCT.md\n\n[open-issue-url]: https://github.com/node-formidable/formidable/issues/new\n\n[tidelift-url]: https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise\n[tidelift-img]: https://badgen.net/badge/tidelift/subscription/4B5168?labelColor=F6914D\n\n[kofi-url]: https://ko-fi.com/tunnckoCore/commissions\n[kofi-img]: https://badgen.net/badge/ko-fi/support/29abe0c2?cache=300&icon=https://rawcdn.githack.com/tunnckoCore/badgen-icons/f8264c6414e0bec449dd86f2241d50a9b89a1203/icons/kofi.svg\n\n[linux-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master?label=linux%20build&icon=github\n[macos-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master?label=macos%20build&icon=github\n[windows-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master/windows?cache=300&label=windows%20build&icon=github\n[build-url]: https://github.com/node-formidable/formidable/actions\n<!-- prettier-ignore-end -->\n"
  },
  {
    "path": "README_pt_BR.md",
    "content": "<p align=\"center\">\n  <img alt=\"npm formidable package logo\" src=\"https://raw.githubusercontent.com/node-formidable/formidable/master/logo.png\" />\n</p>\n\n# formidable [![npm version][npmv-img]][npmv-url] [![MIT license][license-img]][license-url] [![Libera Manifesto][libera-manifesto-img]][libera-manifesto-url] [![Twitter][twitter-img]][twitter-url]\n\n> A Node.js module for parsing form data, especially file uploads.\n\n[![Code style][codestyle-img]][codestyle-url]\n[![codecoverage][codecov-img]][codecov-url]\n[![linux build status][linux-build-img]][build-url]\n[![macos build status][macos-build-img]][build-url]\n\nSe você tiver qualquer tipo de pergunta sobre _como_ fazer, por favor leia o [Contributing\nGuia][contributing-url] e [Código de Conduta][code_of_conduct-url]\ndocumentos.<br /> Para relatórios de bugs e solicitações de recursos, [crie uma\nissue][open-issue-url] ou ping [@tunnckoCore / @3a1FcBx0](https://twitter.com/3a1FcBx0)\nno Twitter.\n\n[![Conventional Commits][ccommits-img]][ccommits-url]\n[![Minimum Required Nodejs][nodejs-img]][npmv-url]\n[![Tidelift Subscription][tidelift-img]][tidelift-url]\n[![Buy me a Kofi][kofi-img]][kofi-url]\n[![Renovate App Status][renovateapp-img]][renovateapp-url]\n[![Make A Pull Request][prs-welcome-img]][prs-welcome-url]\n\nEste projeto é [semanticamente versionado](https://semver.org) e está disponível como\nparte da [Assinatura Tidelift][tidelift-url] para nível profissional\ngarantias, suporte aprimorado e segurança.\n[Saiba mais.](https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise)\n\n_Os mantenedores do `formidable` e milhares de outros pacotes estão trabalhando\ncom Tidelift para fornecer suporte comercial e manutenção para o Open Source\ndependências que você usa para construir seus aplicativos. Economize tempo, reduza riscos e\nmelhorar a integridade do código, enquanto paga aos mantenedores das dependências exatas que você\nusar._\n\n[![][npm-weekly-img]][npmv-url] [![][npm-monthly-img]][npmv-url]\n[![][npm-yearly-img]][npmv-url] [![][npm-alltime-img]][npmv-url]\n\n## Status do Projeto: Mantido\n\n_Verifique [VERSION NOTES](https://github.com/node-formidable/formidable/blob/master/VERSION_NOTES.md) para obter mais informações sobre os planos v1, v2 e v3, NPM dist-tags e branches._\n\nEste módulo foi inicialmente desenvolvido por\n[**@felixge**](https://github.com/felixge) para\n[Transloadit](http://transloadit.com/), um serviço focado em upload e\ncodificação de imagens e vídeos. Foi testado em batalha contra centenas de GBs de\nuploads de arquivos de uma grande variedade de clientes e é considerado pronto para produção\ne é usado na produção por anos.\n\nAtualmente, somos poucos mantenedores tentando lidar com isso. :) Mais contribuidores\nsão sempre bem-vindos! ❤️ Pule\n[issue #412](https://github.com/felixge/node-formidable/issues/412) que está\nfechado, mas se você estiver interessado, podemos discuti-lo e adicioná-lo após regras estritas, como ativar o Two-Factor Auth em suas contas npm e GitHub.\n\n## Destaques\n\n- [Rápido (~ 900-2500 mb/seg)](#benchmarks) e analisador multiparte de streaming\n- Gravar uploads de arquivos automaticamente no disco (opcional, consulte\n   [`options.fileWriteStreamHandler`](#options))\n- [API de plug-ins](#useplugin-plugin) - permitindo analisadores e plug-ins personalizados\n- Baixo consumo de memória\n- Tratamento de erros gracioso\n- Cobertura de teste muito alta\n\n## Instalar\n\nEste projeto requer `Node.js >= 10.13`. Instale-o usando\n[yarn](https://yarnpkg.com) ou [npm](https://npmjs.com).<br /> _Nós altamente\nrecomendamos usar o Yarn quando pensar em contribuir para este projeto._\n\nEste é um pacote de baixo nível e, se você estiver usando uma estrutura de alto nível, _pode_ já estar incluído. Verifique os exemplos\nabaixo e a pasta [examples/](https://github.com/node-formidable/formidable/tree/master/examples).\n\n```\n# v2\nnpm install formidable\nnpm install formidable@v2\n\n# v3\nnpm install formidable@v3\n```\n\n_**Nota:** Em um futuro próximo, a v3 será publicada na dist-tag `latest` do NPM.\nVersões futuras não prontas serão publicadas nas dist-tags `*-next` para a versão correspondente._\n\n\n## Exemplos\n\nPara mais exemplos veja o diretório `examples/`.\n\n### com módulo http Node.js\n\nAnalisar um upload de arquivo de entrada, com o\n[Módulo `http` integrado do Node.js](https://nodejs.org/api/http.html).\n\n```js\nimport http from 'node:http';\nimport formidable, {errors as formidableErrors} from 'formidable';\n\nconst server = http.createServer((req, res) => {\n  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {\n    // analisar um upload de arquivo\n    const form = formidable({});\n\n    form.parse(req, (err, fields, files) => {\n      if (err) {\n        // exemplo para verificar um erro muito específico\n        if (err.code === formidableErrors.maxFieldsExceeded) {\n\n        }\n        res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });\n        res.end(String(err));\n        return;\n      }\n      res.writeHead(200, { 'Content-Type': 'application/json' });\n      res.end(JSON.stringify({ fields, files }, null, 2));\n    });\n\n    return;\n  }\n\n  // mostrar um formulário de upload de arquivo\n  res.writeHead(200, { 'Content-Type': 'text/html' });\n  res.end(`\n    <h2>With Node.js <code>\"http\"</code> module</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>File: <input type=\"file\" name=\"multipleFiles\" multiple=\"multiple\" /></div>\n      <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `);\n});\n\nserver.listen(8080, () => {\n  console.log('Server listening on http://localhost:8080/ ...');\n});\n```\n\n### com Express.js\n\nExistem várias variantes para fazer isso, mas o Formidable só precisa do Node.js Request\nstream, então algo como o exemplo a seguir deve funcionar bem, sem nenhum middleware [Express.js](https://ghub.now.sh/express) de terceiros.\n\nOu tente o\n[examples/with-express.js](https://github.com/node-formidable/formidable/blob/master/examples/with-express.js)\n\n```js\nimport express from 'express';\nimport formidable from 'formidable';\n\nconst app = express();\n\napp.get('/', (req, res) => {\n  res.send(`\n    <h2>With <code>\"express\"</code> npm package</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>File: <input type=\"file\" name=\"someExpressFiles\" multiple=\"multiple\" /></div>\n      <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `);\n});\n\napp.post('/api/upload', (req, res, next) => {\n  const form = formidable({});\n\n  form.parse(req, (err, fields, files) => {\n    if (err) {\n      next(err);\n      return;\n    }\n    res.json({ fields, files });\n  });\n});\n\napp.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n```\n\n### com Koa e Formidable\n\nClaro, com [Koa v1, v2 ou future v3](https://ghub.now.sh/koa) as coisas\nsao muito parecidas. Você pode usar `formidable` manualmente como mostrado abaixo ou através\ndo pacote [koa-better-body](https://ghub.now.sh/koa-better-body) que é\nusando `formidable` sob o capô e suporte a mais recursos e diferentes\ncorpos de solicitação, verifique sua documentação para mais informações.\n\n_Nota: este exemplo está assumindo Koa v2. Esteja ciente de que você deve passar `ctx.req`\nque é a solicitação do Node.js e **NÃO** o `ctx.request` que é a solicitação do Koa\nobjeto - há uma diferença._\n\n```js\nimport Koa from 'Koa';\nimport formidable from 'formidable';\n\nconst app = new Koa();\n\napp.on('error', (err) => {\n  console.error('server error', err);\n});\n\napp.use(async (ctx, next) => {\n  if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') {\n    const form = formidable({});\n\n     // não muito elegante, mas é por enquanto se você não quiser usar `koa-better-body`\n     // ou outros middlewares.\n    await new Promise((resolve, reject) => {\n      form.parse(ctx.req, (err, fields, files) => {\n        if (err) {\n          reject(err);\n          return;\n        }\n\n        ctx.set('Content-Type', 'application/json');\n        ctx.status = 200;\n        ctx.state = { fields, files };\n        ctx.body = JSON.stringify(ctx.state, null, 2);\n        resolve();\n      });\n    });\n    await next();\n    return;\n  }\n\n  // mostrar um formulário de upload de arquivo\n  ctx.set('Content-Type', 'text/html');\n  ctx.status = 200;\n  ctx.body = `\n    <h2>With <code>\"koa\"</code> npm package</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n    <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n    <div>File: <input type=\"file\" name=\"koaFiles\" multiple=\"multiple\" /></div>\n    <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `;\n});\n\napp.use((ctx) => {\n  console.log('The next middleware is called');\n  console.log('Results:', ctx.state);\n});\n\napp.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n```\n\n## Benchmarks\n\nO benchmark é bastante antigo, da antiga base de código. Mas talvez seja bem verdade.\nAnteriormente, os números giravam em torno de ~ 500 mb/s. Atualmente com a mudança para o novo\nNode.js Streams API, é mais rápido. Você pode ver claramente as diferenças entre as\nversões do Node.\n\n_Observação: um benchmarking muito melhor pode e deve ser feito no futuro._\n\nBenchmark realizado em 8 GB de RAM, Xeon X3440 (2,53 GHz, 4 núcleos, 8 threads)\n\n```\n~/github/node-formidable master\n❯ nve --parallel 8 10 12 13 node benchmark/bench-multipart-parser.js\n\n ⬢  Node 8\n\n1261.08 mb/sec\n\n ⬢  Node 10\n\n1113.04 mb/sec\n\n ⬢  Node 12\n\n2107.00 mb/sec\n\n ⬢  Node 13\n\n2566.42 mb/sec\n```\n\n![benchmark 29 de janeiro de 2020](./benchmark/2020-01-29_xeon-x3440.png)\n\n## API\n\n### Formidable / IncomingForm\n\nTodos os mostrados são equivalentes.\n\n_Por favor, passe [`options`](#options) para a função/construtor, não atribuindo\neles para a instância `form`_\n\n```js\nimport formidable from 'formidable';\nconst form = formidable(options);\n```\n\n### Opções\n\nVeja seus padrões em [src/Formidable.js DEFAULT_OPTIONS](./src/Formidable.js)\n(a constante `DEFAULT_OPTIONS`).\n\n- `options.encoding` **{string}** - padrão `'utf-8'`; define a codificação para campos de formulário de entrada,\n- `options.uploadDir` **{string}** - padrão `os.tmpdir()`; o diretório para colocar os uploads de arquivos. Você pode movê-los mais tarde usando `fs.rename()`.\n- `options.keepExtensions` **{boolean}** - padrão `false`; incluir as extensões dos arquivos originais ou não\n- `options.allowEmptyFiles` **{boolean}** - padrão `false`; permitir upload de arquivos vazios\n- `options.minFileSize` **{number}** - padrão `1` (1byte); o tamanho mínimo do arquivo carregado.\n- `options.maxFiles` **{number}** - padrão `Infinity`;\n  limitar a quantidade de arquivos carregados, defina Infinity para ilimitado\n- `options.maxFileSize` **{number}** - padrão `200 * 1024 * 1024` (200mb);\n  limitar o tamanho de cada arquivo carregado.\n- `options.maxTotalFileSize` **{number}** - padrão `options.maxFileSize`;\n  limitar o tamanho do lote de arquivos carregados.\n- `options.maxFields` **{number}** - padrão `1000`; limite o número de campos, defina Infinity para ilimitado\n- `options.maxFieldsSize` **{number}** - padrão `20 * 1024 * 1024` (20mb);\n  limitar a quantidade de memória que todos os campos juntos (exceto arquivos) podem alocar em\n  bytes.\n- `options.hashAlgorithm` **{string | false}** - padrão `false`; incluir checksums calculados\n  para arquivos recebidos, defina isso para algum algoritmo de hash, consulte\n  [crypto.createHash](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options)\n  para algoritmos disponíveis\n- `options.fileWriteStreamHandler` **{function}** - padrão `null`, que por padrão grava no sistema de arquivos da máquina host cada arquivo analisado; A função\n  deve retornar uma instância de um\n  [fluxo gravável](https://nodejs.org/api/stream.html#stream_class_stream_writable)\n  que receberá os dados do arquivo carregado. Com esta opção, você pode ter qualquer\n  comportamento personalizado em relação a onde os dados do arquivo carregado serão transmitidos.\n  Se você deseja gravar o arquivo carregado em outros tipos de armazenamento em nuvem\n  (AWS S3, armazenamento de blob do Azure, armazenamento em nuvem do Google) ou armazenamento de arquivo privado,\n  esta é a opção que você está procurando. Quando esta opção é definida, o comportamento padrão de gravar o arquivo no sistema de arquivos da máquina host é perdido.\n- `options.filename` **{function}** - padrão `undefined` Use-o para controlar newFilename. Deve retornar uma string. Será associado a options.uploadDir.\n\n- `options.filter` **{function}** - função padrão que sempre retorna verdadeiro.\n  Use-o para filtrar arquivos antes de serem carregados. Deve retornar um booleano.\n\n\n#### `options.filename`  **{function}** function (name, ext, part, form) -> string\n\nonde a parte pode ser decomposta como\n\n```js\nconst { originalFilename, mimetype} = part;\n```\n\n_**Observação:** Se este tamanho de campos combinados, ou tamanho de algum arquivo for excedido, um\nO evento `'error'` é disparado._\n\n```js\n// A quantidade de bytes recebidos para este formulário até agora.\nform.bytesReceived;\n```\n\n```js\n// O número esperado de bytes neste formulário.\nform.bytesExpected;\n```\n\n#### `options.filter`  **{function}** function ({name, originalFilename, mimetype}) -> boolean\n\n**Observação:** use uma variável externa para cancelar todos os uploads no primeiro erro\n\n```js\nconst options = {\n  filter: function ({name, originalFilename, mimetype}) {\n    // manter apenas imagens\n    return mimetype && mimetype.includes(\"image\");\n  }\n};\n```\n\n\n### .parse(request, callback)\n\nAnalisa uma `request` do Node.js recebida contendo dados de formulário. Se `callback` for\nfornecido, todos os campos e arquivos são coletados e passados para o retorno de chamada.\n\n```js\nconst form = formidable({ uploadDir: __dirname });\n\nform.parse(req, (err, fields, files) => {\n  console.log('fields:', fields);\n  console.log('files:', files);\n});\n```\n\nVocê pode substituir esse método se estiver interessado em acessar diretamente o\nfluxo de várias partes. Fazer isso desativará qualquer processamento de eventos `'field'` / `'file'`\nque ocorreria de outra forma, tornando você totalmente responsável por lidar com o processamento.\n\nSobre `uploadDir`, dada a seguinte estrutura de diretório\n```\nproject-name\n├── src\n│   └── server.js\n│\n└── uploads\n    └── image.jpg\n```\n\n`__dirname` seria o mesmo diretório que o próprio arquivo de origem (src)\n\n\n```js\n `${__dirname}/../uploads`\n```\n\npara colocar arquivos em uploads.\n\nOmitir `__dirname` tornaria o caminho relativo ao diretório de trabalho atual. Isso seria o mesmo se server.js fosse iniciado a partir de src, mas não de project-name.\n\n\n`null` usará o padrão que é `os.tmpdir()`\n\nNota: Se o diretório não existir, os arquivos carregados são __silenciosamente descartados__. Para ter certeza de que existe:\n\n```js\nimport {createNecessaryDirectoriesSync} from \"filesac\";\n\n\nconst uploadPath = `${__dirname}/../uploads`;\ncreateNecessaryDirectoriesSync(`${uploadPath}/x`);\n```\n\n\nNo exemplo abaixo, escutamos alguns eventos e os direcionamos para o ouvinte `data`, para\nque você possa fazer o que quiser lá, com base em se é antes do arquivo ser emitido, o valor do\ncabeçalho, o nome do cabeçalho, no campo , em arquivo e etc.\n\nOu a outra maneira poderia ser apenas substituir o `form.onPart` como é mostrado um pouco\nmais tarde.\n\n```js\nform.once('error', console.error);\n\nform.on('fileBegin', (formname, file) => {\n  form.emit('data', { name: 'fileBegin', formname, value: file });\n});\n\nform.on('file', (formname, file) => {\n  form.emit('data', { name: 'file', formname, value: file });\n});\n\nform.on('field', (fieldName, fieldValue) => {\n  form.emit('data', { name: 'field', key: fieldName, value: fieldValue });\n});\n\nform.once('end', () => {\n  console.log('Done!');\n});\n\n// Se você quiser personalizar o que quiser...\nform.on('data', ({ name, key, value, buffer, start, end, formname, ...more }) => {\n  if (name === 'partBegin') {\n  }\n  if (name === 'partData') {\n  }\n  if (name === 'headerField') {\n  }\n  if (name === 'headerValue') {\n  }\n  if (name === 'headerEnd') {\n  }\n  if (name === 'headersEnd') {\n  }\n  if (name === 'field') {\n    console.log('field name:', key);\n    console.log('field value:', value);\n  }\n  if (name === 'file') {\n    console.log('file:', formname, value);\n  }\n  if (name === 'fileBegin') {\n    console.log('fileBegin:', formname, value);\n  }\n});\n```\n\n### .use(plugin: Plugin)\n\nUm método que permite estender a biblioteca Formidable. Por padrão, incluímos\n4 plug-ins, que são essencialmente adaptadores para conectar os diferentes analisadores integrados.\n\n**Os plugins adicionados por este método estão sempre ativados.**\n\n_Consulte [src/plugins/](./src/plugins/) para uma visão mais detalhada dos plug-ins padrão._\n\nO parâmetro `plugin` tem essa assinatura:\n\n```typescript\nfunction(formidable: Formidable, options: Options): void;\n```\n\nA arquitetura é simples. O `plugin` é uma função que é passada com a instância Formidable (o `form` nos exemplos README) e as opções.\n\n**Observação:** o contexto `this` da função do plug-in também é a mesma instância.\n\n```js\nconst form = formidable({ keepExtensions: true });\n\nform.use((self, options) => {\n  // self === this === form\n  console.log('woohoo, custom plugin');\n  // faça suas coisas; verifique `src/plugins` para inspiração\n});\n\nform.parse(req, (error, fields, files) => {\n  console.log('done!');\n});\n```\n**Importante observar**, é que dentro do plugin `this.options`, `self.options` e\n`options` PODEM ou NÃO ser iguais. A melhor prática geral é sempre usar o\n`this`, para que você possa testar seu plugin mais tarde de forma independente e mais fácil.\n\nSe você quiser desabilitar alguns recursos de análise do Formidable, você pode desabilitar\no plugin que corresponde ao analisador. Por exemplo, se você deseja desabilitar a análise de\nvárias partes (para que o [src/parsers/Multipart.js](./src/parsers/Multipart.js)\nque é usado em [src/plugins/multipart.js](./src/plugins/multipart.js)), então\nvocê pode removê-lo do `options.enabledPlugins`, assim\n\n```js\nimport formidable, {octetstream, querystring, json} from \"formidable\";\nconst form = formidable({\n  hashAlgorithm: 'sha1',\n  enabledPlugins: [octetstream, querystring, json],\n});\n```\n\n**Esteja ciente** de que a ordem _PODE_ ser importante também. Os nomes correspondem 1:1 a\narquivos na pasta [src/plugins/](./src/plugins).\n\nSolicitações pull para novos plug-ins integrados PODEM ser aceitas - por exemplo, analisador de\nquerystring mais avançado. Adicione seu plugin como um novo arquivo na pasta `src/plugins/` (em letras minúsculas) e\nsiga como os outros plugins são feitos.\n\n### form.onPart\n\nSe você quiser usar Formidable para manipular apenas algumas partes para você, você pode fazer\nalguma coisa similar. ou ver\n[#387](https://github.com/node-formidable/node-formidable/issues/387) para\ninspiração, você pode, por exemplo, validar o tipo mime.\n\n```js\nconst form = formidable();\n\nform.onPart = (part) => {\n  part.on('data', (buffer) => {\n    // faça o que quiser aqui\n  });\n};\n```\n\nPor exemplo, force Formidable a ser usado apenas em \"partes\" que não sejam de arquivo (ou seja, html\nCampos)\n\n```js\nconst form = formidable();\n\nform.onPart = function (part) {\n  // deixe formidável lidar apenas com partes não arquivadas\n  if (part.originalFilename === '' || !part.mimetype) {\n    // usado internamente, por favor, não substitua!\n    form._handlePart(part);\n  }\n};\n```\n\n### Arquivo\n\n```ts\nexport interface File {\n   // O tamanho do arquivo enviado em bytes.\n   // Se o arquivo ainda estiver sendo carregado (veja o evento `'fileBegin'`),\n   // esta propriedade diz quantos bytes do arquivo já foram gravados no disco.\n  file.size: number;\n\n   // O caminho em que este arquivo está sendo gravado. Você pode modificar isso no evento `'fileBegin'`\n   // caso você esteja insatisfeito com a forma como o formidable gera um caminho temporário para seus arquivos.\n  file.filepath: string;\n\n  // O nome que este arquivo tinha de acordo com o cliente de upload.\n  file.originalFilename: string | null;\n\n  // calculado com base nas opções fornecidas.\n  file.newFilename: string | null;\n\n  // O tipo mime deste arquivo, de acordo com o cliente de upload.\n  file.mimetype: string | null;\n\n  // Um objeto Date (ou `null`) contendo a hora em que este arquivo foi gravado pela última vez.\n  // Principalmente aqui para compatibilidade com o [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).\n  file.mtime: Date | null;\n\n  file.hashAlgorithm: false | |'sha1' | 'md5' | 'sha256'\n  // Se o cálculo `options.hashAlgorithm` foi definido, você pode ler o resumo hexadecimal desta var (no final, será uma string)\n  file.hash: string | object | null;\n}\n```\n\n#### file.toJSON()\n\nEste método retorna uma representação JSON do arquivo, permitindo que você `JSON.stringify()`\no arquivo que é útil para registrar e responder a solicitações.\n\n### Eventos\n\n#### `'progress'`\nEmitido após cada bloco de entrada de dados que foi analisado. Pode ser usado para rolar sua própria barra de progresso. **Aviso** Use isso\napenas para a barra de progresso do lado do servidor. No lado do cliente, é melhor usar `XMLHttpRequest` com `xhr.upload.onprogress =`\n\n```js\nform.on('progress', (bytesReceived, bytesExpected) => {});\n```\n\n#### `'field'`\n\nEmitido sempre que um par campo/valor é recebido.\n\n```js\nform.on('field', (name, value) => {});\n```\n\n#### `'fileBegin'`\n\nEmitido sempre que um novo arquivo é detectado no fluxo de upload.\nUse este evento se desejar transmitir o arquivo para outro lugar enquanto armazena o upload no sistema de arquivos.\n\n```js\nform.on('fileBegin', (formName, file) => {\n     // acessível aqui\n     // formName o nome no formulário (<input name=\"thisname\" type=\"file\">) ou http filename para octetstream\n     // file.originalFilename http filename ou null se houver um erro de análise\n     // file.newFilename gerou hexoid ou o que options.filename retornou\n     // file.filepath nome do caminho padrão de acordo com options.uploadDir e options.filename\n     // file.filepath = CUSTOM_PATH // para alterar o caminho final\n});\n```\n\n#### `'file'`\n\nEmitido sempre que um par campo/arquivo é recebido. `file` é uma instância de\n`File`.\n\n```js\nform.on('file', (formname, file) => {\n     // o mesmo que fileBegin, exceto\n     // é muito tarde para alterar file.filepath\n     // file.hash está disponível se options.hash foi usado\n});\n```\n\n#### `'error'`\n\nEmitido quando há um erro no processamento do formulário recebido. Uma solicitação que\napresenta um erro é pausada automaticamente, você terá que chamar manualmente\n`request.resume()` se você quiser que a requisição continue disparando eventos `'data'`.\n\nPode ter `error.httpCode` e `error.code` anexados.\n\n```js\nform.on('error', (err) => {});\n```\n\n#### `'aborted'`\n\nEmitido quando a requisição foi abortada pelo usuário. Agora isso pode ser devido a um\nevento 'timeout' ou 'close' no soquete. Após este evento ser emitido, um\nO evento `error` seguirá. No futuro, haverá um 'timeout' separado\nevento (precisa de uma mudança no núcleo do nó).\n\n```js\nform.on('aborted', () => {});\n```\n\n#### `'end'`\n\nEmitido quando toda a solicitação foi recebida e todos os arquivos contidos foram\nliberados para o disco. Este é um ótimo lugar para você enviar sua resposta.\n\n```js\nform.on('end', () => {});\n```\n\n\n### Helpers\n\n#### firstValues\n\nObtém os primeiros valores dos campos, como pré 3.0.0 sem passar múltiplos em uma\nlista de exceções opcionais onde arrays de strings ainda são desejados (`<select multiple>` por exemplo)\n\n```js\nimport { firstValues } from 'formidable/src/helpers/firstValues.js';\n\n// ...\nform.parse(request, async (error, fieldsMultiple, files) => {\n    if (error) {\n        //...\n    }\n    const exceptions = ['thisshouldbeanarray'];\n    const fieldsSingle = firstValues(form, fieldsMultiple, exceptions);\n    // ...\n```\n\n#### readBooleans\n\nHtml form input type=\"checkbox\" envia apenas o valor \"on\" se marcado,\nconverta-o em booleanos para cada entrada que deve ser enviada como uma caixa de seleção, use somente após a chamada de firstValues ou similar.\n\n```js\nimport { firstValues } from 'formidable/src/helpers/firstValues.js';\nimport { readBooleans } from 'formidable/src/helpers/readBooleans.js';\n\n// ...\nform.parse(request, async (error, fieldsMultiple, files) => {\n    if (error) {\n        //...\n    }\n    const fieldsSingle = firstValues(form, fieldsMultiple);\n\n    const expectedBooleans = ['checkbox1', 'wantsNewsLetter', 'hasACar'];\n    const fieldsWithBooleans = readBooleans(fieldsSingle, expectedBooleans);\n    // ...\n```\n\n## Changelog\n\n[./CHANGELOG.md](./CHANGELOG.md)\n\n## Ports & Créditos\n\n- [multipart-parser](http://github.com/FooBarWidget/multipart-parser): um analisador C++ baseado em formidável\n- [Ryan Dahl](https://x.com/rough__sea) por seu trabalho em\n  [http-parser](http://github.com/ry/http-parser) que inspirou fortemente o `multipart_parser.js` inicial.\n\n## Contribuindo\n\nSe a documentação não estiver clara ou tiver um erro de digitação, clique no botão `Edit` da página (ícone de lápis) e sugira uma correção.\nSe você gostaria de nos ajudar a corrigir\num bug ou adicionar um novo recurso, verifique nosso [Contributing\nGuide][contribuindo-url]. Pull requests são bem-vindos!\n\nAgradecimentos vão para essas pessoas maravilhosas\n([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n  <tr>\n    <td align=\"center\"><a href=\"https://twitter.com/felixge\"><img src=\"https://avatars3.githubusercontent.com/u/15000?s=460&v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Felix Geisendörfer</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=felixge\" title=\"Code\">💻</a> <a href=\"#design-felixge\" title=\"Design\">🎨</a> <a href=\"#ideas-felixge\" title=\"Ideas, Planning, & Feedback\">🤔</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=felixge\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://tunnckoCore.com\"><img src=\"https://avatars3.githubusercontent.com/u/5038030?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Charlike Mike Reagent</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3AtunnckoCore\" title=\"Bug reports\">🐛</a> <a href=\"#infra-tunnckoCore\" title=\"Infrastructure (Hosting, Build-Tools, etc)\">🚇</a> <a href=\"#design-tunnckoCore\" title=\"Design\">🎨</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore\" title=\"Code\">💻</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore\" title=\"Documentation\">📖</a> <a href=\"#example-tunnckoCore\" title=\"Examples\">💡</a> <a href=\"#ideas-tunnckoCore\" title=\"Ideas, Planning, & Feedback\">🤔</a> <a href=\"#maintenance-tunnckoCore\" title=\"Maintenance\">🚧</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore\" title=\"Tests\">⚠️</a></td>\n    <td align=\"center\"><a href=\"https://github.com/kedarv\"><img src=\"https://avatars1.githubusercontent.com/u/1365665?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Kedar</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=kedarv\" title=\"Code\">💻</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=kedarv\" title=\"Tests\">⚠️</a> <a href=\"#question-kedarv\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Akedarv\" title=\"Bug reports\">🐛</a></td>\n    <td align=\"center\"><a href=\"https://github.com/GrosSacASac\"><img src=\"https://avatars0.githubusercontent.com/u/5721194?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Walle Cyril</b></sub></a><br /><a href=\"#question-GrosSacASac\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3AGrosSacASac\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=GrosSacASac\" title=\"Code\">💻</a> <a href=\"#financial-GrosSacASac\" title=\"Financial\">💵</a> <a href=\"#ideas-GrosSacASac\" title=\"Ideas, Planning, & Feedback\">🤔</a> <a href=\"#maintenance-GrosSacASac\" title=\"Maintenance\">🚧</a></td>\n    <td align=\"center\"><a href=\"https://github.com/xarguments\"><img src=\"https://avatars2.githubusercontent.com/u/40522463?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Xargs</b></sub></a><br /><a href=\"#question-xarguments\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Axarguments\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=xarguments\" title=\"Code\">💻</a> <a href=\"#maintenance-xarguments\" title=\"Maintenance\">🚧</a></td>\n    <td align=\"center\"><a href=\"https://github.com/Amit-A\"><img src=\"https://avatars1.githubusercontent.com/u/7987238?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Amit-A</b></sub></a><br /><a href=\"#question-Amit-A\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3AAmit-A\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=Amit-A\" title=\"Code\">💻</a></td>\n  </tr>\n  <tr>\n    <td align=\"center\"><a href=\"https://charmander.me/\"><img src=\"https://avatars1.githubusercontent.com/u/1889843?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Charmander</b></sub></a><br /><a href=\"#question-charmander\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Acharmander\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=charmander\" title=\"Code\">💻</a> <a href=\"#ideas-charmander\" title=\"Ideas, Planning, & Feedback\">🤔</a> <a href=\"#maintenance-charmander\" title=\"Maintenance\">🚧</a></td>\n    <td align=\"center\"><a href=\"https://twitter.com/dylan_piercey\"><img src=\"https://avatars2.githubusercontent.com/u/4985201?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Dylan Piercey</b></sub></a><br /><a href=\"#ideas-DylanPiercey\" title=\"Ideas, Planning, & Feedback\">🤔</a></td>\n    <td align=\"center\"><a href=\"http://ochrona.jawne.info.pl\"><img src=\"https://avatars1.githubusercontent.com/u/3618479?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Adam Dobrawy</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Aad-m\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=ad-m\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://github.com/amitrohatgi\"><img src=\"https://avatars3.githubusercontent.com/u/12177021?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>amitrohatgi</b></sub></a><br /><a href=\"#ideas-amitrohatgi\" title=\"Ideas, Planning, & Feedback\">🤔</a></td>\n    <td align=\"center\"><a href=\"https://github.com/fengxinming\"><img src=\"https://avatars2.githubusercontent.com/u/6262382?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Jesse Feng</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Afengxinming\" title=\"Bug reports\">🐛</a></td>\n    <td align=\"center\"><a href=\"https://qtmsheep.com\"><img src=\"https://avatars1.githubusercontent.com/u/7271496?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Nathanael Demacon</b></sub></a><br /><a href=\"#question-quantumsheep\" title=\"Answering Questions\">💬</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=quantumsheep\" title=\"Code\">💻</a> <a href=\"https://github.com/node-formidable/node-formidable/pulls?q=is%3Apr+reviewed-by%3Aquantumsheep\" title=\"Reviewed Pull Requests\">👀</a></td>\n  </tr>\n  <tr>\n    <td align=\"center\"><a href=\"https://github.com/MunMunMiao\"><img src=\"https://avatars1.githubusercontent.com/u/18216142?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>MunMunMiao</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3AMunMunMiao\" title=\"Bug reports\">🐛</a></td>\n    <td align=\"center\"><a href=\"https://github.com/gabipetrovay\"><img src=\"https://avatars0.githubusercontent.com/u/1170398?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Gabriel Petrovay</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/issues?q=author%3Agabipetrovay\" title=\"Bug reports\">🐛</a> <a href=\"https://github.com/node-formidable/node-formidable/commits?author=gabipetrovay\" title=\"Code\">💻</a></td>\n    <td align=\"center\"><a href=\"https://github.com/Elzair\"><img src=\"https://avatars0.githubusercontent.com/u/2352818?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Philip Woods</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=Elzair\" title=\"Code\">💻</a> <a href=\"#ideas-Elzair\" title=\"Ideas, Planning, & Feedback\">🤔</a></td>\n    <td align=\"center\"><a href=\"https://github.com/dmolim\"><img src=\"https://avatars2.githubusercontent.com/u/7090374?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Dmitry Ivonin</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=dmolim\" title=\"Documentation\">📖</a></td>\n    <td align=\"center\"><a href=\"https://audiobox.fm\"><img src=\"https://avatars1.githubusercontent.com/u/12844?v=4\" width=\"100px;\" alt=\"\"/><br /><sub><b>Claudio Poli</b></sub></a><br /><a href=\"https://github.com/node-formidable/node-formidable/commits?author=masterkain\" title=\"Code\">💻</a></td>\n  </tr>\n</table>\n\n<!-- markdownlint-enable -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nDe uma [postagem do blog Felix](https://felixge.de/2013/03/11/the-pull-request-hack/):\n\n- [Sven Lito](https://github.com/svnlto) por corrigir bugs e mesclar patches\n- [egirshov](https://github.com/egirshov) por contribuir com muitas melhorias para o analisador multipartes formidável de nós\n- [Andrew Kelley](https://github.com/superjoe30) por também ajudar a corrigir bugs e fazer melhorias\n- [Mike Frey](https://github.com/mikefrey) por contribuir com suporte JSON\n\n## Licença\n\nFormidable é licenciado sob a [MIT License][license-url].\n\n<!-- badges -->\n<!-- prettier-ignore-start -->\n\n[codestyle-url]: https://github.com/airbnb/javascript\n[codestyle-img]: https://badgen.net/badge/code%20style/airbnb%20%2B%20prettier/ff5a5f?icon=airbnb&cache=300\n[codecov-url]: https://codecov.io/gh/node-formidable/formidable\n[codecov-img]: https://badgen.net/codecov/c/github/node-formidable/formidable/master?icon=codecov\n[npmv-canary-img]: https://badgen.net/npm/v/formidable/canary?icon=npm\n[npmv-dev-img]: https://badgen.net/npm/v/formidable/dev?icon=npm\n[npmv-img]: https://badgen.net/npm/v/formidable?icon=npm\n[npmv-url]: https://npmjs.com/package/formidable\n[license-img]: https://badgen.net/npm/license/formidable\n[license-url]: https://github.com/node-formidable/formidable/blob/master/LICENSE\n[chat-img]: https://badgen.net/badge/chat/on%20gitter/46BC99?icon=gitter\n[chat-url]: https://gitter.im/node-formidable/Lobby\n[libera-manifesto-url]: https://liberamanifesto.com\n[libera-manifesto-img]: https://badgen.net/badge/libera/manifesto/grey\n[renovateapp-url]: https://renovatebot.com\n[renovateapp-img]: https://badgen.net/badge/renovate/enabled/green?cache=300\n[prs-welcome-img]: https://badgen.net/badge/PRs/welcome/green?cache=300\n[prs-welcome-url]: http://makeapullrequest.com\n[twitter-url]: https://twitter.com/3a1fcBx0\n[twitter-img]: https://badgen.net/twitter/follow/3a1fcBx0?icon=twitter&color=1da1f2&cache=300\n\n[npm-weekly-img]: https://badgen.net/npm/dw/formidable?icon=npm&cache=300\n[npm-monthly-img]: https://badgen.net/npm/dm/formidable?icon=npm&cache=300\n[npm-yearly-img]: https://badgen.net/npm/dy/formidable?icon=npm&cache=300\n[npm-alltime-img]: https://badgen.net/npm/dt/formidable?icon=npm&cache=300&label=total%20downloads\n\n[nodejs-img]: https://badgen.net/badge/node/>=%2010.13/green?cache=300\n\n[ccommits-url]: https://conventionalcommits.org/\n[ccommits-img]: https://badgen.net/badge/conventional%20commits/v1.0.0/green?cache=300\n\n[contributing-url]: https://github.com/node-formidable/.github/blob/master/CONTRIBUTING.md\n[code_of_conduct-url]: https://github.com/node-formidable/.github/blob/master/CODE_OF_CONDUCT.md\n\n[open-issue-url]: https://github.com/node-formidable/formidable/issues/new\n\n[tidelift-url]: https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise\n[tidelift-img]: https://badgen.net/badge/tidelift/subscription/4B5168?labelColor=F6914D\n\n[kofi-url]: https://ko-fi.com/tunnckoCore/commissions\n[kofi-img]: https://badgen.net/badge/ko-fi/support/29abe0c2?cache=300&icon=https://rawcdn.githack.com/tunnckoCore/badgen-icons/f8264c6414e0bec449dd86f2241d50a9b89a1203/icons/kofi.svg\n\n[linux-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master?cache=30&label=linux%20build&icon=github\n[macos-build-img]: https://badgen.net/github/checks/node-formidable/formidable/master?cache=30&label=macos%20build&icon=github\n[build-url]: https://github.com/node-formidable/formidable/actions\n<!-- prettier-ignore-end -->\n"
  },
  {
    "path": "VERSION_NOTES.md",
    "content": "\n# Important Notes for v1, v2, and v3\n\nFor more info, check the [CHANGELOG](https://github.com/node-formidable/formidable/blob/master/CHANGELOG.md) on the master branch.\n\n## v1 is deprecated\n\nAll `v1` versions are deprecated in NPM for over 2 years. You can find it at `formidable@v1` on NPM, and on [v1 branch][v1branch] on GitHub.  \nWe highly recommend to use `v2` or `v3`. Both are already in use by many, especially `v2` which was on `formidable@canary` for 2 years.\n\n- **Status: Not Maintained!**\n- We won't provide support or accept reports on that version.\n- **No Backporting:** bugfixes, security fixes, or new features WILL NOT happen!\n- Please move to at least **v2**! \n- Try with installing `formidable@v2` and if still have the problem - report!\n\n## v2 is going to be deprecated\n\nThe `v2` is available as `formidable@v2`.\nThe source code is available **only** on [v2 branch][v2branch].\nIf you want to use v2, it's recommended to lock and use the v2 dist-tag `formidable@v2-latest`. \n\n**Main Differences from v1:**\n\n- Better organization and modernized code, requiring newer Node.js versions (>= v10).\n- A lot of bugfixes, closed issues, merged or closed PRs.\n- Better docs, new features (plugins, parsers, options) and optimizations.\n\n## v3 - ESModules, Monorepo structure\n\nWe recommend to use `formidable@latest` to install, as it uses more modern Node.js Streams, has support for more stuff.\nYou can see more info and track some ideas on [issue#635](https://github.com/node-formidable/formidable/issues/635).\n\n- The source code can be found on the [master branch][v3branch] on GitHub.\n- It is published as `formidable@latest`\n- Dropping older Node.js versions, requiring higher than v12-v14.\n- Dropping v1 compatibility.\n- Rewritten to ESModules, more optimizations.\n- Moving to monorepo structure, more plugins & helper utils.\n\n[v1branch]: https://github.com/node-formidable/formidable/tree/v1-legacy\n[v2branch]: https://github.com/node-formidable/formidable/tree/v2-latest\n[v3branch]: https://github.com/node-formidable/formidable/tree/master\n"
  },
  {
    "path": "benchmark/2022-11-30-i5-9600k.txt",
    "content": "npm run bench\n\n> formidable@3.2.5 bench\n> node benchmark\n\n4132.23 mb/sec\nPS C:\\files\\formidable> node -v      \nv18.0.0\n\nnpm run bench\n\n> formidable@3.2.5 bench\n> node benchmark\n\n3952.57 mb/sec\n\nPS C:\\files\\formidable> node -v      \nv19.2.0\n\nC:\\files\\formidable> bombardier --body-file=\"./README.md\" --method=POST \n--duration=10s --connections=100 http://localhost:3000/api/upload \nBombarding http://localhost:3000/api/upload for 10s using 100 connection(s)[====================================================================] 10s \nDone!\nStatistics        Avg      Stdev        Max\n  Reqs/sec      2824.09    1512.74    6881.85\n  Latency       35.51ms    37.38ms      0.98s\n  HTTP codes:\n    1xx - 0, 2xx - 28163, 3xx - 0, 4xx - 0, 5xx - 0\n    others - 0\n  Throughput:   102.08MB/s\n"
  },
  {
    "path": "benchmark/e2e.txt",
    "content": "node ./benchmark/server.js\nbombardier --body-file=\"./README.md\" --method=POST --duration=10s --connections=100 http://localhost:3000/api/upload \n\n\n\n\n"
  },
  {
    "path": "benchmark/index.js",
    "content": "import assert from \"node:assert\";\nimport MultipartParser from '../src/parsers/Multipart.js';\n\n\nconst parser = new MultipartParser();\nconst customBoundary = '-----------------------------168072824752491622650073';\nconst mb = 1000; // 1GB\nconst buf = createMultipartBuffer(customBoundary, mb * 1024 * 1024);\n\nconst calls = {\n  partBegin: 0,\n  headerField: 0,\n  headerValue: 0,\n  headerEnd: 0,\n  headersEnd: 0,\n  partData: 0,\n  partEnd: 0,\n  end: 0,\n};\n\nconst start = performance.now();\n\nparser.initWithBoundary(customBoundary);\nparser.on('data', ({ name }) => {\n  calls[name] += 1;\n});\n\nparser.write(buf);\n\nconst duration = performance.now() - start;\nconst mbPerSec = (mb / (duration / 1000)).toFixed(2);\n\nconsole.log(`${mbPerSec} mb/sec`);\n\nfunction createMultipartBuffer(boundary, size) {\n  const head =\n    `--${boundary}\\r\\n` +\n    `content-disposition: form-data; name=\"field1\"\\r\\n` +\n    `\\r\\n`;\n  const tail = `\\r\\n--${boundary}--\\r\\n`;\n  const buffer = Buffer.alloc(size);\n\n  buffer.write(head, 0, 'ascii');\n  buffer.write(tail, buffer.length - tail.length, 'ascii');\n  return buffer;\n}\n\nprocess.on('exit', () => {\n  assert.deepStrictEqual(calls, {\n    partBegin: 1,\n    headerField: 1,\n    headerValue: 1,\n    headerEnd: 1,\n    headersEnd: 1,\n    partData: 1,\n    partEnd: 1,\n    end: 1,\n  });\n  // Object.keys(events).forEach((k) => {\n  //   console.log(k, events[k]);\n  //   // assert.equal(callbacks[k], 0, `${k} count off by ${callbacks[k]}`);\n  // });\n});\n"
  },
  {
    "path": "benchmark/server.js",
    "content": "// inital copy of with-http.js\n// made a copy so that examples can be changed without impacting tests\nimport http from 'node:http';\nimport slugify from '@sindresorhus/slugify';\nimport formidable, {errors as formidableErrors} from '../src/index.js';\n\nconst server = http.createServer((req, res) => {\n  // handle common internet errors\n  // to avoid server crash\n  req.on('error', console.error);\n  res.on('error', console.error);\n\n\n  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {\n    const form = formidable({\n      uploadDir: `benchmark/testuploads`,\n      keepExtensions: true,\n    });\n\n    form.parse(req, (err, fields, files) => {\n      if (err) {\n        console.error(err);\n        res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });\n        res.end(String(err));\n        return;\n      }\n      res.writeHead(200, { 'Content-Type': 'application/json' });\n      res.end(JSON.stringify({ fields, files }, null, 2));\n    });\n\n    return;\n  }\n\n  // else not used in tests\n\n});\n\nserver.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/express-middleware.js",
    "content": "import express from 'express';\nimport formidable from '../src/index.js';\n\nconst app = express();\n\n// middlewares that populates req.fields and req.body\nconst formMiddleWare = (req, res, next) => {\n    const form = formidable({});\n\n    form.parse(req, (err, fields, files) => {\n      if (err) {\n        next(err);\n        return;\n      }\n      req.fields = fields;\n      req.files = files;\n      next();\n    });\n};\n\napp.get('/', (req, res) => {\n  res.send(`\n    <h2>With <code>\"express\"</code> npm package</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>File: <input type=\"file\" name=\"someExpressFiles\" multiple=\"multiple\"></div>\n      <input type=\"submit\" value=\"Upload\">\n    </form>\n  `);\n});\n\n// use middleware\napp.post('/api/upload', formMiddleWare, (req, res, next) => {\n    res.json({ \n        fields: req.fields,\n        files: req.files,\n    });\n});\n\napp.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/forceBuffer.js",
    "content": "// warning: forcing file into a Buffer elminates the benefits of using streams and may cause memory overflow\nimport http from 'node:http';\nimport { Buffer } from 'node:buffer'\nimport { Writable } from 'node:stream';\nimport formidable from '../src/index.js';\n\n\nconst server = http.createServer((req, res) => {\n  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {\n    // parse a file upload\n    const endBuffers = {};\n    const form = formidable({\n      fileWriteStreamHandler: (file) => {\n        const chunks = [];\n        \n        const writable = new Writable({\n          write (chunk, enc, next) {\n            chunks.push(chunk);            \n            next();\n          },\n          destroy() {\n            endBuffers = {};\n          },\n          final(cb) {\n            const buffer = Buffer.concat(chunks);\n            // if filename option is not provided file.newFilename will be a random string\n            endBuffers[file.newFilename] = buffer;\n            cb();\n          },\n        })\n        return writable;\n      },\n    });\n\n    form.parse(req, (err, fields, files) => {\n      // available here endBuffers\n      if (err) {\n        console.error(err);\n        res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });\n        res.end(String(err));\n        return;\n      }\n      res.writeHead(200, { 'Content-Type': 'application/json' });\n      res.end(JSON.stringify({ fields, files }, null, 2));\n\n      Object.entries(endBuffers).map(([key, value]) => {\n        console.log(key);\n        console.log(value.toString(\"utf8\"));\n      });\n    });\n\n    return;\n  }\n\n  // show a file upload form\n  res.writeHead(200, { 'Content-Type': 'text/html' });\n  res.end(`\n    <h2>With Node.js <code>\"http\"</code> module</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\"></div>\n      <div>File: <input type=\"file\" name=\"myfile\"></div>\n      <button>Upload</button>\n    </form>\n  `);\n});\n\nserver.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/json.js",
    "content": "import http from 'node:http';\nimport util from 'node:util';\nimport formidable from '../src/index.js';\n\n\nconst PORT = 3000;\nconst server = http.createServer((req, res) => {\n  if (req.method !== 'POST') {\n    res.writeHead(200, { 'Content-Type': 'text/plain' });\n    res.end(`Please POST a JSON payload to http://localhost:${PORT}/`);\n    return;\n  }\n\n  const form = formidable();\n  const fields = {};\n\n  form\n    .on('error', (err) => {\n      console.error(err);\n      res.writeHead(500, { 'Content-Type': 'text/plain' });\n      res.end(`error:\\n\\n${util.inspect(err)}`);\n    })\n    .on('field', (field, value) => {\n      console.log(field, value);\n      fields[field] = value;\n    })\n    .on('end', () => {\n      console.log('-> post done from \"end\" event');\n      res.writeHead(200, { 'Content-Type': 'text/plain' });\n      res.end(`received fields:\\n\\n${util.inspect(fields)}`);\n    });\n\n  form.parse(req);\n});\n\nserver.listen(PORT, () => {\n  const chosenPort = server.address().port;\n  console.log(`Listening on http://localhost:${chosenPort}/`);\n\n  const body = JSON.stringify({\n    numbers: [1, 2, 3, 4, 5],\n    nested: { key: 'some val' },\n  });\n\n  const request = http.request(\n    {\n      host: 'localhost',\n      path: '/',\n      port: chosenPort,\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'content-length': body.length,\n      },\n    },\n    (response) => {\n      console.log('\\nServer responded with:');\n      console.log('Status:', response.statusCode);\n      response.pipe(process.stdout);\n      response.on('end', () => {\n        console.log('\\n');\n        process.exit();\n      });\n      // const data = '';\n      // response.on('data', function(chunk) {\n      //   data += chunk.toString('utf8');\n      // });\n      // response.on('end', function() {\n      //   console.log('Response Data:');\n      //   console.log(data);\n      //   process.exit();\n      // });\n    },\n  );\n  request.end(body);\n});\n"
  },
  {
    "path": "examples/log-file-content-to-console.js",
    "content": "import http from 'node:http';\nimport { Writable } from 'node:stream';\nimport formidable from '../src/index.js';\n\n\nconst server = http.createServer((req, res) => {\n  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {\n    // parse a file upload\n    const form = formidable({\n      fileWriteStreamHandler: (/* file */) => {\n        const writable = Writable();\n        // eslint-disable-next-line no-underscore-dangle\n        writable._write = (chunk, enc, next) => {\n          console.log(chunk.toString());\n          next();\n        };\n        return writable;\n      },\n    });\n\n    form.parse(req, () => {\n      res.writeHead(200);\n      res.end();\n    });\n\n    return;\n  }\n\n  // show a file upload form\n  res.writeHead(200, { 'Content-Type': 'text/html' });\n  res.end(`\n    <h2>With Node.js <code>\"http\"</code> module</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>File: <input type=\"file\" name=\"file\" /></div>\n      <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `);\n});\n\nserver.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/multipart-parser.js",
    "content": "import { Blob } from 'node:buffer';\nimport { Readable } from 'node:stream';\nimport { FormData, formDataToBlob } from 'formdata-polyfill/esm.min.js'\nimport { MultipartParser } from '../src/index.js';\n\nconst blob1 = new Blob(\n  ['Content of a.txt.'],\n  { type: 'text/plain' }\n);\n\nconst blob2 = new Blob(\n  ['<!DOCTYPE html><title>Content of a.html.</title>'],\n  { type: 'text/html' }\n);\n\nconst fd = new FormData();\nfd.set('text', 'some text ...');\nfd.set('z', 'text inside z');\nfd.set('file1', blob1, 'a.txt');\nfd.set('file2', blob2, 'a.html');\n\nconst multipartParser = new MultipartParser();\nmultipartParser.on('data', ({ name, buffer, start, end }) => {\n  console.log(`${name}:`);\n  if (buffer && start && end) {\n    console.log(String(buffer.slice(start, end)));\n  }\n  console.log();\n});\nmultipartParser.on('error', console.error);\n\nconst blob = formDataToBlob(fd);\nconst boundary = blob.type.split('boundary=')[1];\n\nmultipartParser.initWithBoundary(boundary);\n\nReadable.from(blob.stream()).pipe(multipartParser);\n"
  },
  {
    "path": "examples/multiples.js",
    "content": "import http from 'node:http';\nimport os from 'node:os';\nimport formidable from '../src/index.js';\n\n\nconst server = http.createServer((req, res) => {\n  if (req.url === '/') {\n    res.writeHead(200, { 'Content-Type': 'text/html' });\n    res.end(`\n      <form action=\"/upload\" enctype=\"multipart/form-data\" method=\"post\">\n        <label>simple<input type=\"text\" name=\"text_single\" autofocus /></label><br />\n\n        <label>array text 0<input type=\"text\" name=\"text_multiple[]\" /></label><br />\n        <label>array text 1<input type=\"text\" name=\"text_multiple[]\" /></label><br />\n\n        <label>file simple<input type=\"file\" name=\"file_single\" /></label><br />\n\n        <label>file attribute multiple<input type=\"file\" name=\"file_multiple\" multiple /></label><br />\n\n        <label>file html array0<input type=\"file\" name=\"filearray[]\" /></label><br />\n        <label>file html array1<input type=\"file\" name=\"filearray[]\" /></label><br />\n\n        <label>file html array and multiple0<input type=\"file\" name=\"filearray_with_multiple[]\" multiple /></label><br />\n        <label>file html array and multiple1<input type=\"file\" name=\"filearray_with_multiple[]\" multiple /></label><br />\n        <br />\n        <button>Upload</button>\n      </form>\n    `);\n  } else if (req.url === '/upload') {\n    const form = formidable({ uploadDir: os.tmpdir() });\n\n    form.parse(req, (err, fields, files) => {\n      res.writeHead(200, { 'Content-Type': 'application/json' });\n      res.end(JSON.stringify({ err, fields, files }, null, 2));\n    });\n  } else {\n    res.writeHead(404, { 'Content-Type': 'text/plain' });\n    res.end('404');\n  }\n});\n\nserver.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/store-files-on-s3.js",
    "content": "// To test this example you have to install aws-sdk nodejs package and create a bucket named \"demo-bucket\"\n\nimport http from 'node:http';\nimport { PassThrough } from 'node:stream';\nimport AWS from 'aws-sdk';\nimport formidable from '../src/index.js';\n\n\nconst s3Client = new AWS.S3({\n  credentials: {\n    accessKeyId: process.env.AWS_ACCESS_KEY_ID,\n    secretAccessKey: process.env.AWS_SECRET_KEY,\n  },\n});\n\nconst uploadStream = (file) => {\n  const pass = new PassThrough();\n  s3Client.upload(\n    {\n      Bucket: 'demo-bucket',\n      Key: file.newFilename,\n      Body: pass,\n    },\n    (err, data) => {\n      console.log(err, data);\n    },\n  );\n\n  return pass;\n};\n\nconst server = http.createServer((req, res) => {\n  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {\n    // parse a file upload\n    const form = formidable({\n      fileWriteStreamHandler: uploadStream,\n    });\n\n    form.parse(req, () => {\n      res.writeHead(200);\n      res.end();\n    });\n\n    return;\n  }\n\n  // show a file upload form\n  res.writeHead(200, { 'Content-Type': 'text/html' });\n  res.end(`\n    <h2>With Node.js <code>\"http\"</code> module</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>File: <input type=\"file\" name=\"file\"/></div>\n      <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `);\n});\n\nserver.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/upload-multiple-files.js",
    "content": "import http from 'node:http';\nimport util from 'node:util';\nimport os from 'node:os';\nimport formidable from '../src/index.js';\n\n\nconst server = http.createServer((req, res) => {\n  if (req.url === '/') {\n    res.writeHead(200, { 'Content-Type': 'text/html' });\n    res.end(`\n      <form action=\"/upload\" enctype=\"multipart/form-data\" method=\"post\">\n        <input type=\"text\" name=\"title\"><br>\n        <input type=\"file\" name=\"someCoolFiles\" multiple><br>\n        <button>Upload</button>\n      </form>\n    `);\n  } else if (req.url === '/upload') {\n    const form = formidable({ uploadDir: os.tmpdir() });\n    const files = [];\n    const fields = [];\n\n    form\n      .on('field', (fieldName, value) => {\n        console.log(fieldName, value);\n        fields.push({ fieldName, value });\n      })\n      .on('file', (fieldName, file) => {\n        console.log(fieldName, file);\n        files.push({ fieldName, file });\n      })\n      .on('end', () => {\n        console.log('-> upload done');\n        res.writeHead(200, { 'Content-Type': 'text/plain' });\n        res.write(`received fields:\\n\\n${util.inspect(fields)}`);\n        res.write('\\n\\n');\n        res.end(`received files:\\n\\n${util.inspect(files)}`);\n      });\n\n    form.parse(req);\n  } else {\n    res.writeHead(404, { 'Content-Type': 'text/plain' });\n    res.end('404');\n  }\n});\n\nserver.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/urlencoded-no-enctype.js",
    "content": "import http from 'node:http';\nimport util from 'node:util';\nimport formidable from '../src/index.js';\n\n\nconst server = http.createServer((req, res) => {\n  if (req.url === '/') {\n    res.writeHead(200, { 'Content-Type': 'text/html' });\n    res.end(`\n      <form action=\"/post\" method=\"post\">\n        Title: <input type=\"text\" name=\"title\" /><br />\n        Data: <input type=\"text\" name=\"data\" /><br />\n        <button>Submit</button>\n      </form>\n    `);\n  } else if (req.url === '/post') {\n    const form = formidable();\n    const fields = [];\n\n    form\n      .on('error', (err) => {\n        console.log('err!', err);\n        res.writeHead(200, { 'Content-Type': 'text/plain' });\n        res.end(`error:\\n\\n${util.inspect(err)}`);\n      })\n      .on('field', (fieldName, fieldValue) => {\n        console.log('fieldName:', fieldName);\n        console.log('fieldValue:', fieldValue);\n\n        fields.push({ fieldName, fieldValue });\n      })\n      .on('end', () => {\n        console.log('-> post done from \"end\" event');\n        res.writeHead(200, { 'Content-Type': 'text/plain' });\n        res.end(`received fields:\\n\\n${util.inspect(fields)}`);\n      });\n\n    form.parse(req, () => {\n      console.log('-> post done from callback');\n      // res.writeHead(200, { 'Content-Type': 'text/plain' });\n      // res.end(`received fields:\\n\\n${util.inspect(fields)}`);\n    });\n  } else {\n    res.writeHead(404, { 'Content-Type': 'text/plain' });\n    res.end('404');\n  }\n});\n\nserver.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/with-express.js",
    "content": "import express from 'express';\nimport formidable from '../src/index.js';\n\nconst app = express();\n\napp.get('/', (req, res) => {\n  res.send(`\n    <h2>With <code>\"express\"</code> npm package</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>File: <input type=\"file\" name=\"someExpressFiles\" multiple=\"multiple\" /></div>\n      <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `);\n});\n\napp.post('/api/upload', (req, res, next) => {\n  const form = formidable({ });\n\n  form.parse(req, (err, fields, files) => {\n    if (err) {\n      next(err);\n      return;\n    }\n    res.json({ fields, files });\n  });\n});\n\napp.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/with-http.js",
    "content": "import http from 'node:http';\nimport slugify from '@sindresorhus/slugify';\nimport formidable, {errors as formidableErrors} from '../src/index.js';\n\nconst server = http.createServer((req, res) => {\n  // handle common internet errors\n  // to avoid server crash\n  req.on('error', console.error);\n  res.on('error', console.error);\n\n\n  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {\n    // parse a file upload\n    const form = formidable({\n      defaultInvalidName: 'invalid',\n      uploadDir: `uploads`,\n      keepExtensions: true,\n      createDirsFromUploads: true,\n      allowEmptyFiles: true,\n      minFileSize: 0,\n      filename(name, ext, part, form) {\n        /* name basename of the http originalFilename\n          ext with the dot \".txt\" only if keepExtensions is true\n         */\n        // originalFilename will have slashes with relative path if a\n        // directory was uploaded\n        const {originalFilename} = part;\n        if (!originalFilename) {\n          return 'invalid';\n        }\n        \n        // return 'yo.txt'; // or completly different name\n        // return 'z/yo.txt'; // subdirectory\n        return originalFilename.split(\"/\").map((subdir) => {\n          return slugify(subdir, {separator: ''});  // slugify to avoid invalid filenames\n        }).join(\"/\").substr(0, 100); // substr to define a maximum \n      },\n      filter: function ({name, originalFilename, mimetype}) {\n        return Boolean(originalFilename);\n        // keep only images\n        // return mimetype?.includes(\"image\");\n      }\n\n      // maxTotalFileSize: 4000,\n      // maxFileSize: 1000,\n\n    });\n\n    form.parse(req, (err, fields, files) => {\n      if (err) {\n        console.error(err);\n        res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });\n        res.end(String(err));\n        return;\n      }\n      res.writeHead(200, { 'Content-Type': 'application/json' });\n      res.end(JSON.stringify({ fields, files }, null, 2));\n    });\n\n    return;\n  }\n\n  // else show a file upload form\n  res.writeHead(200, { 'Content-Type': 'text/html' });\n  res.end(`\n    <h2>With Node.js <code>\"http\"</code> module</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>File: <input type=\"file\" name=\"multipleFiles\" multiple /></div>\n      <div>Folders: <input type=\"file\" name=\"folders\" webkitdirectory directory multiple /></div>\n      <input type=\"submit\" value=\"Upload\" />\n    </form>\n\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n      <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n      <div>Text field with same name: <input type=\"text\" name=\"title\" /></div>\n      <div>Other field <input type=\"text\" name=\"other\" /></div>\n      <input type=\"submit\" value=\"submit simple\" />\n    </form>\n  `);\n});\n\nserver.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "examples/with-koa2.js",
    "content": "import Koa from 'koa';\nimport formidable from '../src/index.js';\n\n\nconst app = new Koa();\n\napp.on('error', (err) => {\n  console.error('server error', err);\n});\n\napp.use(async (ctx, next) => {\n  if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') {\n    let i = 0;\n    const form = formidable({\n      keepExtensions: true,\n      // must return absolute path\n      filename: (part, $self) => {\n        i += 1;\n        return `${$self.uploadDir}/sasasa${i}`;\n      },\n    });\n\n    // not very elegant, but that's for now if you don't want touse `koa-better-body`\n    // or other middlewares.\n    await new Promise((resolve, reject) => {\n      form.parse(ctx.req, (err, fields, files) => {\n        if (err) {\n          reject(err);\n          return;\n        }\n\n        ctx.set('Content-Type', 'application/json');\n        ctx.status = 200;\n        ctx.state = { fields, files };\n        ctx.body = JSON.stringify(ctx.state, null, 2);\n        resolve();\n      });\n    });\n    await next();\n    return;\n  }\n\n  // show a file upload form\n  ctx.set('Content-Type', 'text/html');\n  ctx.status = 200;\n  ctx.body = `\n    <h2>With <code>\"koa\"</code> npm package</h2>\n    <form action=\"/api/upload\" enctype=\"multipart/form-data\" method=\"post\">\n    <div>Text field title: <input type=\"text\" name=\"title\" /></div>\n    <div>File: <input type=\"file\" name=\"koaFiles\" multiple=\"multiple\" /></div>\n    <input type=\"submit\" value=\"Upload\" />\n    </form>\n  `;\n});\n\napp.use((ctx) => {\n  console.log('The next middleware is called');\n  console.log('Results:', ctx.state);\n});\n\napp.listen(3000, () => {\n  console.log('Server listening on http://localhost:3000 ...');\n});\n"
  },
  {
    "path": "nyc.config.js",
    "content": "'use strict';\n\nmodule.exports = {\n  statements: 70,\n  branches: 70,\n  functions: 70,\n  lines: 70,\n\n  'check-coverage': true,\n  exclude: ['test'],\n  include: ['src'],\n  reporter: ['text', 'text-summary', 'lcov', 'clover'],\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"formidable\",\n  \"version\": \"3.5.4\",\n  \"license\": \"MIT\",\n  \"description\": \"A node.js module for parsing form data, especially file uploads.\",\n  \"homepage\": \"https://github.com/node-formidable/formidable\",\n  \"funding\": \"https://ko-fi.com/tunnckoCore/commissions\",\n  \"repository\": \"node-formidable/formidable\",\n  \"type\": \"module\",\n  \"main\": \"./dist/index.cjs\",\n  \"exports\": {\n    \".\": {\n      \"import\": {\n        \"default\": \"./src/index.js\"\n      },\n      \"require\": {\n        \"default\": \"./dist/index.cjs\"\n      },\n      \"default\": \"./dist/index.cjs\"\n    },\n    \"./src/helpers/*.js\": {\n      \"import\": {\n        \"default\": \"./src/helpers/*.js\"\n      },\n      \"require\": {\n        \"default\": \"./dist/helpers/*.cjs\"\n      }\n    },\n    \"./src/parsers/*.js\": {\n      \"import\": {\n        \"default\": \"./src/parsers/*.js\"\n      },\n      \"require\": {\n        \"default\": \"./dist/index.cjs\"\n      }\n    }\n  },\n  \"files\": [\n    \"src\",\n    \"./dist\",\n    \"./CHANGELOG\",\n    \"./README.md\",\n    \"./README_pt_BR.md\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\",\n    \"tag\": \"latest\"\n  },\n  \"scripts\": {\n    \"build-package\": \"rollup --config ./tool/rollup.config.js\",\n    \"prepublishOnly\": \"pnpm run build-package\",\n    \"bench\": \"node benchmark\",\n    \"bench2prep\": \"node benchmark/server.js\",\n    \"bench2\": \"bombardier --body-file=\\\"./README.md\\\" --method=POST --duration=10s --connections=100 http://localhost:3000/api/upload\",\n    \"fmt\": \"pnpm run fmt:prepare '**/*'\",\n    \"fmt:prepare\": \"prettier --write\",\n    \"lint\": \"pnpm run lint:prepare .\",\n    \"lint:prepare\": \"eslint --cache --fix --quiet --format codeframe\",\n    \"fresh\": \"rm -rf ./node_modules\",\n\n    \"test-specific\": \"node --disable-warning=ExperimentalWarning --experimental-vm-modules ./node_modules/jest/bin/jest.js --testPathPattern=test/standalone/keep-alive-error.test.js\",\n    \"test-jest\": \"node --disable-warning=ExperimentalWarning --experimental-vm-modules ./node_modules/jest/bin/jest.js --testPathPattern=test/ --coverage\",\n    \"test-node\": \"node --disable-warning=ExperimentalWarning --test ./test-node/**/*.test.js\",\n\n    \"test-jest:ci\": \"node --experimental-vm-modules ./node_modules/jest/bin/jest.js --testPathPattern=test/ --coverage\",\n\n    \"test:local\": \"pnpm run test-node && pnpm run test-jest\",\n\n    \"audit\": \"pnpm audit --prod --fix\",\n    \"pretest\": \"rm -rf ./test/tmp && mkdir ./test/tmp\",\n    \"test\": \"pnpm run audit && node --test ./test-node/**/*.test.js && pnpm run test-jest:ci\"\n  },\n  \"dependencies\": {\n    \"@paralleldrive/cuid2\": \"2.2.2\",\n    \"dezalgo\": \"^1.0.4\",\n    \"once\": \"^1.4.0\"\n  },\n\"packageManager\": \"pnpm@10.8.1\",\n  \"devDependencies\": {\n    \"@rollup/plugin-commonjs\": \"^25.0.2\",\n    \"@rollup/plugin-node-resolve\": \"^15.1.0\",\n    \"@sindresorhus/slugify\": \"^2.1.0\",\n    \"@tunnckocore/prettier-config\": \"1.3.8\",\n    \"eslint\": \"6.8.0\",\n    \"eslint-config-airbnb-base\": \"14.1.0\",\n    \"eslint-config-prettier\": \"6.11.0\",\n    \"eslint-plugin-import\": \"2.20.2\",\n    \"eslint-plugin-prettier\": \"3.1.3\",\n    \"express\": \"^4.21.1\",\n    \"formdata-polyfill\": \"^4.0.10\",\n    \"jest\": \"27.2.4\",\n    \"koa\": \"2.16.1\",\n    \"nyc\": \"15.1.0\",\n    \"prettier\": \"2.0.5\",\n    \"prettier-plugin-pkgjson\": \"0.2.8\",\n    \"rollup\": \"^3.25.3\",\n    \"supertest\": \"6.1.6\"\n  },\n  \"engines\": {\n    \"node\": \">=14.0.0\"\n  },\n  \"jest\": {\n    \"verbose\": true\n  },\n  \"keywords\": [\n    \"multipart\",\n    \"form\",\n    \"data\",\n    \"querystring\",\n    \"www\",\n    \"json\",\n    \"ulpoad\",\n    \"file\"\n  ]\n}\n"
  },
  {
    "path": "pnpm-lock.yaml",
    "content": "lockfileVersion: '9.0'\n\nsettings:\n  autoInstallPeers: true\n  excludeLinksFromLockfile: false\n\nimporters:\n\n  .:\n    dependencies:\n      '@paralleldrive/cuid2':\n        specifier: 2.2.2\n        version: 2.2.2\n      dezalgo:\n        specifier: ^1.0.4\n        version: 1.0.4\n      once:\n        specifier: ^1.4.0\n        version: 1.4.0\n    devDependencies:\n      '@rollup/plugin-commonjs':\n        specifier: ^25.0.2\n        version: 25.0.8(rollup@3.29.5)\n      '@rollup/plugin-node-resolve':\n        specifier: ^15.1.0\n        version: 15.3.1(rollup@3.29.5)\n      '@sindresorhus/slugify':\n        specifier: ^2.1.0\n        version: 2.2.1\n      '@tunnckocore/prettier-config':\n        specifier: 1.3.8\n        version: 1.3.8(prettier-plugin-pkgjson@0.2.8(prettier@2.0.5))(prettier@2.0.5)\n      eslint:\n        specifier: 6.8.0\n        version: 6.8.0\n      eslint-config-airbnb-base:\n        specifier: 14.1.0\n        version: 14.1.0(eslint-plugin-import@2.20.2(eslint@6.8.0))(eslint@6.8.0)\n      eslint-config-prettier:\n        specifier: 6.11.0\n        version: 6.11.0(eslint@6.8.0)\n      eslint-plugin-import:\n        specifier: 2.20.2\n        version: 2.20.2(eslint@6.8.0)\n      eslint-plugin-prettier:\n        specifier: 3.1.3\n        version: 3.1.3(eslint@6.8.0)(prettier@2.0.5)\n      express:\n        specifier: ^4.21.1\n        version: 4.21.2\n      formdata-polyfill:\n        specifier: ^4.0.10\n        version: 4.0.10\n      jest:\n        specifier: 27.2.4\n        version: 27.2.4\n      koa:\n        specifier: 2.16.1\n        version: 2.16.1\n      nyc:\n        specifier: 15.1.0\n        version: 15.1.0\n      prettier:\n        specifier: 2.0.5\n        version: 2.0.5\n      prettier-plugin-pkgjson:\n        specifier: 0.2.8\n        version: 0.2.8(prettier@2.0.5)\n      rollup:\n        specifier: ^3.25.3\n        version: 3.29.5\n      supertest:\n        specifier: 6.1.6\n        version: 6.1.6\n\npackages:\n\n  '@ampproject/remapping@2.3.0':\n    resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}\n    engines: {node: '>=6.0.0'}\n\n  '@babel/code-frame@7.26.2':\n    resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/compat-data@7.26.8':\n    resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/core@7.26.10':\n    resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/generator@7.27.0':\n    resolution: {integrity: sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/helper-compilation-targets@7.27.0':\n    resolution: {integrity: sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/helper-module-imports@7.25.9':\n    resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/helper-module-transforms@7.26.0':\n    resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==}\n    engines: {node: '>=6.9.0'}\n    peerDependencies:\n      '@babel/core': ^7.0.0\n\n  '@babel/helper-plugin-utils@7.26.5':\n    resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/helper-string-parser@7.25.9':\n    resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/helper-validator-identifier@7.25.9':\n    resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/helper-validator-option@7.25.9':\n    resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/helpers@7.27.0':\n    resolution: {integrity: sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/parser@7.27.0':\n    resolution: {integrity: sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==}\n    engines: {node: '>=6.0.0'}\n    hasBin: true\n\n  '@babel/plugin-syntax-async-generators@7.8.4':\n    resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-bigint@7.8.3':\n    resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-class-properties@7.12.13':\n    resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-class-static-block@7.14.5':\n    resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}\n    engines: {node: '>=6.9.0'}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-import-attributes@7.26.0':\n    resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==}\n    engines: {node: '>=6.9.0'}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-import-meta@7.10.4':\n    resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-json-strings@7.8.3':\n    resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-logical-assignment-operators@7.10.4':\n    resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3':\n    resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-numeric-separator@7.10.4':\n    resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-object-rest-spread@7.8.3':\n    resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-optional-catch-binding@7.8.3':\n    resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-optional-chaining@7.8.3':\n    resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-private-property-in-object@7.14.5':\n    resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}\n    engines: {node: '>=6.9.0'}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-top-level-await@7.14.5':\n    resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}\n    engines: {node: '>=6.9.0'}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/plugin-syntax-typescript@7.25.9':\n    resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==}\n    engines: {node: '>=6.9.0'}\n    peerDependencies:\n      '@babel/core': ^7.0.0-0\n\n  '@babel/template@7.27.0':\n    resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/traverse@7.27.0':\n    resolution: {integrity: sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==}\n    engines: {node: '>=6.9.0'}\n\n  '@babel/types@7.27.0':\n    resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==}\n    engines: {node: '>=6.9.0'}\n\n  '@bcoe/v8-coverage@0.2.3':\n    resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}\n\n  '@istanbuljs/load-nyc-config@1.1.0':\n    resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}\n    engines: {node: '>=8'}\n\n  '@istanbuljs/schema@0.1.3':\n    resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}\n    engines: {node: '>=8'}\n\n  '@jest/console@27.5.1':\n    resolution: {integrity: sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  '@jest/core@27.5.1':\n    resolution: {integrity: sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n    peerDependencies:\n      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0\n    peerDependenciesMeta:\n      node-notifier:\n        optional: true\n\n  '@jest/environment@27.5.1':\n    resolution: {integrity: sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  '@jest/fake-timers@27.5.1':\n    resolution: {integrity: sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  '@jest/globals@27.5.1':\n    resolution: {integrity: sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  '@jest/reporters@27.5.1':\n    resolution: {integrity: sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n    peerDependencies:\n      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0\n    peerDependenciesMeta:\n      node-notifier:\n        optional: true\n\n  '@jest/source-map@27.5.1':\n    resolution: {integrity: sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  '@jest/test-result@27.5.1':\n    resolution: {integrity: sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  '@jest/test-sequencer@27.5.1':\n    resolution: {integrity: sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  '@jest/transform@27.5.1':\n    resolution: {integrity: sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  '@jest/types@27.5.1':\n    resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  '@jridgewell/gen-mapping@0.3.8':\n    resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==}\n    engines: {node: '>=6.0.0'}\n\n  '@jridgewell/resolve-uri@3.1.2':\n    resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}\n    engines: {node: '>=6.0.0'}\n\n  '@jridgewell/set-array@1.2.1':\n    resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==}\n    engines: {node: '>=6.0.0'}\n\n  '@jridgewell/sourcemap-codec@1.5.0':\n    resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==}\n\n  '@jridgewell/trace-mapping@0.3.25':\n    resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}\n\n  '@noble/hashes@1.8.0':\n    resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}\n    engines: {node: ^14.21.3 || >=16}\n\n  '@nodelib/fs.scandir@2.1.5':\n    resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}\n    engines: {node: '>= 8'}\n\n  '@nodelib/fs.stat@2.0.5':\n    resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}\n    engines: {node: '>= 8'}\n\n  '@nodelib/fs.walk@1.2.8':\n    resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}\n    engines: {node: '>= 8'}\n\n  '@paralleldrive/cuid2@2.2.2':\n    resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}\n\n  '@rollup/plugin-commonjs@25.0.8':\n    resolution: {integrity: sha512-ZEZWTK5n6Qde0to4vS9Mr5x/0UZoqCxPVR9KRUjU4kA2sO7GEUn1fop0DAwpO6z0Nw/kJON9bDmSxdWxO/TT1A==}\n    engines: {node: '>=14.0.0'}\n    peerDependencies:\n      rollup: ^2.68.0||^3.0.0||^4.0.0\n    peerDependenciesMeta:\n      rollup:\n        optional: true\n\n  '@rollup/plugin-node-resolve@15.3.1':\n    resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==}\n    engines: {node: '>=14.0.0'}\n    peerDependencies:\n      rollup: ^2.78.0||^3.0.0||^4.0.0\n    peerDependenciesMeta:\n      rollup:\n        optional: true\n\n  '@rollup/pluginutils@5.1.4':\n    resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==}\n    engines: {node: '>=14.0.0'}\n    peerDependencies:\n      rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0\n    peerDependenciesMeta:\n      rollup:\n        optional: true\n\n  '@sindresorhus/slugify@2.2.1':\n    resolution: {integrity: sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==}\n    engines: {node: '>=12'}\n\n  '@sindresorhus/transliterate@1.6.0':\n    resolution: {integrity: sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==}\n    engines: {node: '>=12'}\n\n  '@sinonjs/commons@1.8.6':\n    resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==}\n\n  '@sinonjs/fake-timers@8.1.0':\n    resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==}\n\n  '@tootallnate/once@1.1.2':\n    resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==}\n    engines: {node: '>= 6'}\n\n  '@tunnckocore/prettier-config@1.3.8':\n    resolution: {integrity: sha512-vhWfo1bgHMGR8qj8w9clxsanIDXYKTge/8kL23qVDfIMLOjam4SCyWgJi5ueOZ+drQJL7y3ni0y+o9lFvxaW+Q==}\n    engines: {node: '>=10.13'}\n    peerDependencies:\n      prettier: ^2.0.2\n      prettier-plugin-pkgjson: ^0.2.3\n\n  '@types/babel__core@7.20.5':\n    resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}\n\n  '@types/babel__generator@7.27.0':\n    resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}\n\n  '@types/babel__template@7.4.4':\n    resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}\n\n  '@types/babel__traverse@7.20.7':\n    resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==}\n\n  '@types/estree@1.0.7':\n    resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}\n\n  '@types/glob@7.2.0':\n    resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}\n\n  '@types/graceful-fs@4.1.9':\n    resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}\n\n  '@types/istanbul-lib-coverage@2.0.6':\n    resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}\n\n  '@types/istanbul-lib-report@3.0.3':\n    resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}\n\n  '@types/istanbul-reports@3.0.4':\n    resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}\n\n  '@types/minimatch@5.1.2':\n    resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}\n\n  '@types/node@22.14.1':\n    resolution: {integrity: sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==}\n\n  '@types/prettier@2.7.3':\n    resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==}\n\n  '@types/resolve@1.20.2':\n    resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}\n\n  '@types/stack-utils@2.0.3':\n    resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}\n\n  '@types/yargs-parser@21.0.3':\n    resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}\n\n  '@types/yargs@16.0.9':\n    resolution: {integrity: sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA==}\n\n  abab@2.0.6:\n    resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}\n    deprecated: Use your platform's native atob() and btoa() methods instead\n\n  accepts@1.3.8:\n    resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}\n    engines: {node: '>= 0.6'}\n\n  acorn-globals@6.0.0:\n    resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==}\n\n  acorn-jsx@5.3.2:\n    resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}\n    peerDependencies:\n      acorn: ^6.0.0 || ^7.0.0 || ^8.0.0\n\n  acorn-walk@7.2.0:\n    resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}\n    engines: {node: '>=0.4.0'}\n\n  acorn@7.4.1:\n    resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}\n    engines: {node: '>=0.4.0'}\n    hasBin: true\n\n  acorn@8.14.1:\n    resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==}\n    engines: {node: '>=0.4.0'}\n    hasBin: true\n\n  agent-base@6.0.2:\n    resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}\n    engines: {node: '>= 6.0.0'}\n\n  aggregate-error@3.1.0:\n    resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}\n    engines: {node: '>=8'}\n\n  ajv@6.12.6:\n    resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}\n\n  ansi-escapes@4.3.2:\n    resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}\n    engines: {node: '>=8'}\n\n  ansi-regex@4.1.1:\n    resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==}\n    engines: {node: '>=6'}\n\n  ansi-regex@5.0.1:\n    resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}\n    engines: {node: '>=8'}\n\n  ansi-styles@3.2.1:\n    resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}\n    engines: {node: '>=4'}\n\n  ansi-styles@4.3.0:\n    resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}\n    engines: {node: '>=8'}\n\n  ansi-styles@5.2.0:\n    resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}\n    engines: {node: '>=10'}\n\n  anymatch@3.1.3:\n    resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}\n    engines: {node: '>= 8'}\n\n  append-transform@2.0.0:\n    resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==}\n    engines: {node: '>=8'}\n\n  archy@1.0.0:\n    resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==}\n\n  argparse@1.0.10:\n    resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}\n\n  array-buffer-byte-length@1.0.2:\n    resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==}\n    engines: {node: '>= 0.4'}\n\n  array-flatten@1.1.1:\n    resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}\n\n  array-includes@3.1.8:\n    resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==}\n    engines: {node: '>= 0.4'}\n\n  array-union@2.1.0:\n    resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}\n    engines: {node: '>=8'}\n\n  array.prototype.flat@1.3.3:\n    resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==}\n    engines: {node: '>= 0.4'}\n\n  arraybuffer.prototype.slice@1.0.4:\n    resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}\n    engines: {node: '>= 0.4'}\n\n  asap@2.0.6:\n    resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}\n\n  astral-regex@1.0.0:\n    resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==}\n    engines: {node: '>=4'}\n\n  async-function@1.0.0:\n    resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}\n    engines: {node: '>= 0.4'}\n\n  asynckit@0.4.0:\n    resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}\n\n  available-typed-arrays@1.0.7:\n    resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==}\n    engines: {node: '>= 0.4'}\n\n  babel-jest@27.5.1:\n    resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n    peerDependencies:\n      '@babel/core': ^7.8.0\n\n  babel-plugin-istanbul@6.1.1:\n    resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}\n    engines: {node: '>=8'}\n\n  babel-plugin-jest-hoist@27.5.1:\n    resolution: {integrity: sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  babel-preset-current-node-syntax@1.1.0:\n    resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==}\n    peerDependencies:\n      '@babel/core': ^7.0.0\n\n  babel-preset-jest@27.5.1:\n    resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n    peerDependencies:\n      '@babel/core': ^7.0.0\n\n  balanced-match@1.0.2:\n    resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}\n\n  body-parser@1.20.3:\n    resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==}\n    engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}\n\n  brace-expansion@1.1.11:\n    resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}\n\n  brace-expansion@2.0.1:\n    resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}\n\n  braces@3.0.3:\n    resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}\n    engines: {node: '>=8'}\n\n  browser-process-hrtime@1.0.0:\n    resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==}\n\n  browserslist@4.24.4:\n    resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==}\n    engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}\n    hasBin: true\n\n  bser@2.1.1:\n    resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}\n\n  buffer-from@1.1.2:\n    resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}\n\n  bytes@3.1.2:\n    resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}\n    engines: {node: '>= 0.8'}\n\n  cache-content-type@1.0.1:\n    resolution: {integrity: sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==}\n    engines: {node: '>= 6.0.0'}\n\n  caching-transform@4.0.0:\n    resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==}\n    engines: {node: '>=8'}\n\n  call-bind-apply-helpers@1.0.2:\n    resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}\n    engines: {node: '>= 0.4'}\n\n  call-bind@1.0.8:\n    resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==}\n    engines: {node: '>= 0.4'}\n\n  call-bound@1.0.4:\n    resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==}\n    engines: {node: '>= 0.4'}\n\n  callsites@3.1.0:\n    resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}\n    engines: {node: '>=6'}\n\n  camelcase@5.3.1:\n    resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}\n    engines: {node: '>=6'}\n\n  camelcase@6.3.0:\n    resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}\n    engines: {node: '>=10'}\n\n  caniuse-lite@1.0.30001715:\n    resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==}\n\n  chalk@2.4.2:\n    resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}\n    engines: {node: '>=4'}\n\n  chalk@4.1.2:\n    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}\n    engines: {node: '>=10'}\n\n  char-regex@1.0.2:\n    resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}\n    engines: {node: '>=10'}\n\n  chardet@0.7.0:\n    resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}\n\n  ci-info@3.9.0:\n    resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}\n    engines: {node: '>=8'}\n\n  cjs-module-lexer@1.4.3:\n    resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==}\n\n  clean-stack@2.2.0:\n    resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}\n    engines: {node: '>=6'}\n\n  cli-cursor@3.1.0:\n    resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}\n    engines: {node: '>=8'}\n\n  cli-width@3.0.0:\n    resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}\n    engines: {node: '>= 10'}\n\n  cliui@6.0.0:\n    resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}\n\n  cliui@7.0.4:\n    resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}\n\n  co@4.6.0:\n    resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}\n    engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}\n\n  collect-v8-coverage@1.0.2:\n    resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}\n\n  color-convert@1.9.3:\n    resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}\n\n  color-convert@2.0.1:\n    resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}\n    engines: {node: '>=7.0.0'}\n\n  color-name@1.1.3:\n    resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}\n\n  color-name@1.1.4:\n    resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}\n\n  combined-stream@1.0.8:\n    resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}\n    engines: {node: '>= 0.8'}\n\n  commondir@1.0.1:\n    resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}\n\n  component-emitter@1.3.1:\n    resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==}\n\n  concat-map@0.0.1:\n    resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}\n\n  confusing-browser-globals@1.0.11:\n    resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==}\n\n  contains-path@0.1.0:\n    resolution: {integrity: sha512-OKZnPGeMQy2RPaUIBPFFd71iNf4791H12MCRuVQDnzGRwCYNYmTDy5pdafo2SLAcEMKzTOQnLWG4QdcjeJUMEg==}\n    engines: {node: '>=0.10.0'}\n\n  content-disposition@0.5.4:\n    resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}\n    engines: {node: '>= 0.6'}\n\n  content-type@1.0.5:\n    resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}\n    engines: {node: '>= 0.6'}\n\n  convert-source-map@1.9.0:\n    resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}\n\n  convert-source-map@2.0.0:\n    resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}\n\n  cookie-signature@1.0.6:\n    resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}\n\n  cookie@0.7.1:\n    resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}\n    engines: {node: '>= 0.6'}\n\n  cookiejar@2.1.4:\n    resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==}\n\n  cookies@0.9.1:\n    resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==}\n    engines: {node: '>= 0.8'}\n\n  cross-spawn@6.0.6:\n    resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==}\n    engines: {node: '>=4.8'}\n\n  cross-spawn@7.0.6:\n    resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}\n    engines: {node: '>= 8'}\n\n  cssom@0.3.8:\n    resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}\n\n  cssom@0.4.4:\n    resolution: {integrity: sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==}\n\n  cssstyle@2.3.0:\n    resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==}\n    engines: {node: '>=8'}\n\n  data-urls@2.0.0:\n    resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==}\n    engines: {node: '>=10'}\n\n  data-view-buffer@1.0.2:\n    resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}\n    engines: {node: '>= 0.4'}\n\n  data-view-byte-length@1.0.2:\n    resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==}\n    engines: {node: '>= 0.4'}\n\n  data-view-byte-offset@1.0.1:\n    resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}\n    engines: {node: '>= 0.4'}\n\n  debug@2.6.9:\n    resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}\n    peerDependencies:\n      supports-color: '*'\n    peerDependenciesMeta:\n      supports-color:\n        optional: true\n\n  debug@3.2.7:\n    resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}\n    peerDependencies:\n      supports-color: '*'\n    peerDependenciesMeta:\n      supports-color:\n        optional: true\n\n  debug@4.4.0:\n    resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==}\n    engines: {node: '>=6.0'}\n    peerDependencies:\n      supports-color: '*'\n    peerDependenciesMeta:\n      supports-color:\n        optional: true\n\n  decamelize@1.2.0:\n    resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}\n    engines: {node: '>=0.10.0'}\n\n  decimal.js@10.5.0:\n    resolution: {integrity: sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==}\n\n  dedent@0.7.0:\n    resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}\n\n  deep-equal@1.0.1:\n    resolution: {integrity: sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==}\n\n  deep-is@0.1.4:\n    resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}\n\n  deepmerge@4.3.1:\n    resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}\n    engines: {node: '>=0.10.0'}\n\n  default-require-extensions@3.0.1:\n    resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==}\n    engines: {node: '>=8'}\n\n  define-data-property@1.1.4:\n    resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}\n    engines: {node: '>= 0.4'}\n\n  define-properties@1.2.1:\n    resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}\n    engines: {node: '>= 0.4'}\n\n  delayed-stream@1.0.0:\n    resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}\n    engines: {node: '>=0.4.0'}\n\n  delegates@1.0.0:\n    resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}\n\n  depd@1.1.2:\n    resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==}\n    engines: {node: '>= 0.6'}\n\n  depd@2.0.0:\n    resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}\n    engines: {node: '>= 0.8'}\n\n  destroy@1.2.0:\n    resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}\n    engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}\n\n  detect-indent@6.1.0:\n    resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}\n    engines: {node: '>=8'}\n\n  detect-newline@3.1.0:\n    resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}\n    engines: {node: '>=8'}\n\n  dezalgo@1.0.4:\n    resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}\n\n  diff-sequences@27.5.1:\n    resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  dir-glob@3.0.1:\n    resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}\n    engines: {node: '>=8'}\n\n  doctrine@1.5.0:\n    resolution: {integrity: sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg==}\n    engines: {node: '>=0.10.0'}\n\n  doctrine@3.0.0:\n    resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}\n    engines: {node: '>=6.0.0'}\n\n  domexception@2.0.1:\n    resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==}\n    engines: {node: '>=8'}\n    deprecated: Use your platform's native DOMException instead\n\n  dunder-proto@1.0.1:\n    resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}\n    engines: {node: '>= 0.4'}\n\n  ee-first@1.1.1:\n    resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}\n\n  electron-to-chromium@1.5.140:\n    resolution: {integrity: sha512-o82Rj+ONp4Ip7Cl1r7lrqx/pXhbp/lh9DpKcMNscFJdh8ebyRofnc7Sh01B4jx403RI0oqTBvlZ7OBIZLMr2+Q==}\n\n  emittery@0.8.1:\n    resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==}\n    engines: {node: '>=10'}\n\n  emoji-regex@7.0.3:\n    resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==}\n\n  emoji-regex@8.0.0:\n    resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}\n\n  encodeurl@1.0.2:\n    resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}\n    engines: {node: '>= 0.8'}\n\n  encodeurl@2.0.0:\n    resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}\n    engines: {node: '>= 0.8'}\n\n  error-ex@1.3.2:\n    resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}\n\n  es-abstract@1.23.9:\n    resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==}\n    engines: {node: '>= 0.4'}\n\n  es-define-property@1.0.1:\n    resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}\n    engines: {node: '>= 0.4'}\n\n  es-errors@1.3.0:\n    resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}\n    engines: {node: '>= 0.4'}\n\n  es-object-atoms@1.1.1:\n    resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}\n    engines: {node: '>= 0.4'}\n\n  es-set-tostringtag@2.1.0:\n    resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}\n    engines: {node: '>= 0.4'}\n\n  es-shim-unscopables@1.1.0:\n    resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==}\n    engines: {node: '>= 0.4'}\n\n  es-to-primitive@1.3.0:\n    resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}\n    engines: {node: '>= 0.4'}\n\n  es6-error@4.1.1:\n    resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}\n\n  escalade@3.2.0:\n    resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}\n    engines: {node: '>=6'}\n\n  escape-html@1.0.3:\n    resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}\n\n  escape-string-regexp@1.0.5:\n    resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}\n    engines: {node: '>=0.8.0'}\n\n  escape-string-regexp@2.0.0:\n    resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}\n    engines: {node: '>=8'}\n\n  escape-string-regexp@5.0.0:\n    resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}\n    engines: {node: '>=12'}\n\n  escodegen@2.1.0:\n    resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}\n    engines: {node: '>=6.0'}\n    hasBin: true\n\n  eslint-config-airbnb-base@14.1.0:\n    resolution: {integrity: sha512-+XCcfGyCnbzOnktDVhwsCAx+9DmrzEmuwxyHUJpw+kqBVT744OUBrB09khgFKlK1lshVww6qXGsYPZpavoNjJw==}\n    engines: {node: '>= 6'}\n    peerDependencies:\n      eslint: ^5.16.0 || ^6.8.0\n      eslint-plugin-import: ^2.20.1\n\n  eslint-config-prettier@6.11.0:\n    resolution: {integrity: sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==}\n    hasBin: true\n    peerDependencies:\n      eslint: '>=3.14.1'\n\n  eslint-import-resolver-node@0.3.9:\n    resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==}\n\n  eslint-module-utils@2.12.0:\n    resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==}\n    engines: {node: '>=4'}\n    peerDependencies:\n      '@typescript-eslint/parser': '*'\n      eslint: '*'\n      eslint-import-resolver-node: '*'\n      eslint-import-resolver-typescript: '*'\n      eslint-import-resolver-webpack: '*'\n    peerDependenciesMeta:\n      '@typescript-eslint/parser':\n        optional: true\n      eslint:\n        optional: true\n      eslint-import-resolver-node:\n        optional: true\n      eslint-import-resolver-typescript:\n        optional: true\n      eslint-import-resolver-webpack:\n        optional: true\n\n  eslint-plugin-import@2.20.2:\n    resolution: {integrity: sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg==}\n    engines: {node: '>=4'}\n    peerDependencies:\n      '@typescript-eslint/parser': '*'\n      eslint: 2.x - 6.x\n    peerDependenciesMeta:\n      '@typescript-eslint/parser':\n        optional: true\n\n  eslint-plugin-prettier@3.1.3:\n    resolution: {integrity: sha512-+HG5jmu/dN3ZV3T6eCD7a4BlAySdN7mLIbJYo0z1cFQuI+r2DiTJEFeF68ots93PsnrMxbzIZ2S/ieX+mkrBeQ==}\n    engines: {node: '>=6.0.0'}\n    peerDependencies:\n      eslint: '>= 5.0.0'\n      prettier: '>= 1.13.0'\n\n  eslint-scope@5.1.1:\n    resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}\n    engines: {node: '>=8.0.0'}\n\n  eslint-utils@1.4.3:\n    resolution: {integrity: sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==}\n    engines: {node: '>=6'}\n\n  eslint-visitor-keys@1.3.0:\n    resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==}\n    engines: {node: '>=4'}\n\n  eslint@6.8.0:\n    resolution: {integrity: sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==}\n    engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1}\n    deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.\n    hasBin: true\n\n  espree@6.2.1:\n    resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==}\n    engines: {node: '>=6.0.0'}\n\n  esprima@4.0.1:\n    resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}\n    engines: {node: '>=4'}\n    hasBin: true\n\n  esquery@1.6.0:\n    resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==}\n    engines: {node: '>=0.10'}\n\n  esrecurse@4.3.0:\n    resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}\n    engines: {node: '>=4.0'}\n\n  estraverse@4.3.0:\n    resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}\n    engines: {node: '>=4.0'}\n\n  estraverse@5.3.0:\n    resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}\n    engines: {node: '>=4.0'}\n\n  estree-walker@2.0.2:\n    resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}\n\n  esutils@2.0.3:\n    resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}\n    engines: {node: '>=0.10.0'}\n\n  etag@1.8.1:\n    resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}\n    engines: {node: '>= 0.6'}\n\n  execa@5.1.1:\n    resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}\n    engines: {node: '>=10'}\n\n  exit@0.1.2:\n    resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}\n    engines: {node: '>= 0.8.0'}\n\n  expect@27.5.1:\n    resolution: {integrity: sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  express@4.21.2:\n    resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==}\n    engines: {node: '>= 0.10.0'}\n\n  external-editor@3.1.0:\n    resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}\n    engines: {node: '>=4'}\n\n  fast-deep-equal@3.1.3:\n    resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}\n\n  fast-diff@1.3.0:\n    resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}\n\n  fast-glob@3.3.3:\n    resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==}\n    engines: {node: '>=8.6.0'}\n\n  fast-json-stable-stringify@2.1.0:\n    resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}\n\n  fast-levenshtein@2.0.6:\n    resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}\n\n  fast-safe-stringify@2.1.1:\n    resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}\n\n  fastq@1.19.1:\n    resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==}\n\n  fb-watchman@2.0.2:\n    resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}\n\n  fetch-blob@3.2.0:\n    resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}\n    engines: {node: ^12.20 || >= 14.13}\n\n  figures@3.2.0:\n    resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}\n    engines: {node: '>=8'}\n\n  file-entry-cache@5.0.1:\n    resolution: {integrity: sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==}\n    engines: {node: '>=4'}\n\n  fill-range@7.1.1:\n    resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}\n    engines: {node: '>=8'}\n\n  finalhandler@1.3.1:\n    resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==}\n    engines: {node: '>= 0.8'}\n\n  find-cache-dir@3.3.2:\n    resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==}\n    engines: {node: '>=8'}\n\n  find-up@2.1.0:\n    resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==}\n    engines: {node: '>=4'}\n\n  find-up@4.1.0:\n    resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}\n    engines: {node: '>=8'}\n\n  flat-cache@2.0.1:\n    resolution: {integrity: sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==}\n    engines: {node: '>=4'}\n\n  flatted@2.0.2:\n    resolution: {integrity: sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==}\n\n  for-each@0.3.5:\n    resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}\n    engines: {node: '>= 0.4'}\n\n  foreground-child@2.0.0:\n    resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==}\n    engines: {node: '>=8.0.0'}\n\n  form-data@3.0.3:\n    resolution: {integrity: sha512-q5YBMeWy6E2Un0nMGWMgI65MAKtaylxfNJGJxpGh45YDciZB4epbWpaAfImil6CPAPTYB4sh0URQNDRIZG5F2w==}\n    engines: {node: '>= 6'}\n\n  formdata-polyfill@4.0.10:\n    resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}\n    engines: {node: '>=12.20.0'}\n\n  formidable@1.2.6:\n    resolution: {integrity: sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==}\n    deprecated: 'Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau'\n\n  forwarded@0.2.0:\n    resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}\n    engines: {node: '>= 0.6'}\n\n  fresh@0.5.2:\n    resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}\n    engines: {node: '>= 0.6'}\n\n  fromentries@1.3.2:\n    resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==}\n\n  fs.realpath@1.0.0:\n    resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}\n\n  fsevents@2.3.3:\n    resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}\n    engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}\n    os: [darwin]\n\n  function-bind@1.1.2:\n    resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}\n\n  function.prototype.name@1.1.8:\n    resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==}\n    engines: {node: '>= 0.4'}\n\n  functional-red-black-tree@1.0.1:\n    resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==}\n\n  functions-have-names@1.2.3:\n    resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}\n\n  gensync@1.0.0-beta.2:\n    resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}\n    engines: {node: '>=6.9.0'}\n\n  get-caller-file@2.0.5:\n    resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}\n    engines: {node: 6.* || 8.* || >= 10.*}\n\n  get-intrinsic@1.3.0:\n    resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}\n    engines: {node: '>= 0.4'}\n\n  get-package-type@0.1.0:\n    resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}\n    engines: {node: '>=8.0.0'}\n\n  get-proto@1.0.1:\n    resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}\n    engines: {node: '>= 0.4'}\n\n  get-stdin@6.0.0:\n    resolution: {integrity: sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==}\n    engines: {node: '>=4'}\n\n  get-stream@6.0.1:\n    resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}\n    engines: {node: '>=10'}\n\n  get-symbol-description@1.1.0:\n    resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==}\n    engines: {node: '>= 0.4'}\n\n  git-hooks-list@1.0.3:\n    resolution: {integrity: sha512-Y7wLWcrLUXwk2noSka166byGCvhMtDRpgHdzCno1UQv/n/Hegp++a2xBWJL1lJarnKD3SWaljD+0z1ztqxuKyQ==}\n\n  glob-parent@5.1.2:\n    resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}\n    engines: {node: '>= 6'}\n\n  glob@7.2.3:\n    resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}\n    deprecated: Glob versions prior to v9 are no longer supported\n\n  glob@8.1.0:\n    resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}\n    engines: {node: '>=12'}\n    deprecated: Glob versions prior to v9 are no longer supported\n\n  globals@11.12.0:\n    resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}\n    engines: {node: '>=4'}\n\n  globals@12.4.0:\n    resolution: {integrity: sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==}\n    engines: {node: '>=8'}\n\n  globalthis@1.0.4:\n    resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==}\n    engines: {node: '>= 0.4'}\n\n  globby@10.0.0:\n    resolution: {integrity: sha512-3LifW9M4joGZasyYPz2A1U74zbC/45fvpXUvO/9KbSa+VV0aGZarWkfdgKyR9sExNP0t0x0ss/UMJpNpcaTspw==}\n    engines: {node: '>=8'}\n\n  gopd@1.2.0:\n    resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}\n    engines: {node: '>= 0.4'}\n\n  graceful-fs@4.2.11:\n    resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}\n\n  has-bigints@1.1.0:\n    resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==}\n    engines: {node: '>= 0.4'}\n\n  has-flag@3.0.0:\n    resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}\n    engines: {node: '>=4'}\n\n  has-flag@4.0.0:\n    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}\n    engines: {node: '>=8'}\n\n  has-property-descriptors@1.0.2:\n    resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}\n\n  has-proto@1.2.0:\n    resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==}\n    engines: {node: '>= 0.4'}\n\n  has-symbols@1.1.0:\n    resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}\n    engines: {node: '>= 0.4'}\n\n  has-tostringtag@1.0.2:\n    resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}\n    engines: {node: '>= 0.4'}\n\n  has@1.0.4:\n    resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==}\n    engines: {node: '>= 0.4.0'}\n\n  hasha@5.2.2:\n    resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==}\n    engines: {node: '>=8'}\n\n  hasown@2.0.2:\n    resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}\n    engines: {node: '>= 0.4'}\n\n  hosted-git-info@2.8.9:\n    resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}\n\n  html-encoding-sniffer@2.0.1:\n    resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==}\n    engines: {node: '>=10'}\n\n  html-escaper@2.0.2:\n    resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}\n\n  http-assert@1.5.0:\n    resolution: {integrity: sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==}\n    engines: {node: '>= 0.8'}\n\n  http-errors@1.8.1:\n    resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==}\n    engines: {node: '>= 0.6'}\n\n  http-errors@2.0.0:\n    resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}\n    engines: {node: '>= 0.8'}\n\n  http-proxy-agent@4.0.1:\n    resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==}\n    engines: {node: '>= 6'}\n\n  https-proxy-agent@5.0.1:\n    resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}\n    engines: {node: '>= 6'}\n\n  human-signals@2.1.0:\n    resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}\n    engines: {node: '>=10.17.0'}\n\n  iconv-lite@0.4.24:\n    resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}\n    engines: {node: '>=0.10.0'}\n\n  ignore@4.0.6:\n    resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}\n    engines: {node: '>= 4'}\n\n  ignore@5.3.2:\n    resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}\n    engines: {node: '>= 4'}\n\n  import-fresh@3.3.1:\n    resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}\n    engines: {node: '>=6'}\n\n  import-local@3.2.0:\n    resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==}\n    engines: {node: '>=8'}\n    hasBin: true\n\n  imurmurhash@0.1.4:\n    resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}\n    engines: {node: '>=0.8.19'}\n\n  indent-string@4.0.0:\n    resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}\n    engines: {node: '>=8'}\n\n  inflight@1.0.6:\n    resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}\n    deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.\n\n  inherits@2.0.4:\n    resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}\n\n  inquirer@7.3.3:\n    resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==}\n    engines: {node: '>=8.0.0'}\n\n  internal-slot@1.1.0:\n    resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}\n    engines: {node: '>= 0.4'}\n\n  ipaddr.js@1.9.1:\n    resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}\n    engines: {node: '>= 0.10'}\n\n  is-array-buffer@3.0.5:\n    resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==}\n    engines: {node: '>= 0.4'}\n\n  is-arrayish@0.2.1:\n    resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}\n\n  is-async-function@2.1.1:\n    resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}\n    engines: {node: '>= 0.4'}\n\n  is-bigint@1.1.0:\n    resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==}\n    engines: {node: '>= 0.4'}\n\n  is-boolean-object@1.2.2:\n    resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==}\n    engines: {node: '>= 0.4'}\n\n  is-callable@1.2.7:\n    resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}\n    engines: {node: '>= 0.4'}\n\n  is-core-module@2.16.1:\n    resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}\n    engines: {node: '>= 0.4'}\n\n  is-data-view@1.0.2:\n    resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==}\n    engines: {node: '>= 0.4'}\n\n  is-date-object@1.1.0:\n    resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==}\n    engines: {node: '>= 0.4'}\n\n  is-extglob@2.1.1:\n    resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}\n    engines: {node: '>=0.10.0'}\n\n  is-finalizationregistry@1.1.1:\n    resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==}\n    engines: {node: '>= 0.4'}\n\n  is-fullwidth-code-point@2.0.0:\n    resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==}\n    engines: {node: '>=4'}\n\n  is-fullwidth-code-point@3.0.0:\n    resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}\n    engines: {node: '>=8'}\n\n  is-generator-fn@2.1.0:\n    resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}\n    engines: {node: '>=6'}\n\n  is-generator-function@1.1.0:\n    resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==}\n    engines: {node: '>= 0.4'}\n\n  is-glob@4.0.3:\n    resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}\n    engines: {node: '>=0.10.0'}\n\n  is-map@2.0.3:\n    resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==}\n    engines: {node: '>= 0.4'}\n\n  is-module@1.0.0:\n    resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}\n\n  is-number-object@1.1.1:\n    resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==}\n    engines: {node: '>= 0.4'}\n\n  is-number@7.0.0:\n    resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}\n    engines: {node: '>=0.12.0'}\n\n  is-plain-obj@2.1.0:\n    resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==}\n    engines: {node: '>=8'}\n\n  is-potential-custom-element-name@1.0.1:\n    resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}\n\n  is-reference@1.2.1:\n    resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}\n\n  is-regex@1.2.1:\n    resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==}\n    engines: {node: '>= 0.4'}\n\n  is-set@2.0.3:\n    resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==}\n    engines: {node: '>= 0.4'}\n\n  is-shared-array-buffer@1.0.4:\n    resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}\n    engines: {node: '>= 0.4'}\n\n  is-stream@2.0.1:\n    resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}\n    engines: {node: '>=8'}\n\n  is-string@1.1.1:\n    resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}\n    engines: {node: '>= 0.4'}\n\n  is-symbol@1.1.1:\n    resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==}\n    engines: {node: '>= 0.4'}\n\n  is-typed-array@1.1.15:\n    resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==}\n    engines: {node: '>= 0.4'}\n\n  is-typedarray@1.0.0:\n    resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==}\n\n  is-weakmap@2.0.2:\n    resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==}\n    engines: {node: '>= 0.4'}\n\n  is-weakref@1.1.1:\n    resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==}\n    engines: {node: '>= 0.4'}\n\n  is-weakset@2.0.4:\n    resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==}\n    engines: {node: '>= 0.4'}\n\n  is-windows@1.0.2:\n    resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}\n    engines: {node: '>=0.10.0'}\n\n  isarray@1.0.0:\n    resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}\n\n  isarray@2.0.5:\n    resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}\n\n  isexe@2.0.0:\n    resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}\n\n  istanbul-lib-coverage@3.2.2:\n    resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}\n    engines: {node: '>=8'}\n\n  istanbul-lib-hook@3.0.0:\n    resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==}\n    engines: {node: '>=8'}\n\n  istanbul-lib-instrument@4.0.3:\n    resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==}\n    engines: {node: '>=8'}\n\n  istanbul-lib-instrument@5.2.1:\n    resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}\n    engines: {node: '>=8'}\n\n  istanbul-lib-processinfo@2.0.3:\n    resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==}\n    engines: {node: '>=8'}\n\n  istanbul-lib-report@3.0.1:\n    resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}\n    engines: {node: '>=10'}\n\n  istanbul-lib-source-maps@4.0.1:\n    resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}\n    engines: {node: '>=10'}\n\n  istanbul-reports@3.1.7:\n    resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==}\n    engines: {node: '>=8'}\n\n  jest-changed-files@27.5.1:\n    resolution: {integrity: sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-circus@27.5.1:\n    resolution: {integrity: sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-cli@27.5.1:\n    resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n    hasBin: true\n    peerDependencies:\n      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0\n    peerDependenciesMeta:\n      node-notifier:\n        optional: true\n\n  jest-config@27.5.1:\n    resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n    peerDependencies:\n      ts-node: '>=9.0.0'\n    peerDependenciesMeta:\n      ts-node:\n        optional: true\n\n  jest-diff@27.5.1:\n    resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-docblock@27.5.1:\n    resolution: {integrity: sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-each@27.5.1:\n    resolution: {integrity: sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-environment-jsdom@27.5.1:\n    resolution: {integrity: sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-environment-node@27.5.1:\n    resolution: {integrity: sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-get-type@27.5.1:\n    resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-haste-map@27.5.1:\n    resolution: {integrity: sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-jasmine2@27.5.1:\n    resolution: {integrity: sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-leak-detector@27.5.1:\n    resolution: {integrity: sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-matcher-utils@27.5.1:\n    resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-message-util@27.5.1:\n    resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-mock@27.5.1:\n    resolution: {integrity: sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-pnp-resolver@1.2.3:\n    resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}\n    engines: {node: '>=6'}\n    peerDependencies:\n      jest-resolve: '*'\n    peerDependenciesMeta:\n      jest-resolve:\n        optional: true\n\n  jest-regex-util@27.5.1:\n    resolution: {integrity: sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-resolve-dependencies@27.5.1:\n    resolution: {integrity: sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-resolve@27.5.1:\n    resolution: {integrity: sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-runner@27.5.1:\n    resolution: {integrity: sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-runtime@27.5.1:\n    resolution: {integrity: sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-serializer@27.5.1:\n    resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-snapshot@27.5.1:\n    resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-util@27.5.1:\n    resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-validate@27.5.1:\n    resolution: {integrity: sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-watcher@27.5.1:\n    resolution: {integrity: sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  jest-worker@27.5.1:\n    resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}\n    engines: {node: '>= 10.13.0'}\n\n  jest@27.2.4:\n    resolution: {integrity: sha512-h4uqb1EQLfPulWyUFFWv9e9Nn8sCqsJ/j3wk/KCY0p4s4s0ICCfP3iMf6hRf5hEhsDyvyrCgKiZXma63gMz16A==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n    hasBin: true\n    peerDependencies:\n      node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0\n    peerDependenciesMeta:\n      node-notifier:\n        optional: true\n\n  js-tokens@4.0.0:\n    resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}\n\n  js-yaml@3.14.1:\n    resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}\n    hasBin: true\n\n  jsdom@16.7.0:\n    resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==}\n    engines: {node: '>=10'}\n    peerDependencies:\n      canvas: ^2.5.0\n    peerDependenciesMeta:\n      canvas:\n        optional: true\n\n  jsesc@3.1.0:\n    resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}\n    engines: {node: '>=6'}\n    hasBin: true\n\n  json-parse-even-better-errors@2.3.1:\n    resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}\n\n  json-schema-traverse@0.4.1:\n    resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}\n\n  json-stable-stringify-without-jsonify@1.0.1:\n    resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}\n\n  json5@2.2.3:\n    resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}\n    engines: {node: '>=6'}\n    hasBin: true\n\n  keygrip@1.1.0:\n    resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==}\n    engines: {node: '>= 0.6'}\n\n  kleur@3.0.3:\n    resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}\n    engines: {node: '>=6'}\n\n  koa-compose@4.1.0:\n    resolution: {integrity: sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==}\n\n  koa-convert@2.0.0:\n    resolution: {integrity: sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==}\n    engines: {node: '>= 10'}\n\n  koa@2.16.1:\n    resolution: {integrity: sha512-umfX9d3iuSxTQP4pnzLOz0HKnPg0FaUUIKcye2lOiz3KPu1Y3M3xlz76dISdFPQs37P9eJz1wUpcTS6KDPn9fA==}\n    engines: {node: ^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4}\n\n  leven@3.1.0:\n    resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}\n    engines: {node: '>=6'}\n\n  levn@0.3.0:\n    resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==}\n    engines: {node: '>= 0.8.0'}\n\n  lines-and-columns@1.2.4:\n    resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}\n\n  load-json-file@2.0.0:\n    resolution: {integrity: sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==}\n    engines: {node: '>=4'}\n\n  locate-path@2.0.0:\n    resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==}\n    engines: {node: '>=4'}\n\n  locate-path@5.0.0:\n    resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}\n    engines: {node: '>=8'}\n\n  lodash.flattendeep@4.4.0:\n    resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==}\n\n  lodash@4.17.21:\n    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}\n\n  lru-cache@5.1.1:\n    resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}\n\n  magic-string@0.30.17:\n    resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}\n\n  make-dir@3.1.0:\n    resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}\n    engines: {node: '>=8'}\n\n  make-dir@4.0.0:\n    resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}\n    engines: {node: '>=10'}\n\n  makeerror@1.0.12:\n    resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}\n\n  math-intrinsics@1.1.0:\n    resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}\n    engines: {node: '>= 0.4'}\n\n  media-typer@0.3.0:\n    resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}\n    engines: {node: '>= 0.6'}\n\n  merge-descriptors@1.0.3:\n    resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==}\n\n  merge-stream@2.0.0:\n    resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}\n\n  merge2@1.4.1:\n    resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}\n    engines: {node: '>= 8'}\n\n  methods@1.1.2:\n    resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}\n    engines: {node: '>= 0.6'}\n\n  micromatch@4.0.8:\n    resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}\n    engines: {node: '>=8.6'}\n\n  mime-db@1.52.0:\n    resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}\n    engines: {node: '>= 0.6'}\n\n  mime-types@2.1.35:\n    resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}\n    engines: {node: '>= 0.6'}\n\n  mime@1.6.0:\n    resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}\n    engines: {node: '>=4'}\n    hasBin: true\n\n  mime@2.6.0:\n    resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==}\n    engines: {node: '>=4.0.0'}\n    hasBin: true\n\n  mimic-fn@2.1.0:\n    resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}\n    engines: {node: '>=6'}\n\n  minimatch@3.1.2:\n    resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}\n\n  minimatch@5.1.6:\n    resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}\n    engines: {node: '>=10'}\n\n  minimist@1.2.8:\n    resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}\n\n  mkdirp@0.5.6:\n    resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}\n    hasBin: true\n\n  ms@2.0.0:\n    resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}\n\n  ms@2.1.3:\n    resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}\n\n  mute-stream@0.0.8:\n    resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==}\n\n  natural-compare@1.4.0:\n    resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}\n\n  negotiator@0.6.3:\n    resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}\n    engines: {node: '>= 0.6'}\n\n  nice-try@1.0.5:\n    resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}\n\n  node-domexception@1.0.0:\n    resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}\n    engines: {node: '>=10.5.0'}\n    deprecated: Use your platform's native DOMException instead\n\n  node-int64@0.4.0:\n    resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}\n\n  node-preload@0.2.1:\n    resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==}\n    engines: {node: '>=8'}\n\n  node-releases@2.0.19:\n    resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}\n\n  normalize-package-data@2.5.0:\n    resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}\n\n  normalize-path@3.0.0:\n    resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}\n    engines: {node: '>=0.10.0'}\n\n  npm-run-path@4.0.1:\n    resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}\n    engines: {node: '>=8'}\n\n  nwsapi@2.2.20:\n    resolution: {integrity: sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==}\n\n  nyc@15.1.0:\n    resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==}\n    engines: {node: '>=8.9'}\n    hasBin: true\n\n  object-inspect@1.13.4:\n    resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}\n    engines: {node: '>= 0.4'}\n\n  object-keys@1.1.1:\n    resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}\n    engines: {node: '>= 0.4'}\n\n  object.assign@4.1.7:\n    resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==}\n    engines: {node: '>= 0.4'}\n\n  object.entries@1.1.9:\n    resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==}\n    engines: {node: '>= 0.4'}\n\n  object.values@1.2.1:\n    resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==}\n    engines: {node: '>= 0.4'}\n\n  on-finished@2.4.1:\n    resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}\n    engines: {node: '>= 0.8'}\n\n  once@1.4.0:\n    resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}\n\n  onetime@5.1.2:\n    resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}\n    engines: {node: '>=6'}\n\n  only@0.0.2:\n    resolution: {integrity: sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==}\n\n  optionator@0.8.3:\n    resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==}\n    engines: {node: '>= 0.8.0'}\n\n  os-tmpdir@1.0.2:\n    resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==}\n    engines: {node: '>=0.10.0'}\n\n  own-keys@1.0.1:\n    resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==}\n    engines: {node: '>= 0.4'}\n\n  p-limit@1.3.0:\n    resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==}\n    engines: {node: '>=4'}\n\n  p-limit@2.3.0:\n    resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}\n    engines: {node: '>=6'}\n\n  p-locate@2.0.0:\n    resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==}\n    engines: {node: '>=4'}\n\n  p-locate@4.1.0:\n    resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}\n    engines: {node: '>=8'}\n\n  p-map@3.0.0:\n    resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==}\n    engines: {node: '>=8'}\n\n  p-try@1.0.0:\n    resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==}\n    engines: {node: '>=4'}\n\n  p-try@2.2.0:\n    resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}\n    engines: {node: '>=6'}\n\n  package-hash@4.0.0:\n    resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==}\n    engines: {node: '>=8'}\n\n  parent-module@1.0.1:\n    resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}\n    engines: {node: '>=6'}\n\n  parse-json@2.2.0:\n    resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==}\n    engines: {node: '>=0.10.0'}\n\n  parse-json@5.2.0:\n    resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}\n    engines: {node: '>=8'}\n\n  parse5@6.0.1:\n    resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}\n\n  parseurl@1.3.3:\n    resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}\n    engines: {node: '>= 0.8'}\n\n  path-exists@3.0.0:\n    resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==}\n    engines: {node: '>=4'}\n\n  path-exists@4.0.0:\n    resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}\n    engines: {node: '>=8'}\n\n  path-is-absolute@1.0.1:\n    resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}\n    engines: {node: '>=0.10.0'}\n\n  path-key@2.0.1:\n    resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}\n    engines: {node: '>=4'}\n\n  path-key@3.1.1:\n    resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}\n    engines: {node: '>=8'}\n\n  path-parse@1.0.7:\n    resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}\n\n  path-to-regexp@0.1.12:\n    resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==}\n\n  path-type@2.0.0:\n    resolution: {integrity: sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==}\n    engines: {node: '>=4'}\n\n  path-type@4.0.0:\n    resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}\n    engines: {node: '>=8'}\n\n  picocolors@1.1.1:\n    resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}\n\n  picomatch@2.3.1:\n    resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}\n    engines: {node: '>=8.6'}\n\n  picomatch@4.0.2:\n    resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}\n    engines: {node: '>=12'}\n\n  pify@2.3.0:\n    resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}\n    engines: {node: '>=0.10.0'}\n\n  pirates@4.0.7:\n    resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}\n    engines: {node: '>= 6'}\n\n  pkg-dir@4.2.0:\n    resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}\n    engines: {node: '>=8'}\n\n  possible-typed-array-names@1.1.0:\n    resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}\n    engines: {node: '>= 0.4'}\n\n  prelude-ls@1.1.2:\n    resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}\n    engines: {node: '>= 0.8.0'}\n\n  prettier-linter-helpers@1.0.0:\n    resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}\n    engines: {node: '>=6.0.0'}\n\n  prettier-plugin-pkgjson@0.2.8:\n    resolution: {integrity: sha512-MBpPCjqQKxKc5SxhLkVeE2Q+3N7KBk+zJLkFzHVL6SMRAZlyiq/44w/NonCmO+24pI7s/LKoeFqcWY2+08vuEg==}\n    engines: {node: '>=10.13'}\n    peerDependencies:\n      prettier: ^2.0.2\n\n  prettier@2.0.5:\n    resolution: {integrity: sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==}\n    engines: {node: '>=10.13.0'}\n    hasBin: true\n\n  pretty-format@27.5.1:\n    resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}\n    engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}\n\n  process-on-spawn@1.1.0:\n    resolution: {integrity: sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==}\n    engines: {node: '>=8'}\n\n  progress@2.0.3:\n    resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}\n    engines: {node: '>=0.4.0'}\n\n  prompts@2.4.2:\n    resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}\n    engines: {node: '>= 6'}\n\n  proxy-addr@2.0.7:\n    resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}\n    engines: {node: '>= 0.10'}\n\n  psl@1.15.0:\n    resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}\n\n  punycode@2.3.1:\n    resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}\n    engines: {node: '>=6'}\n\n  qs@6.13.0:\n    resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==}\n    engines: {node: '>=0.6'}\n\n  qs@6.14.0:\n    resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}\n    engines: {node: '>=0.6'}\n\n  querystringify@2.2.0:\n    resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}\n\n  queue-microtask@1.2.3:\n    resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}\n\n  range-parser@1.2.1:\n    resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}\n    engines: {node: '>= 0.6'}\n\n  raw-body@2.5.2:\n    resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==}\n    engines: {node: '>= 0.8'}\n\n  react-is@17.0.2:\n    resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}\n\n  read-pkg-up@2.0.0:\n    resolution: {integrity: sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==}\n    engines: {node: '>=4'}\n\n  read-pkg@2.0.0:\n    resolution: {integrity: sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==}\n    engines: {node: '>=4'}\n\n  readable-stream@3.6.2:\n    resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}\n    engines: {node: '>= 6'}\n\n  reflect.getprototypeof@1.0.10:\n    resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==}\n    engines: {node: '>= 0.4'}\n\n  regexp.prototype.flags@1.5.4:\n    resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==}\n    engines: {node: '>= 0.4'}\n\n  regexpp@2.0.1:\n    resolution: {integrity: sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==}\n    engines: {node: '>=6.5.0'}\n\n  release-zalgo@1.0.0:\n    resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==}\n    engines: {node: '>=4'}\n\n  require-directory@2.1.1:\n    resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}\n    engines: {node: '>=0.10.0'}\n\n  require-main-filename@2.0.0:\n    resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}\n\n  requires-port@1.0.0:\n    resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}\n\n  resolve-cwd@3.0.0:\n    resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}\n    engines: {node: '>=8'}\n\n  resolve-from@4.0.0:\n    resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}\n    engines: {node: '>=4'}\n\n  resolve-from@5.0.0:\n    resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}\n    engines: {node: '>=8'}\n\n  resolve.exports@1.1.1:\n    resolution: {integrity: sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==}\n    engines: {node: '>=10'}\n\n  resolve@1.22.10:\n    resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==}\n    engines: {node: '>= 0.4'}\n    hasBin: true\n\n  restore-cursor@3.1.0:\n    resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}\n    engines: {node: '>=8'}\n\n  reusify@1.1.0:\n    resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}\n    engines: {iojs: '>=1.0.0', node: '>=0.10.0'}\n\n  rimraf@2.6.3:\n    resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==}\n    deprecated: Rimraf versions prior to v4 are no longer supported\n    hasBin: true\n\n  rimraf@3.0.2:\n    resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}\n    deprecated: Rimraf versions prior to v4 are no longer supported\n    hasBin: true\n\n  rollup@3.29.5:\n    resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==}\n    engines: {node: '>=14.18.0', npm: '>=8.0.0'}\n    hasBin: true\n\n  run-async@2.4.1:\n    resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}\n    engines: {node: '>=0.12.0'}\n\n  run-parallel@1.2.0:\n    resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}\n\n  rxjs@6.6.7:\n    resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==}\n    engines: {npm: '>=2.0.0'}\n\n  safe-array-concat@1.1.3:\n    resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}\n    engines: {node: '>=0.4'}\n\n  safe-buffer@5.2.1:\n    resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}\n\n  safe-push-apply@1.0.0:\n    resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}\n    engines: {node: '>= 0.4'}\n\n  safe-regex-test@1.1.0:\n    resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==}\n    engines: {node: '>= 0.4'}\n\n  safer-buffer@2.1.2:\n    resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}\n\n  saxes@5.0.1:\n    resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==}\n    engines: {node: '>=10'}\n\n  semver@5.7.2:\n    resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}\n    hasBin: true\n\n  semver@6.3.1:\n    resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}\n    hasBin: true\n\n  semver@7.7.1:\n    resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==}\n    engines: {node: '>=10'}\n    hasBin: true\n\n  send@0.19.0:\n    resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==}\n    engines: {node: '>= 0.8.0'}\n\n  serve-static@1.16.2:\n    resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==}\n    engines: {node: '>= 0.8.0'}\n\n  set-blocking@2.0.0:\n    resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}\n\n  set-function-length@1.2.2:\n    resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}\n    engines: {node: '>= 0.4'}\n\n  set-function-name@2.0.2:\n    resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==}\n    engines: {node: '>= 0.4'}\n\n  set-proto@1.0.0:\n    resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}\n    engines: {node: '>= 0.4'}\n\n  setprototypeof@1.2.0:\n    resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}\n\n  shebang-command@1.2.0:\n    resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==}\n    engines: {node: '>=0.10.0'}\n\n  shebang-command@2.0.0:\n    resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}\n    engines: {node: '>=8'}\n\n  shebang-regex@1.0.0:\n    resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==}\n    engines: {node: '>=0.10.0'}\n\n  shebang-regex@3.0.0:\n    resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}\n    engines: {node: '>=8'}\n\n  side-channel-list@1.0.0:\n    resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==}\n    engines: {node: '>= 0.4'}\n\n  side-channel-map@1.0.1:\n    resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==}\n    engines: {node: '>= 0.4'}\n\n  side-channel-weakmap@1.0.2:\n    resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==}\n    engines: {node: '>= 0.4'}\n\n  side-channel@1.1.0:\n    resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}\n    engines: {node: '>= 0.4'}\n\n  signal-exit@3.0.7:\n    resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}\n\n  sisteransi@1.0.5:\n    resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}\n\n  slash@3.0.0:\n    resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}\n    engines: {node: '>=8'}\n\n  slice-ansi@2.1.0:\n    resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==}\n    engines: {node: '>=6'}\n\n  sort-object-keys@1.1.3:\n    resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==}\n\n  sort-package-json@1.57.0:\n    resolution: {integrity: sha512-FYsjYn2dHTRb41wqnv+uEqCUvBpK3jZcTp9rbz2qDTmel7Pmdtf+i2rLaaPMRZeSVM60V3Se31GyWFpmKs4Q5Q==}\n    hasBin: true\n\n  source-map-support@0.5.21:\n    resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}\n\n  source-map@0.6.1:\n    resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}\n    engines: {node: '>=0.10.0'}\n\n  source-map@0.7.4:\n    resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}\n    engines: {node: '>= 8'}\n\n  spawn-wrap@2.0.0:\n    resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==}\n    engines: {node: '>=8'}\n\n  spdx-correct@3.2.0:\n    resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==}\n\n  spdx-exceptions@2.5.0:\n    resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==}\n\n  spdx-expression-parse@3.0.1:\n    resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}\n\n  spdx-license-ids@3.0.21:\n    resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==}\n\n  sprintf-js@1.0.3:\n    resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}\n\n  stack-utils@2.0.6:\n    resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}\n    engines: {node: '>=10'}\n\n  statuses@1.5.0:\n    resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}\n    engines: {node: '>= 0.6'}\n\n  statuses@2.0.1:\n    resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}\n    engines: {node: '>= 0.8'}\n\n  string-length@4.0.2:\n    resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}\n    engines: {node: '>=10'}\n\n  string-width@3.1.0:\n    resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==}\n    engines: {node: '>=6'}\n\n  string-width@4.2.3:\n    resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}\n    engines: {node: '>=8'}\n\n  string.prototype.trim@1.2.10:\n    resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==}\n    engines: {node: '>= 0.4'}\n\n  string.prototype.trimend@1.0.9:\n    resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==}\n    engines: {node: '>= 0.4'}\n\n  string.prototype.trimstart@1.0.8:\n    resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}\n    engines: {node: '>= 0.4'}\n\n  string_decoder@1.3.0:\n    resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}\n\n  strip-ansi@5.2.0:\n    resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==}\n    engines: {node: '>=6'}\n\n  strip-ansi@6.0.1:\n    resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}\n    engines: {node: '>=8'}\n\n  strip-bom@3.0.0:\n    resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}\n    engines: {node: '>=4'}\n\n  strip-bom@4.0.0:\n    resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}\n    engines: {node: '>=8'}\n\n  strip-final-newline@2.0.0:\n    resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}\n    engines: {node: '>=6'}\n\n  strip-json-comments@3.1.1:\n    resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}\n    engines: {node: '>=8'}\n\n  superagent@6.1.0:\n    resolution: {integrity: sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==}\n    engines: {node: '>= 7.0.0'}\n    deprecated: Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net\n\n  supertest@6.1.6:\n    resolution: {integrity: sha512-0hACYGNJ8OHRg8CRITeZOdbjur7NLuNs0mBjVhdpxi7hP6t3QIbOzLON5RTUmZcy2I9riuII3+Pr2C7yztrIIg==}\n    engines: {node: '>=6.0.0'}\n\n  supports-color@5.5.0:\n    resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}\n    engines: {node: '>=4'}\n\n  supports-color@7.2.0:\n    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}\n    engines: {node: '>=8'}\n\n  supports-color@8.1.1:\n    resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}\n    engines: {node: '>=10'}\n\n  supports-hyperlinks@2.3.0:\n    resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==}\n    engines: {node: '>=8'}\n\n  supports-preserve-symlinks-flag@1.0.0:\n    resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}\n    engines: {node: '>= 0.4'}\n\n  symbol-tree@3.2.4:\n    resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}\n\n  table@5.4.6:\n    resolution: {integrity: sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==}\n    engines: {node: '>=6.0.0'}\n\n  terminal-link@2.1.1:\n    resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==}\n    engines: {node: '>=8'}\n\n  test-exclude@6.0.0:\n    resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}\n    engines: {node: '>=8'}\n\n  text-table@0.2.0:\n    resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}\n\n  throat@6.0.2:\n    resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==}\n\n  through@2.3.8:\n    resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}\n\n  tmp@0.0.33:\n    resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}\n    engines: {node: '>=0.6.0'}\n\n  tmpl@1.0.5:\n    resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}\n\n  to-regex-range@5.0.1:\n    resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}\n    engines: {node: '>=8.0'}\n\n  toidentifier@1.0.1:\n    resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}\n    engines: {node: '>=0.6'}\n\n  tough-cookie@4.1.4:\n    resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}\n    engines: {node: '>=6'}\n\n  tr46@2.1.0:\n    resolution: {integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==}\n    engines: {node: '>=8'}\n\n  tslib@1.14.1:\n    resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}\n\n  tsscmp@1.0.6:\n    resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==}\n    engines: {node: '>=0.6.x'}\n\n  type-check@0.3.2:\n    resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==}\n    engines: {node: '>= 0.8.0'}\n\n  type-detect@4.0.8:\n    resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}\n    engines: {node: '>=4'}\n\n  type-fest@0.21.3:\n    resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}\n    engines: {node: '>=10'}\n\n  type-fest@0.8.1:\n    resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}\n    engines: {node: '>=8'}\n\n  type-is@1.6.18:\n    resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}\n    engines: {node: '>= 0.6'}\n\n  typed-array-buffer@1.0.3:\n    resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}\n    engines: {node: '>= 0.4'}\n\n  typed-array-byte-length@1.0.3:\n    resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==}\n    engines: {node: '>= 0.4'}\n\n  typed-array-byte-offset@1.0.4:\n    resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==}\n    engines: {node: '>= 0.4'}\n\n  typed-array-length@1.0.7:\n    resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==}\n    engines: {node: '>= 0.4'}\n\n  typedarray-to-buffer@3.1.5:\n    resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}\n\n  unbox-primitive@1.1.0:\n    resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==}\n    engines: {node: '>= 0.4'}\n\n  undici-types@6.21.0:\n    resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}\n\n  universalify@0.2.0:\n    resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}\n    engines: {node: '>= 4.0.0'}\n\n  unpipe@1.0.0:\n    resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}\n    engines: {node: '>= 0.8'}\n\n  update-browserslist-db@1.1.3:\n    resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}\n    hasBin: true\n    peerDependencies:\n      browserslist: '>= 4.21.0'\n\n  uri-js@4.4.1:\n    resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}\n\n  url-parse@1.5.10:\n    resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}\n\n  util-deprecate@1.0.2:\n    resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}\n\n  utils-merge@1.0.1:\n    resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}\n    engines: {node: '>= 0.4.0'}\n\n  uuid@8.3.2:\n    resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}\n    hasBin: true\n\n  v8-compile-cache@2.4.0:\n    resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==}\n\n  v8-to-istanbul@8.1.1:\n    resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==}\n    engines: {node: '>=10.12.0'}\n\n  validate-npm-package-license@3.0.4:\n    resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}\n\n  vary@1.1.2:\n    resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}\n    engines: {node: '>= 0.8'}\n\n  w3c-hr-time@1.0.2:\n    resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}\n    deprecated: Use your platform's native performance.now() and performance.timeOrigin.\n\n  w3c-xmlserializer@2.0.0:\n    resolution: {integrity: sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==}\n    engines: {node: '>=10'}\n\n  walker@1.0.8:\n    resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}\n\n  web-streams-polyfill@3.3.3:\n    resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}\n    engines: {node: '>= 8'}\n\n  webidl-conversions@5.0.0:\n    resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==}\n    engines: {node: '>=8'}\n\n  webidl-conversions@6.1.0:\n    resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==}\n    engines: {node: '>=10.4'}\n\n  whatwg-encoding@1.0.5:\n    resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==}\n\n  whatwg-mimetype@2.3.0:\n    resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==}\n\n  whatwg-url@8.7.0:\n    resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==}\n    engines: {node: '>=10'}\n\n  which-boxed-primitive@1.1.1:\n    resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}\n    engines: {node: '>= 0.4'}\n\n  which-builtin-type@1.2.1:\n    resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==}\n    engines: {node: '>= 0.4'}\n\n  which-collection@1.0.2:\n    resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==}\n    engines: {node: '>= 0.4'}\n\n  which-module@2.0.1:\n    resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==}\n\n  which-typed-array@1.1.19:\n    resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==}\n    engines: {node: '>= 0.4'}\n\n  which@1.3.1:\n    resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}\n    hasBin: true\n\n  which@2.0.2:\n    resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}\n    engines: {node: '>= 8'}\n    hasBin: true\n\n  word-wrap@1.2.5:\n    resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}\n    engines: {node: '>=0.10.0'}\n\n  wrap-ansi@6.2.0:\n    resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}\n    engines: {node: '>=8'}\n\n  wrap-ansi@7.0.0:\n    resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}\n    engines: {node: '>=10'}\n\n  wrappy@1.0.2:\n    resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}\n\n  write-file-atomic@3.0.3:\n    resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}\n\n  write@1.0.3:\n    resolution: {integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==}\n    engines: {node: '>=4'}\n\n  ws@7.5.10:\n    resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==}\n    engines: {node: '>=8.3.0'}\n    peerDependencies:\n      bufferutil: ^4.0.1\n      utf-8-validate: ^5.0.2\n    peerDependenciesMeta:\n      bufferutil:\n        optional: true\n      utf-8-validate:\n        optional: true\n\n  xml-name-validator@3.0.0:\n    resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==}\n\n  xmlchars@2.2.0:\n    resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}\n\n  y18n@4.0.3:\n    resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}\n\n  y18n@5.0.8:\n    resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}\n    engines: {node: '>=10'}\n\n  yallist@3.1.1:\n    resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}\n\n  yargs-parser@18.1.3:\n    resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}\n    engines: {node: '>=6'}\n\n  yargs-parser@20.2.9:\n    resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}\n    engines: {node: '>=10'}\n\n  yargs@15.4.1:\n    resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}\n    engines: {node: '>=8'}\n\n  yargs@16.2.0:\n    resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}\n    engines: {node: '>=10'}\n\n  ylru@1.4.0:\n    resolution: {integrity: sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA==}\n    engines: {node: '>= 4.0.0'}\n\nsnapshots:\n\n  '@ampproject/remapping@2.3.0':\n    dependencies:\n      '@jridgewell/gen-mapping': 0.3.8\n      '@jridgewell/trace-mapping': 0.3.25\n\n  '@babel/code-frame@7.26.2':\n    dependencies:\n      '@babel/helper-validator-identifier': 7.25.9\n      js-tokens: 4.0.0\n      picocolors: 1.1.1\n\n  '@babel/compat-data@7.26.8': {}\n\n  '@babel/core@7.26.10':\n    dependencies:\n      '@ampproject/remapping': 2.3.0\n      '@babel/code-frame': 7.26.2\n      '@babel/generator': 7.27.0\n      '@babel/helper-compilation-targets': 7.27.0\n      '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10)\n      '@babel/helpers': 7.27.0\n      '@babel/parser': 7.27.0\n      '@babel/template': 7.27.0\n      '@babel/traverse': 7.27.0\n      '@babel/types': 7.27.0\n      convert-source-map: 2.0.0\n      debug: 4.4.0\n      gensync: 1.0.0-beta.2\n      json5: 2.2.3\n      semver: 6.3.1\n    transitivePeerDependencies:\n      - supports-color\n\n  '@babel/generator@7.27.0':\n    dependencies:\n      '@babel/parser': 7.27.0\n      '@babel/types': 7.27.0\n      '@jridgewell/gen-mapping': 0.3.8\n      '@jridgewell/trace-mapping': 0.3.25\n      jsesc: 3.1.0\n\n  '@babel/helper-compilation-targets@7.27.0':\n    dependencies:\n      '@babel/compat-data': 7.26.8\n      '@babel/helper-validator-option': 7.25.9\n      browserslist: 4.24.4\n      lru-cache: 5.1.1\n      semver: 6.3.1\n\n  '@babel/helper-module-imports@7.25.9':\n    dependencies:\n      '@babel/traverse': 7.27.0\n      '@babel/types': 7.27.0\n    transitivePeerDependencies:\n      - supports-color\n\n  '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-module-imports': 7.25.9\n      '@babel/helper-validator-identifier': 7.25.9\n      '@babel/traverse': 7.27.0\n    transitivePeerDependencies:\n      - supports-color\n\n  '@babel/helper-plugin-utils@7.26.5': {}\n\n  '@babel/helper-string-parser@7.25.9': {}\n\n  '@babel/helper-validator-identifier@7.25.9': {}\n\n  '@babel/helper-validator-option@7.25.9': {}\n\n  '@babel/helpers@7.27.0':\n    dependencies:\n      '@babel/template': 7.27.0\n      '@babel/types': 7.27.0\n\n  '@babel/parser@7.27.0':\n    dependencies:\n      '@babel/types': 7.27.0\n\n  '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.10)':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/helper-plugin-utils': 7.26.5\n\n  '@babel/template@7.27.0':\n    dependencies:\n      '@babel/code-frame': 7.26.2\n      '@babel/parser': 7.27.0\n      '@babel/types': 7.27.0\n\n  '@babel/traverse@7.27.0':\n    dependencies:\n      '@babel/code-frame': 7.26.2\n      '@babel/generator': 7.27.0\n      '@babel/parser': 7.27.0\n      '@babel/template': 7.27.0\n      '@babel/types': 7.27.0\n      debug: 4.4.0\n      globals: 11.12.0\n    transitivePeerDependencies:\n      - supports-color\n\n  '@babel/types@7.27.0':\n    dependencies:\n      '@babel/helper-string-parser': 7.25.9\n      '@babel/helper-validator-identifier': 7.25.9\n\n  '@bcoe/v8-coverage@0.2.3': {}\n\n  '@istanbuljs/load-nyc-config@1.1.0':\n    dependencies:\n      camelcase: 5.3.1\n      find-up: 4.1.0\n      get-package-type: 0.1.0\n      js-yaml: 3.14.1\n      resolve-from: 5.0.0\n\n  '@istanbuljs/schema@0.1.3': {}\n\n  '@jest/console@27.5.1':\n    dependencies:\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      chalk: 4.1.2\n      jest-message-util: 27.5.1\n      jest-util: 27.5.1\n      slash: 3.0.0\n\n  '@jest/core@27.5.1':\n    dependencies:\n      '@jest/console': 27.5.1\n      '@jest/reporters': 27.5.1\n      '@jest/test-result': 27.5.1\n      '@jest/transform': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      ansi-escapes: 4.3.2\n      chalk: 4.1.2\n      emittery: 0.8.1\n      exit: 0.1.2\n      graceful-fs: 4.2.11\n      jest-changed-files: 27.5.1\n      jest-config: 27.5.1\n      jest-haste-map: 27.5.1\n      jest-message-util: 27.5.1\n      jest-regex-util: 27.5.1\n      jest-resolve: 27.5.1\n      jest-resolve-dependencies: 27.5.1\n      jest-runner: 27.5.1\n      jest-runtime: 27.5.1\n      jest-snapshot: 27.5.1\n      jest-util: 27.5.1\n      jest-validate: 27.5.1\n      jest-watcher: 27.5.1\n      micromatch: 4.0.8\n      rimraf: 3.0.2\n      slash: 3.0.0\n      strip-ansi: 6.0.1\n    transitivePeerDependencies:\n      - bufferutil\n      - canvas\n      - supports-color\n      - ts-node\n      - utf-8-validate\n\n  '@jest/environment@27.5.1':\n    dependencies:\n      '@jest/fake-timers': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      jest-mock: 27.5.1\n\n  '@jest/fake-timers@27.5.1':\n    dependencies:\n      '@jest/types': 27.5.1\n      '@sinonjs/fake-timers': 8.1.0\n      '@types/node': 22.14.1\n      jest-message-util: 27.5.1\n      jest-mock: 27.5.1\n      jest-util: 27.5.1\n\n  '@jest/globals@27.5.1':\n    dependencies:\n      '@jest/environment': 27.5.1\n      '@jest/types': 27.5.1\n      expect: 27.5.1\n\n  '@jest/reporters@27.5.1':\n    dependencies:\n      '@bcoe/v8-coverage': 0.2.3\n      '@jest/console': 27.5.1\n      '@jest/test-result': 27.5.1\n      '@jest/transform': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      chalk: 4.1.2\n      collect-v8-coverage: 1.0.2\n      exit: 0.1.2\n      glob: 7.2.3\n      graceful-fs: 4.2.11\n      istanbul-lib-coverage: 3.2.2\n      istanbul-lib-instrument: 5.2.1\n      istanbul-lib-report: 3.0.1\n      istanbul-lib-source-maps: 4.0.1\n      istanbul-reports: 3.1.7\n      jest-haste-map: 27.5.1\n      jest-resolve: 27.5.1\n      jest-util: 27.5.1\n      jest-worker: 27.5.1\n      slash: 3.0.0\n      source-map: 0.6.1\n      string-length: 4.0.2\n      terminal-link: 2.1.1\n      v8-to-istanbul: 8.1.1\n    transitivePeerDependencies:\n      - supports-color\n\n  '@jest/source-map@27.5.1':\n    dependencies:\n      callsites: 3.1.0\n      graceful-fs: 4.2.11\n      source-map: 0.6.1\n\n  '@jest/test-result@27.5.1':\n    dependencies:\n      '@jest/console': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/istanbul-lib-coverage': 2.0.6\n      collect-v8-coverage: 1.0.2\n\n  '@jest/test-sequencer@27.5.1':\n    dependencies:\n      '@jest/test-result': 27.5.1\n      graceful-fs: 4.2.11\n      jest-haste-map: 27.5.1\n      jest-runtime: 27.5.1\n    transitivePeerDependencies:\n      - supports-color\n\n  '@jest/transform@27.5.1':\n    dependencies:\n      '@babel/core': 7.26.10\n      '@jest/types': 27.5.1\n      babel-plugin-istanbul: 6.1.1\n      chalk: 4.1.2\n      convert-source-map: 1.9.0\n      fast-json-stable-stringify: 2.1.0\n      graceful-fs: 4.2.11\n      jest-haste-map: 27.5.1\n      jest-regex-util: 27.5.1\n      jest-util: 27.5.1\n      micromatch: 4.0.8\n      pirates: 4.0.7\n      slash: 3.0.0\n      source-map: 0.6.1\n      write-file-atomic: 3.0.3\n    transitivePeerDependencies:\n      - supports-color\n\n  '@jest/types@27.5.1':\n    dependencies:\n      '@types/istanbul-lib-coverage': 2.0.6\n      '@types/istanbul-reports': 3.0.4\n      '@types/node': 22.14.1\n      '@types/yargs': 16.0.9\n      chalk: 4.1.2\n\n  '@jridgewell/gen-mapping@0.3.8':\n    dependencies:\n      '@jridgewell/set-array': 1.2.1\n      '@jridgewell/sourcemap-codec': 1.5.0\n      '@jridgewell/trace-mapping': 0.3.25\n\n  '@jridgewell/resolve-uri@3.1.2': {}\n\n  '@jridgewell/set-array@1.2.1': {}\n\n  '@jridgewell/sourcemap-codec@1.5.0': {}\n\n  '@jridgewell/trace-mapping@0.3.25':\n    dependencies:\n      '@jridgewell/resolve-uri': 3.1.2\n      '@jridgewell/sourcemap-codec': 1.5.0\n\n  '@noble/hashes@1.8.0': {}\n\n  '@nodelib/fs.scandir@2.1.5':\n    dependencies:\n      '@nodelib/fs.stat': 2.0.5\n      run-parallel: 1.2.0\n\n  '@nodelib/fs.stat@2.0.5': {}\n\n  '@nodelib/fs.walk@1.2.8':\n    dependencies:\n      '@nodelib/fs.scandir': 2.1.5\n      fastq: 1.19.1\n\n  '@paralleldrive/cuid2@2.2.2':\n    dependencies:\n      '@noble/hashes': 1.8.0\n\n  '@rollup/plugin-commonjs@25.0.8(rollup@3.29.5)':\n    dependencies:\n      '@rollup/pluginutils': 5.1.4(rollup@3.29.5)\n      commondir: 1.0.1\n      estree-walker: 2.0.2\n      glob: 8.1.0\n      is-reference: 1.2.1\n      magic-string: 0.30.17\n    optionalDependencies:\n      rollup: 3.29.5\n\n  '@rollup/plugin-node-resolve@15.3.1(rollup@3.29.5)':\n    dependencies:\n      '@rollup/pluginutils': 5.1.4(rollup@3.29.5)\n      '@types/resolve': 1.20.2\n      deepmerge: 4.3.1\n      is-module: 1.0.0\n      resolve: 1.22.10\n    optionalDependencies:\n      rollup: 3.29.5\n\n  '@rollup/pluginutils@5.1.4(rollup@3.29.5)':\n    dependencies:\n      '@types/estree': 1.0.7\n      estree-walker: 2.0.2\n      picomatch: 4.0.2\n    optionalDependencies:\n      rollup: 3.29.5\n\n  '@sindresorhus/slugify@2.2.1':\n    dependencies:\n      '@sindresorhus/transliterate': 1.6.0\n      escape-string-regexp: 5.0.0\n\n  '@sindresorhus/transliterate@1.6.0':\n    dependencies:\n      escape-string-regexp: 5.0.0\n\n  '@sinonjs/commons@1.8.6':\n    dependencies:\n      type-detect: 4.0.8\n\n  '@sinonjs/fake-timers@8.1.0':\n    dependencies:\n      '@sinonjs/commons': 1.8.6\n\n  '@tootallnate/once@1.1.2': {}\n\n  '@tunnckocore/prettier-config@1.3.8(prettier-plugin-pkgjson@0.2.8(prettier@2.0.5))(prettier@2.0.5)':\n    dependencies:\n      prettier: 2.0.5\n      prettier-plugin-pkgjson: 0.2.8(prettier@2.0.5)\n\n  '@types/babel__core@7.20.5':\n    dependencies:\n      '@babel/parser': 7.27.0\n      '@babel/types': 7.27.0\n      '@types/babel__generator': 7.27.0\n      '@types/babel__template': 7.4.4\n      '@types/babel__traverse': 7.20.7\n\n  '@types/babel__generator@7.27.0':\n    dependencies:\n      '@babel/types': 7.27.0\n\n  '@types/babel__template@7.4.4':\n    dependencies:\n      '@babel/parser': 7.27.0\n      '@babel/types': 7.27.0\n\n  '@types/babel__traverse@7.20.7':\n    dependencies:\n      '@babel/types': 7.27.0\n\n  '@types/estree@1.0.7': {}\n\n  '@types/glob@7.2.0':\n    dependencies:\n      '@types/minimatch': 5.1.2\n      '@types/node': 22.14.1\n\n  '@types/graceful-fs@4.1.9':\n    dependencies:\n      '@types/node': 22.14.1\n\n  '@types/istanbul-lib-coverage@2.0.6': {}\n\n  '@types/istanbul-lib-report@3.0.3':\n    dependencies:\n      '@types/istanbul-lib-coverage': 2.0.6\n\n  '@types/istanbul-reports@3.0.4':\n    dependencies:\n      '@types/istanbul-lib-report': 3.0.3\n\n  '@types/minimatch@5.1.2': {}\n\n  '@types/node@22.14.1':\n    dependencies:\n      undici-types: 6.21.0\n\n  '@types/prettier@2.7.3': {}\n\n  '@types/resolve@1.20.2': {}\n\n  '@types/stack-utils@2.0.3': {}\n\n  '@types/yargs-parser@21.0.3': {}\n\n  '@types/yargs@16.0.9':\n    dependencies:\n      '@types/yargs-parser': 21.0.3\n\n  abab@2.0.6: {}\n\n  accepts@1.3.8:\n    dependencies:\n      mime-types: 2.1.35\n      negotiator: 0.6.3\n\n  acorn-globals@6.0.0:\n    dependencies:\n      acorn: 7.4.1\n      acorn-walk: 7.2.0\n\n  acorn-jsx@5.3.2(acorn@7.4.1):\n    dependencies:\n      acorn: 7.4.1\n\n  acorn-walk@7.2.0: {}\n\n  acorn@7.4.1: {}\n\n  acorn@8.14.1: {}\n\n  agent-base@6.0.2:\n    dependencies:\n      debug: 4.4.0\n    transitivePeerDependencies:\n      - supports-color\n\n  aggregate-error@3.1.0:\n    dependencies:\n      clean-stack: 2.2.0\n      indent-string: 4.0.0\n\n  ajv@6.12.6:\n    dependencies:\n      fast-deep-equal: 3.1.3\n      fast-json-stable-stringify: 2.1.0\n      json-schema-traverse: 0.4.1\n      uri-js: 4.4.1\n\n  ansi-escapes@4.3.2:\n    dependencies:\n      type-fest: 0.21.3\n\n  ansi-regex@4.1.1: {}\n\n  ansi-regex@5.0.1: {}\n\n  ansi-styles@3.2.1:\n    dependencies:\n      color-convert: 1.9.3\n\n  ansi-styles@4.3.0:\n    dependencies:\n      color-convert: 2.0.1\n\n  ansi-styles@5.2.0: {}\n\n  anymatch@3.1.3:\n    dependencies:\n      normalize-path: 3.0.0\n      picomatch: 2.3.1\n\n  append-transform@2.0.0:\n    dependencies:\n      default-require-extensions: 3.0.1\n\n  archy@1.0.0: {}\n\n  argparse@1.0.10:\n    dependencies:\n      sprintf-js: 1.0.3\n\n  array-buffer-byte-length@1.0.2:\n    dependencies:\n      call-bound: 1.0.4\n      is-array-buffer: 3.0.5\n\n  array-flatten@1.1.1: {}\n\n  array-includes@3.1.8:\n    dependencies:\n      call-bind: 1.0.8\n      define-properties: 1.2.1\n      es-abstract: 1.23.9\n      es-object-atoms: 1.1.1\n      get-intrinsic: 1.3.0\n      is-string: 1.1.1\n\n  array-union@2.1.0: {}\n\n  array.prototype.flat@1.3.3:\n    dependencies:\n      call-bind: 1.0.8\n      define-properties: 1.2.1\n      es-abstract: 1.23.9\n      es-shim-unscopables: 1.1.0\n\n  arraybuffer.prototype.slice@1.0.4:\n    dependencies:\n      array-buffer-byte-length: 1.0.2\n      call-bind: 1.0.8\n      define-properties: 1.2.1\n      es-abstract: 1.23.9\n      es-errors: 1.3.0\n      get-intrinsic: 1.3.0\n      is-array-buffer: 3.0.5\n\n  asap@2.0.6: {}\n\n  astral-regex@1.0.0: {}\n\n  async-function@1.0.0: {}\n\n  asynckit@0.4.0: {}\n\n  available-typed-arrays@1.0.7:\n    dependencies:\n      possible-typed-array-names: 1.1.0\n\n  babel-jest@27.5.1(@babel/core@7.26.10):\n    dependencies:\n      '@babel/core': 7.26.10\n      '@jest/transform': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/babel__core': 7.20.5\n      babel-plugin-istanbul: 6.1.1\n      babel-preset-jest: 27.5.1(@babel/core@7.26.10)\n      chalk: 4.1.2\n      graceful-fs: 4.2.11\n      slash: 3.0.0\n    transitivePeerDependencies:\n      - supports-color\n\n  babel-plugin-istanbul@6.1.1:\n    dependencies:\n      '@babel/helper-plugin-utils': 7.26.5\n      '@istanbuljs/load-nyc-config': 1.1.0\n      '@istanbuljs/schema': 0.1.3\n      istanbul-lib-instrument: 5.2.1\n      test-exclude: 6.0.0\n    transitivePeerDependencies:\n      - supports-color\n\n  babel-plugin-jest-hoist@27.5.1:\n    dependencies:\n      '@babel/template': 7.27.0\n      '@babel/types': 7.27.0\n      '@types/babel__core': 7.20.5\n      '@types/babel__traverse': 7.20.7\n\n  babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.10):\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.10)\n      '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.10)\n      '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.10)\n      '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.10)\n      '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.10)\n      '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.10)\n      '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.10)\n      '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.10)\n      '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.10)\n      '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.10)\n      '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.10)\n      '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.10)\n      '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.10)\n      '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.10)\n      '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.10)\n\n  babel-preset-jest@27.5.1(@babel/core@7.26.10):\n    dependencies:\n      '@babel/core': 7.26.10\n      babel-plugin-jest-hoist: 27.5.1\n      babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.10)\n\n  balanced-match@1.0.2: {}\n\n  body-parser@1.20.3:\n    dependencies:\n      bytes: 3.1.2\n      content-type: 1.0.5\n      debug: 2.6.9\n      depd: 2.0.0\n      destroy: 1.2.0\n      http-errors: 2.0.0\n      iconv-lite: 0.4.24\n      on-finished: 2.4.1\n      qs: 6.13.0\n      raw-body: 2.5.2\n      type-is: 1.6.18\n      unpipe: 1.0.0\n    transitivePeerDependencies:\n      - supports-color\n\n  brace-expansion@1.1.11:\n    dependencies:\n      balanced-match: 1.0.2\n      concat-map: 0.0.1\n\n  brace-expansion@2.0.1:\n    dependencies:\n      balanced-match: 1.0.2\n\n  braces@3.0.3:\n    dependencies:\n      fill-range: 7.1.1\n\n  browser-process-hrtime@1.0.0: {}\n\n  browserslist@4.24.4:\n    dependencies:\n      caniuse-lite: 1.0.30001715\n      electron-to-chromium: 1.5.140\n      node-releases: 2.0.19\n      update-browserslist-db: 1.1.3(browserslist@4.24.4)\n\n  bser@2.1.1:\n    dependencies:\n      node-int64: 0.4.0\n\n  buffer-from@1.1.2: {}\n\n  bytes@3.1.2: {}\n\n  cache-content-type@1.0.1:\n    dependencies:\n      mime-types: 2.1.35\n      ylru: 1.4.0\n\n  caching-transform@4.0.0:\n    dependencies:\n      hasha: 5.2.2\n      make-dir: 3.1.0\n      package-hash: 4.0.0\n      write-file-atomic: 3.0.3\n\n  call-bind-apply-helpers@1.0.2:\n    dependencies:\n      es-errors: 1.3.0\n      function-bind: 1.1.2\n\n  call-bind@1.0.8:\n    dependencies:\n      call-bind-apply-helpers: 1.0.2\n      es-define-property: 1.0.1\n      get-intrinsic: 1.3.0\n      set-function-length: 1.2.2\n\n  call-bound@1.0.4:\n    dependencies:\n      call-bind-apply-helpers: 1.0.2\n      get-intrinsic: 1.3.0\n\n  callsites@3.1.0: {}\n\n  camelcase@5.3.1: {}\n\n  camelcase@6.3.0: {}\n\n  caniuse-lite@1.0.30001715: {}\n\n  chalk@2.4.2:\n    dependencies:\n      ansi-styles: 3.2.1\n      escape-string-regexp: 1.0.5\n      supports-color: 5.5.0\n\n  chalk@4.1.2:\n    dependencies:\n      ansi-styles: 4.3.0\n      supports-color: 7.2.0\n\n  char-regex@1.0.2: {}\n\n  chardet@0.7.0: {}\n\n  ci-info@3.9.0: {}\n\n  cjs-module-lexer@1.4.3: {}\n\n  clean-stack@2.2.0: {}\n\n  cli-cursor@3.1.0:\n    dependencies:\n      restore-cursor: 3.1.0\n\n  cli-width@3.0.0: {}\n\n  cliui@6.0.0:\n    dependencies:\n      string-width: 4.2.3\n      strip-ansi: 6.0.1\n      wrap-ansi: 6.2.0\n\n  cliui@7.0.4:\n    dependencies:\n      string-width: 4.2.3\n      strip-ansi: 6.0.1\n      wrap-ansi: 7.0.0\n\n  co@4.6.0: {}\n\n  collect-v8-coverage@1.0.2: {}\n\n  color-convert@1.9.3:\n    dependencies:\n      color-name: 1.1.3\n\n  color-convert@2.0.1:\n    dependencies:\n      color-name: 1.1.4\n\n  color-name@1.1.3: {}\n\n  color-name@1.1.4: {}\n\n  combined-stream@1.0.8:\n    dependencies:\n      delayed-stream: 1.0.0\n\n  commondir@1.0.1: {}\n\n  component-emitter@1.3.1: {}\n\n  concat-map@0.0.1: {}\n\n  confusing-browser-globals@1.0.11: {}\n\n  contains-path@0.1.0: {}\n\n  content-disposition@0.5.4:\n    dependencies:\n      safe-buffer: 5.2.1\n\n  content-type@1.0.5: {}\n\n  convert-source-map@1.9.0: {}\n\n  convert-source-map@2.0.0: {}\n\n  cookie-signature@1.0.6: {}\n\n  cookie@0.7.1: {}\n\n  cookiejar@2.1.4: {}\n\n  cookies@0.9.1:\n    dependencies:\n      depd: 2.0.0\n      keygrip: 1.1.0\n\n  cross-spawn@6.0.6:\n    dependencies:\n      nice-try: 1.0.5\n      path-key: 2.0.1\n      semver: 5.7.2\n      shebang-command: 1.2.0\n      which: 1.3.1\n\n  cross-spawn@7.0.6:\n    dependencies:\n      path-key: 3.1.1\n      shebang-command: 2.0.0\n      which: 2.0.2\n\n  cssom@0.3.8: {}\n\n  cssom@0.4.4: {}\n\n  cssstyle@2.3.0:\n    dependencies:\n      cssom: 0.3.8\n\n  data-urls@2.0.0:\n    dependencies:\n      abab: 2.0.6\n      whatwg-mimetype: 2.3.0\n      whatwg-url: 8.7.0\n\n  data-view-buffer@1.0.2:\n    dependencies:\n      call-bound: 1.0.4\n      es-errors: 1.3.0\n      is-data-view: 1.0.2\n\n  data-view-byte-length@1.0.2:\n    dependencies:\n      call-bound: 1.0.4\n      es-errors: 1.3.0\n      is-data-view: 1.0.2\n\n  data-view-byte-offset@1.0.1:\n    dependencies:\n      call-bound: 1.0.4\n      es-errors: 1.3.0\n      is-data-view: 1.0.2\n\n  debug@2.6.9:\n    dependencies:\n      ms: 2.0.0\n\n  debug@3.2.7:\n    dependencies:\n      ms: 2.1.3\n\n  debug@4.4.0:\n    dependencies:\n      ms: 2.1.3\n\n  decamelize@1.2.0: {}\n\n  decimal.js@10.5.0: {}\n\n  dedent@0.7.0: {}\n\n  deep-equal@1.0.1: {}\n\n  deep-is@0.1.4: {}\n\n  deepmerge@4.3.1: {}\n\n  default-require-extensions@3.0.1:\n    dependencies:\n      strip-bom: 4.0.0\n\n  define-data-property@1.1.4:\n    dependencies:\n      es-define-property: 1.0.1\n      es-errors: 1.3.0\n      gopd: 1.2.0\n\n  define-properties@1.2.1:\n    dependencies:\n      define-data-property: 1.1.4\n      has-property-descriptors: 1.0.2\n      object-keys: 1.1.1\n\n  delayed-stream@1.0.0: {}\n\n  delegates@1.0.0: {}\n\n  depd@1.1.2: {}\n\n  depd@2.0.0: {}\n\n  destroy@1.2.0: {}\n\n  detect-indent@6.1.0: {}\n\n  detect-newline@3.1.0: {}\n\n  dezalgo@1.0.4:\n    dependencies:\n      asap: 2.0.6\n      wrappy: 1.0.2\n\n  diff-sequences@27.5.1: {}\n\n  dir-glob@3.0.1:\n    dependencies:\n      path-type: 4.0.0\n\n  doctrine@1.5.0:\n    dependencies:\n      esutils: 2.0.3\n      isarray: 1.0.0\n\n  doctrine@3.0.0:\n    dependencies:\n      esutils: 2.0.3\n\n  domexception@2.0.1:\n    dependencies:\n      webidl-conversions: 5.0.0\n\n  dunder-proto@1.0.1:\n    dependencies:\n      call-bind-apply-helpers: 1.0.2\n      es-errors: 1.3.0\n      gopd: 1.2.0\n\n  ee-first@1.1.1: {}\n\n  electron-to-chromium@1.5.140: {}\n\n  emittery@0.8.1: {}\n\n  emoji-regex@7.0.3: {}\n\n  emoji-regex@8.0.0: {}\n\n  encodeurl@1.0.2: {}\n\n  encodeurl@2.0.0: {}\n\n  error-ex@1.3.2:\n    dependencies:\n      is-arrayish: 0.2.1\n\n  es-abstract@1.23.9:\n    dependencies:\n      array-buffer-byte-length: 1.0.2\n      arraybuffer.prototype.slice: 1.0.4\n      available-typed-arrays: 1.0.7\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      data-view-buffer: 1.0.2\n      data-view-byte-length: 1.0.2\n      data-view-byte-offset: 1.0.1\n      es-define-property: 1.0.1\n      es-errors: 1.3.0\n      es-object-atoms: 1.1.1\n      es-set-tostringtag: 2.1.0\n      es-to-primitive: 1.3.0\n      function.prototype.name: 1.1.8\n      get-intrinsic: 1.3.0\n      get-proto: 1.0.1\n      get-symbol-description: 1.1.0\n      globalthis: 1.0.4\n      gopd: 1.2.0\n      has-property-descriptors: 1.0.2\n      has-proto: 1.2.0\n      has-symbols: 1.1.0\n      hasown: 2.0.2\n      internal-slot: 1.1.0\n      is-array-buffer: 3.0.5\n      is-callable: 1.2.7\n      is-data-view: 1.0.2\n      is-regex: 1.2.1\n      is-shared-array-buffer: 1.0.4\n      is-string: 1.1.1\n      is-typed-array: 1.1.15\n      is-weakref: 1.1.1\n      math-intrinsics: 1.1.0\n      object-inspect: 1.13.4\n      object-keys: 1.1.1\n      object.assign: 4.1.7\n      own-keys: 1.0.1\n      regexp.prototype.flags: 1.5.4\n      safe-array-concat: 1.1.3\n      safe-push-apply: 1.0.0\n      safe-regex-test: 1.1.0\n      set-proto: 1.0.0\n      string.prototype.trim: 1.2.10\n      string.prototype.trimend: 1.0.9\n      string.prototype.trimstart: 1.0.8\n      typed-array-buffer: 1.0.3\n      typed-array-byte-length: 1.0.3\n      typed-array-byte-offset: 1.0.4\n      typed-array-length: 1.0.7\n      unbox-primitive: 1.1.0\n      which-typed-array: 1.1.19\n\n  es-define-property@1.0.1: {}\n\n  es-errors@1.3.0: {}\n\n  es-object-atoms@1.1.1:\n    dependencies:\n      es-errors: 1.3.0\n\n  es-set-tostringtag@2.1.0:\n    dependencies:\n      es-errors: 1.3.0\n      get-intrinsic: 1.3.0\n      has-tostringtag: 1.0.2\n      hasown: 2.0.2\n\n  es-shim-unscopables@1.1.0:\n    dependencies:\n      hasown: 2.0.2\n\n  es-to-primitive@1.3.0:\n    dependencies:\n      is-callable: 1.2.7\n      is-date-object: 1.1.0\n      is-symbol: 1.1.1\n\n  es6-error@4.1.1: {}\n\n  escalade@3.2.0: {}\n\n  escape-html@1.0.3: {}\n\n  escape-string-regexp@1.0.5: {}\n\n  escape-string-regexp@2.0.0: {}\n\n  escape-string-regexp@5.0.0: {}\n\n  escodegen@2.1.0:\n    dependencies:\n      esprima: 4.0.1\n      estraverse: 5.3.0\n      esutils: 2.0.3\n    optionalDependencies:\n      source-map: 0.6.1\n\n  eslint-config-airbnb-base@14.1.0(eslint-plugin-import@2.20.2(eslint@6.8.0))(eslint@6.8.0):\n    dependencies:\n      confusing-browser-globals: 1.0.11\n      eslint: 6.8.0\n      eslint-plugin-import: 2.20.2(eslint@6.8.0)\n      object.assign: 4.1.7\n      object.entries: 1.1.9\n\n  eslint-config-prettier@6.11.0(eslint@6.8.0):\n    dependencies:\n      eslint: 6.8.0\n      get-stdin: 6.0.0\n\n  eslint-import-resolver-node@0.3.9:\n    dependencies:\n      debug: 3.2.7\n      is-core-module: 2.16.1\n      resolve: 1.22.10\n    transitivePeerDependencies:\n      - supports-color\n\n  eslint-module-utils@2.12.0(eslint-import-resolver-node@0.3.9)(eslint@6.8.0):\n    dependencies:\n      debug: 3.2.7\n    optionalDependencies:\n      eslint: 6.8.0\n      eslint-import-resolver-node: 0.3.9\n    transitivePeerDependencies:\n      - supports-color\n\n  eslint-plugin-import@2.20.2(eslint@6.8.0):\n    dependencies:\n      array-includes: 3.1.8\n      array.prototype.flat: 1.3.3\n      contains-path: 0.1.0\n      debug: 2.6.9\n      doctrine: 1.5.0\n      eslint: 6.8.0\n      eslint-import-resolver-node: 0.3.9\n      eslint-module-utils: 2.12.0(eslint-import-resolver-node@0.3.9)(eslint@6.8.0)\n      has: 1.0.4\n      minimatch: 3.1.2\n      object.values: 1.2.1\n      read-pkg-up: 2.0.0\n      resolve: 1.22.10\n    transitivePeerDependencies:\n      - eslint-import-resolver-typescript\n      - eslint-import-resolver-webpack\n      - supports-color\n\n  eslint-plugin-prettier@3.1.3(eslint@6.8.0)(prettier@2.0.5):\n    dependencies:\n      eslint: 6.8.0\n      prettier: 2.0.5\n      prettier-linter-helpers: 1.0.0\n\n  eslint-scope@5.1.1:\n    dependencies:\n      esrecurse: 4.3.0\n      estraverse: 4.3.0\n\n  eslint-utils@1.4.3:\n    dependencies:\n      eslint-visitor-keys: 1.3.0\n\n  eslint-visitor-keys@1.3.0: {}\n\n  eslint@6.8.0:\n    dependencies:\n      '@babel/code-frame': 7.26.2\n      ajv: 6.12.6\n      chalk: 2.4.2\n      cross-spawn: 6.0.6\n      debug: 4.4.0\n      doctrine: 3.0.0\n      eslint-scope: 5.1.1\n      eslint-utils: 1.4.3\n      eslint-visitor-keys: 1.3.0\n      espree: 6.2.1\n      esquery: 1.6.0\n      esutils: 2.0.3\n      file-entry-cache: 5.0.1\n      functional-red-black-tree: 1.0.1\n      glob-parent: 5.1.2\n      globals: 12.4.0\n      ignore: 4.0.6\n      import-fresh: 3.3.1\n      imurmurhash: 0.1.4\n      inquirer: 7.3.3\n      is-glob: 4.0.3\n      js-yaml: 3.14.1\n      json-stable-stringify-without-jsonify: 1.0.1\n      levn: 0.3.0\n      lodash: 4.17.21\n      minimatch: 3.1.2\n      mkdirp: 0.5.6\n      natural-compare: 1.4.0\n      optionator: 0.8.3\n      progress: 2.0.3\n      regexpp: 2.0.1\n      semver: 6.3.1\n      strip-ansi: 5.2.0\n      strip-json-comments: 3.1.1\n      table: 5.4.6\n      text-table: 0.2.0\n      v8-compile-cache: 2.4.0\n    transitivePeerDependencies:\n      - supports-color\n\n  espree@6.2.1:\n    dependencies:\n      acorn: 7.4.1\n      acorn-jsx: 5.3.2(acorn@7.4.1)\n      eslint-visitor-keys: 1.3.0\n\n  esprima@4.0.1: {}\n\n  esquery@1.6.0:\n    dependencies:\n      estraverse: 5.3.0\n\n  esrecurse@4.3.0:\n    dependencies:\n      estraverse: 5.3.0\n\n  estraverse@4.3.0: {}\n\n  estraverse@5.3.0: {}\n\n  estree-walker@2.0.2: {}\n\n  esutils@2.0.3: {}\n\n  etag@1.8.1: {}\n\n  execa@5.1.1:\n    dependencies:\n      cross-spawn: 7.0.6\n      get-stream: 6.0.1\n      human-signals: 2.1.0\n      is-stream: 2.0.1\n      merge-stream: 2.0.0\n      npm-run-path: 4.0.1\n      onetime: 5.1.2\n      signal-exit: 3.0.7\n      strip-final-newline: 2.0.0\n\n  exit@0.1.2: {}\n\n  expect@27.5.1:\n    dependencies:\n      '@jest/types': 27.5.1\n      jest-get-type: 27.5.1\n      jest-matcher-utils: 27.5.1\n      jest-message-util: 27.5.1\n\n  express@4.21.2:\n    dependencies:\n      accepts: 1.3.8\n      array-flatten: 1.1.1\n      body-parser: 1.20.3\n      content-disposition: 0.5.4\n      content-type: 1.0.5\n      cookie: 0.7.1\n      cookie-signature: 1.0.6\n      debug: 2.6.9\n      depd: 2.0.0\n      encodeurl: 2.0.0\n      escape-html: 1.0.3\n      etag: 1.8.1\n      finalhandler: 1.3.1\n      fresh: 0.5.2\n      http-errors: 2.0.0\n      merge-descriptors: 1.0.3\n      methods: 1.1.2\n      on-finished: 2.4.1\n      parseurl: 1.3.3\n      path-to-regexp: 0.1.12\n      proxy-addr: 2.0.7\n      qs: 6.13.0\n      range-parser: 1.2.1\n      safe-buffer: 5.2.1\n      send: 0.19.0\n      serve-static: 1.16.2\n      setprototypeof: 1.2.0\n      statuses: 2.0.1\n      type-is: 1.6.18\n      utils-merge: 1.0.1\n      vary: 1.1.2\n    transitivePeerDependencies:\n      - supports-color\n\n  external-editor@3.1.0:\n    dependencies:\n      chardet: 0.7.0\n      iconv-lite: 0.4.24\n      tmp: 0.0.33\n\n  fast-deep-equal@3.1.3: {}\n\n  fast-diff@1.3.0: {}\n\n  fast-glob@3.3.3:\n    dependencies:\n      '@nodelib/fs.stat': 2.0.5\n      '@nodelib/fs.walk': 1.2.8\n      glob-parent: 5.1.2\n      merge2: 1.4.1\n      micromatch: 4.0.8\n\n  fast-json-stable-stringify@2.1.0: {}\n\n  fast-levenshtein@2.0.6: {}\n\n  fast-safe-stringify@2.1.1: {}\n\n  fastq@1.19.1:\n    dependencies:\n      reusify: 1.1.0\n\n  fb-watchman@2.0.2:\n    dependencies:\n      bser: 2.1.1\n\n  fetch-blob@3.2.0:\n    dependencies:\n      node-domexception: 1.0.0\n      web-streams-polyfill: 3.3.3\n\n  figures@3.2.0:\n    dependencies:\n      escape-string-regexp: 1.0.5\n\n  file-entry-cache@5.0.1:\n    dependencies:\n      flat-cache: 2.0.1\n\n  fill-range@7.1.1:\n    dependencies:\n      to-regex-range: 5.0.1\n\n  finalhandler@1.3.1:\n    dependencies:\n      debug: 2.6.9\n      encodeurl: 2.0.0\n      escape-html: 1.0.3\n      on-finished: 2.4.1\n      parseurl: 1.3.3\n      statuses: 2.0.1\n      unpipe: 1.0.0\n    transitivePeerDependencies:\n      - supports-color\n\n  find-cache-dir@3.3.2:\n    dependencies:\n      commondir: 1.0.1\n      make-dir: 3.1.0\n      pkg-dir: 4.2.0\n\n  find-up@2.1.0:\n    dependencies:\n      locate-path: 2.0.0\n\n  find-up@4.1.0:\n    dependencies:\n      locate-path: 5.0.0\n      path-exists: 4.0.0\n\n  flat-cache@2.0.1:\n    dependencies:\n      flatted: 2.0.2\n      rimraf: 2.6.3\n      write: 1.0.3\n\n  flatted@2.0.2: {}\n\n  for-each@0.3.5:\n    dependencies:\n      is-callable: 1.2.7\n\n  foreground-child@2.0.0:\n    dependencies:\n      cross-spawn: 7.0.6\n      signal-exit: 3.0.7\n\n  form-data@3.0.3:\n    dependencies:\n      asynckit: 0.4.0\n      combined-stream: 1.0.8\n      es-set-tostringtag: 2.1.0\n      mime-types: 2.1.35\n\n  formdata-polyfill@4.0.10:\n    dependencies:\n      fetch-blob: 3.2.0\n\n  formidable@1.2.6: {}\n\n  forwarded@0.2.0: {}\n\n  fresh@0.5.2: {}\n\n  fromentries@1.3.2: {}\n\n  fs.realpath@1.0.0: {}\n\n  fsevents@2.3.3:\n    optional: true\n\n  function-bind@1.1.2: {}\n\n  function.prototype.name@1.1.8:\n    dependencies:\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      define-properties: 1.2.1\n      functions-have-names: 1.2.3\n      hasown: 2.0.2\n      is-callable: 1.2.7\n\n  functional-red-black-tree@1.0.1: {}\n\n  functions-have-names@1.2.3: {}\n\n  gensync@1.0.0-beta.2: {}\n\n  get-caller-file@2.0.5: {}\n\n  get-intrinsic@1.3.0:\n    dependencies:\n      call-bind-apply-helpers: 1.0.2\n      es-define-property: 1.0.1\n      es-errors: 1.3.0\n      es-object-atoms: 1.1.1\n      function-bind: 1.1.2\n      get-proto: 1.0.1\n      gopd: 1.2.0\n      has-symbols: 1.1.0\n      hasown: 2.0.2\n      math-intrinsics: 1.1.0\n\n  get-package-type@0.1.0: {}\n\n  get-proto@1.0.1:\n    dependencies:\n      dunder-proto: 1.0.1\n      es-object-atoms: 1.1.1\n\n  get-stdin@6.0.0: {}\n\n  get-stream@6.0.1: {}\n\n  get-symbol-description@1.1.0:\n    dependencies:\n      call-bound: 1.0.4\n      es-errors: 1.3.0\n      get-intrinsic: 1.3.0\n\n  git-hooks-list@1.0.3: {}\n\n  glob-parent@5.1.2:\n    dependencies:\n      is-glob: 4.0.3\n\n  glob@7.2.3:\n    dependencies:\n      fs.realpath: 1.0.0\n      inflight: 1.0.6\n      inherits: 2.0.4\n      minimatch: 3.1.2\n      once: 1.4.0\n      path-is-absolute: 1.0.1\n\n  glob@8.1.0:\n    dependencies:\n      fs.realpath: 1.0.0\n      inflight: 1.0.6\n      inherits: 2.0.4\n      minimatch: 5.1.6\n      once: 1.4.0\n\n  globals@11.12.0: {}\n\n  globals@12.4.0:\n    dependencies:\n      type-fest: 0.8.1\n\n  globalthis@1.0.4:\n    dependencies:\n      define-properties: 1.2.1\n      gopd: 1.2.0\n\n  globby@10.0.0:\n    dependencies:\n      '@types/glob': 7.2.0\n      array-union: 2.1.0\n      dir-glob: 3.0.1\n      fast-glob: 3.3.3\n      glob: 7.2.3\n      ignore: 5.3.2\n      merge2: 1.4.1\n      slash: 3.0.0\n\n  gopd@1.2.0: {}\n\n  graceful-fs@4.2.11: {}\n\n  has-bigints@1.1.0: {}\n\n  has-flag@3.0.0: {}\n\n  has-flag@4.0.0: {}\n\n  has-property-descriptors@1.0.2:\n    dependencies:\n      es-define-property: 1.0.1\n\n  has-proto@1.2.0:\n    dependencies:\n      dunder-proto: 1.0.1\n\n  has-symbols@1.1.0: {}\n\n  has-tostringtag@1.0.2:\n    dependencies:\n      has-symbols: 1.1.0\n\n  has@1.0.4: {}\n\n  hasha@5.2.2:\n    dependencies:\n      is-stream: 2.0.1\n      type-fest: 0.8.1\n\n  hasown@2.0.2:\n    dependencies:\n      function-bind: 1.1.2\n\n  hosted-git-info@2.8.9: {}\n\n  html-encoding-sniffer@2.0.1:\n    dependencies:\n      whatwg-encoding: 1.0.5\n\n  html-escaper@2.0.2: {}\n\n  http-assert@1.5.0:\n    dependencies:\n      deep-equal: 1.0.1\n      http-errors: 1.8.1\n\n  http-errors@1.8.1:\n    dependencies:\n      depd: 1.1.2\n      inherits: 2.0.4\n      setprototypeof: 1.2.0\n      statuses: 1.5.0\n      toidentifier: 1.0.1\n\n  http-errors@2.0.0:\n    dependencies:\n      depd: 2.0.0\n      inherits: 2.0.4\n      setprototypeof: 1.2.0\n      statuses: 2.0.1\n      toidentifier: 1.0.1\n\n  http-proxy-agent@4.0.1:\n    dependencies:\n      '@tootallnate/once': 1.1.2\n      agent-base: 6.0.2\n      debug: 4.4.0\n    transitivePeerDependencies:\n      - supports-color\n\n  https-proxy-agent@5.0.1:\n    dependencies:\n      agent-base: 6.0.2\n      debug: 4.4.0\n    transitivePeerDependencies:\n      - supports-color\n\n  human-signals@2.1.0: {}\n\n  iconv-lite@0.4.24:\n    dependencies:\n      safer-buffer: 2.1.2\n\n  ignore@4.0.6: {}\n\n  ignore@5.3.2: {}\n\n  import-fresh@3.3.1:\n    dependencies:\n      parent-module: 1.0.1\n      resolve-from: 4.0.0\n\n  import-local@3.2.0:\n    dependencies:\n      pkg-dir: 4.2.0\n      resolve-cwd: 3.0.0\n\n  imurmurhash@0.1.4: {}\n\n  indent-string@4.0.0: {}\n\n  inflight@1.0.6:\n    dependencies:\n      once: 1.4.0\n      wrappy: 1.0.2\n\n  inherits@2.0.4: {}\n\n  inquirer@7.3.3:\n    dependencies:\n      ansi-escapes: 4.3.2\n      chalk: 4.1.2\n      cli-cursor: 3.1.0\n      cli-width: 3.0.0\n      external-editor: 3.1.0\n      figures: 3.2.0\n      lodash: 4.17.21\n      mute-stream: 0.0.8\n      run-async: 2.4.1\n      rxjs: 6.6.7\n      string-width: 4.2.3\n      strip-ansi: 6.0.1\n      through: 2.3.8\n\n  internal-slot@1.1.0:\n    dependencies:\n      es-errors: 1.3.0\n      hasown: 2.0.2\n      side-channel: 1.1.0\n\n  ipaddr.js@1.9.1: {}\n\n  is-array-buffer@3.0.5:\n    dependencies:\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      get-intrinsic: 1.3.0\n\n  is-arrayish@0.2.1: {}\n\n  is-async-function@2.1.1:\n    dependencies:\n      async-function: 1.0.0\n      call-bound: 1.0.4\n      get-proto: 1.0.1\n      has-tostringtag: 1.0.2\n      safe-regex-test: 1.1.0\n\n  is-bigint@1.1.0:\n    dependencies:\n      has-bigints: 1.1.0\n\n  is-boolean-object@1.2.2:\n    dependencies:\n      call-bound: 1.0.4\n      has-tostringtag: 1.0.2\n\n  is-callable@1.2.7: {}\n\n  is-core-module@2.16.1:\n    dependencies:\n      hasown: 2.0.2\n\n  is-data-view@1.0.2:\n    dependencies:\n      call-bound: 1.0.4\n      get-intrinsic: 1.3.0\n      is-typed-array: 1.1.15\n\n  is-date-object@1.1.0:\n    dependencies:\n      call-bound: 1.0.4\n      has-tostringtag: 1.0.2\n\n  is-extglob@2.1.1: {}\n\n  is-finalizationregistry@1.1.1:\n    dependencies:\n      call-bound: 1.0.4\n\n  is-fullwidth-code-point@2.0.0: {}\n\n  is-fullwidth-code-point@3.0.0: {}\n\n  is-generator-fn@2.1.0: {}\n\n  is-generator-function@1.1.0:\n    dependencies:\n      call-bound: 1.0.4\n      get-proto: 1.0.1\n      has-tostringtag: 1.0.2\n      safe-regex-test: 1.1.0\n\n  is-glob@4.0.3:\n    dependencies:\n      is-extglob: 2.1.1\n\n  is-map@2.0.3: {}\n\n  is-module@1.0.0: {}\n\n  is-number-object@1.1.1:\n    dependencies:\n      call-bound: 1.0.4\n      has-tostringtag: 1.0.2\n\n  is-number@7.0.0: {}\n\n  is-plain-obj@2.1.0: {}\n\n  is-potential-custom-element-name@1.0.1: {}\n\n  is-reference@1.2.1:\n    dependencies:\n      '@types/estree': 1.0.7\n\n  is-regex@1.2.1:\n    dependencies:\n      call-bound: 1.0.4\n      gopd: 1.2.0\n      has-tostringtag: 1.0.2\n      hasown: 2.0.2\n\n  is-set@2.0.3: {}\n\n  is-shared-array-buffer@1.0.4:\n    dependencies:\n      call-bound: 1.0.4\n\n  is-stream@2.0.1: {}\n\n  is-string@1.1.1:\n    dependencies:\n      call-bound: 1.0.4\n      has-tostringtag: 1.0.2\n\n  is-symbol@1.1.1:\n    dependencies:\n      call-bound: 1.0.4\n      has-symbols: 1.1.0\n      safe-regex-test: 1.1.0\n\n  is-typed-array@1.1.15:\n    dependencies:\n      which-typed-array: 1.1.19\n\n  is-typedarray@1.0.0: {}\n\n  is-weakmap@2.0.2: {}\n\n  is-weakref@1.1.1:\n    dependencies:\n      call-bound: 1.0.4\n\n  is-weakset@2.0.4:\n    dependencies:\n      call-bound: 1.0.4\n      get-intrinsic: 1.3.0\n\n  is-windows@1.0.2: {}\n\n  isarray@1.0.0: {}\n\n  isarray@2.0.5: {}\n\n  isexe@2.0.0: {}\n\n  istanbul-lib-coverage@3.2.2: {}\n\n  istanbul-lib-hook@3.0.0:\n    dependencies:\n      append-transform: 2.0.0\n\n  istanbul-lib-instrument@4.0.3:\n    dependencies:\n      '@babel/core': 7.26.10\n      '@istanbuljs/schema': 0.1.3\n      istanbul-lib-coverage: 3.2.2\n      semver: 6.3.1\n    transitivePeerDependencies:\n      - supports-color\n\n  istanbul-lib-instrument@5.2.1:\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/parser': 7.27.0\n      '@istanbuljs/schema': 0.1.3\n      istanbul-lib-coverage: 3.2.2\n      semver: 6.3.1\n    transitivePeerDependencies:\n      - supports-color\n\n  istanbul-lib-processinfo@2.0.3:\n    dependencies:\n      archy: 1.0.0\n      cross-spawn: 7.0.6\n      istanbul-lib-coverage: 3.2.2\n      p-map: 3.0.0\n      rimraf: 3.0.2\n      uuid: 8.3.2\n\n  istanbul-lib-report@3.0.1:\n    dependencies:\n      istanbul-lib-coverage: 3.2.2\n      make-dir: 4.0.0\n      supports-color: 7.2.0\n\n  istanbul-lib-source-maps@4.0.1:\n    dependencies:\n      debug: 4.4.0\n      istanbul-lib-coverage: 3.2.2\n      source-map: 0.6.1\n    transitivePeerDependencies:\n      - supports-color\n\n  istanbul-reports@3.1.7:\n    dependencies:\n      html-escaper: 2.0.2\n      istanbul-lib-report: 3.0.1\n\n  jest-changed-files@27.5.1:\n    dependencies:\n      '@jest/types': 27.5.1\n      execa: 5.1.1\n      throat: 6.0.2\n\n  jest-circus@27.5.1:\n    dependencies:\n      '@jest/environment': 27.5.1\n      '@jest/test-result': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      chalk: 4.1.2\n      co: 4.6.0\n      dedent: 0.7.0\n      expect: 27.5.1\n      is-generator-fn: 2.1.0\n      jest-each: 27.5.1\n      jest-matcher-utils: 27.5.1\n      jest-message-util: 27.5.1\n      jest-runtime: 27.5.1\n      jest-snapshot: 27.5.1\n      jest-util: 27.5.1\n      pretty-format: 27.5.1\n      slash: 3.0.0\n      stack-utils: 2.0.6\n      throat: 6.0.2\n    transitivePeerDependencies:\n      - supports-color\n\n  jest-cli@27.5.1:\n    dependencies:\n      '@jest/core': 27.5.1\n      '@jest/test-result': 27.5.1\n      '@jest/types': 27.5.1\n      chalk: 4.1.2\n      exit: 0.1.2\n      graceful-fs: 4.2.11\n      import-local: 3.2.0\n      jest-config: 27.5.1\n      jest-util: 27.5.1\n      jest-validate: 27.5.1\n      prompts: 2.4.2\n      yargs: 16.2.0\n    transitivePeerDependencies:\n      - bufferutil\n      - canvas\n      - supports-color\n      - ts-node\n      - utf-8-validate\n\n  jest-config@27.5.1:\n    dependencies:\n      '@babel/core': 7.26.10\n      '@jest/test-sequencer': 27.5.1\n      '@jest/types': 27.5.1\n      babel-jest: 27.5.1(@babel/core@7.26.10)\n      chalk: 4.1.2\n      ci-info: 3.9.0\n      deepmerge: 4.3.1\n      glob: 7.2.3\n      graceful-fs: 4.2.11\n      jest-circus: 27.5.1\n      jest-environment-jsdom: 27.5.1\n      jest-environment-node: 27.5.1\n      jest-get-type: 27.5.1\n      jest-jasmine2: 27.5.1\n      jest-regex-util: 27.5.1\n      jest-resolve: 27.5.1\n      jest-runner: 27.5.1\n      jest-util: 27.5.1\n      jest-validate: 27.5.1\n      micromatch: 4.0.8\n      parse-json: 5.2.0\n      pretty-format: 27.5.1\n      slash: 3.0.0\n      strip-json-comments: 3.1.1\n    transitivePeerDependencies:\n      - bufferutil\n      - canvas\n      - supports-color\n      - utf-8-validate\n\n  jest-diff@27.5.1:\n    dependencies:\n      chalk: 4.1.2\n      diff-sequences: 27.5.1\n      jest-get-type: 27.5.1\n      pretty-format: 27.5.1\n\n  jest-docblock@27.5.1:\n    dependencies:\n      detect-newline: 3.1.0\n\n  jest-each@27.5.1:\n    dependencies:\n      '@jest/types': 27.5.1\n      chalk: 4.1.2\n      jest-get-type: 27.5.1\n      jest-util: 27.5.1\n      pretty-format: 27.5.1\n\n  jest-environment-jsdom@27.5.1:\n    dependencies:\n      '@jest/environment': 27.5.1\n      '@jest/fake-timers': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      jest-mock: 27.5.1\n      jest-util: 27.5.1\n      jsdom: 16.7.0\n    transitivePeerDependencies:\n      - bufferutil\n      - canvas\n      - supports-color\n      - utf-8-validate\n\n  jest-environment-node@27.5.1:\n    dependencies:\n      '@jest/environment': 27.5.1\n      '@jest/fake-timers': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      jest-mock: 27.5.1\n      jest-util: 27.5.1\n\n  jest-get-type@27.5.1: {}\n\n  jest-haste-map@27.5.1:\n    dependencies:\n      '@jest/types': 27.5.1\n      '@types/graceful-fs': 4.1.9\n      '@types/node': 22.14.1\n      anymatch: 3.1.3\n      fb-watchman: 2.0.2\n      graceful-fs: 4.2.11\n      jest-regex-util: 27.5.1\n      jest-serializer: 27.5.1\n      jest-util: 27.5.1\n      jest-worker: 27.5.1\n      micromatch: 4.0.8\n      walker: 1.0.8\n    optionalDependencies:\n      fsevents: 2.3.3\n\n  jest-jasmine2@27.5.1:\n    dependencies:\n      '@jest/environment': 27.5.1\n      '@jest/source-map': 27.5.1\n      '@jest/test-result': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      chalk: 4.1.2\n      co: 4.6.0\n      expect: 27.5.1\n      is-generator-fn: 2.1.0\n      jest-each: 27.5.1\n      jest-matcher-utils: 27.5.1\n      jest-message-util: 27.5.1\n      jest-runtime: 27.5.1\n      jest-snapshot: 27.5.1\n      jest-util: 27.5.1\n      pretty-format: 27.5.1\n      throat: 6.0.2\n    transitivePeerDependencies:\n      - supports-color\n\n  jest-leak-detector@27.5.1:\n    dependencies:\n      jest-get-type: 27.5.1\n      pretty-format: 27.5.1\n\n  jest-matcher-utils@27.5.1:\n    dependencies:\n      chalk: 4.1.2\n      jest-diff: 27.5.1\n      jest-get-type: 27.5.1\n      pretty-format: 27.5.1\n\n  jest-message-util@27.5.1:\n    dependencies:\n      '@babel/code-frame': 7.26.2\n      '@jest/types': 27.5.1\n      '@types/stack-utils': 2.0.3\n      chalk: 4.1.2\n      graceful-fs: 4.2.11\n      micromatch: 4.0.8\n      pretty-format: 27.5.1\n      slash: 3.0.0\n      stack-utils: 2.0.6\n\n  jest-mock@27.5.1:\n    dependencies:\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n\n  jest-pnp-resolver@1.2.3(jest-resolve@27.5.1):\n    optionalDependencies:\n      jest-resolve: 27.5.1\n\n  jest-regex-util@27.5.1: {}\n\n  jest-resolve-dependencies@27.5.1:\n    dependencies:\n      '@jest/types': 27.5.1\n      jest-regex-util: 27.5.1\n      jest-snapshot: 27.5.1\n    transitivePeerDependencies:\n      - supports-color\n\n  jest-resolve@27.5.1:\n    dependencies:\n      '@jest/types': 27.5.1\n      chalk: 4.1.2\n      graceful-fs: 4.2.11\n      jest-haste-map: 27.5.1\n      jest-pnp-resolver: 1.2.3(jest-resolve@27.5.1)\n      jest-util: 27.5.1\n      jest-validate: 27.5.1\n      resolve: 1.22.10\n      resolve.exports: 1.1.1\n      slash: 3.0.0\n\n  jest-runner@27.5.1:\n    dependencies:\n      '@jest/console': 27.5.1\n      '@jest/environment': 27.5.1\n      '@jest/test-result': 27.5.1\n      '@jest/transform': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      chalk: 4.1.2\n      emittery: 0.8.1\n      graceful-fs: 4.2.11\n      jest-docblock: 27.5.1\n      jest-environment-jsdom: 27.5.1\n      jest-environment-node: 27.5.1\n      jest-haste-map: 27.5.1\n      jest-leak-detector: 27.5.1\n      jest-message-util: 27.5.1\n      jest-resolve: 27.5.1\n      jest-runtime: 27.5.1\n      jest-util: 27.5.1\n      jest-worker: 27.5.1\n      source-map-support: 0.5.21\n      throat: 6.0.2\n    transitivePeerDependencies:\n      - bufferutil\n      - canvas\n      - supports-color\n      - utf-8-validate\n\n  jest-runtime@27.5.1:\n    dependencies:\n      '@jest/environment': 27.5.1\n      '@jest/fake-timers': 27.5.1\n      '@jest/globals': 27.5.1\n      '@jest/source-map': 27.5.1\n      '@jest/test-result': 27.5.1\n      '@jest/transform': 27.5.1\n      '@jest/types': 27.5.1\n      chalk: 4.1.2\n      cjs-module-lexer: 1.4.3\n      collect-v8-coverage: 1.0.2\n      execa: 5.1.1\n      glob: 7.2.3\n      graceful-fs: 4.2.11\n      jest-haste-map: 27.5.1\n      jest-message-util: 27.5.1\n      jest-mock: 27.5.1\n      jest-regex-util: 27.5.1\n      jest-resolve: 27.5.1\n      jest-snapshot: 27.5.1\n      jest-util: 27.5.1\n      slash: 3.0.0\n      strip-bom: 4.0.0\n    transitivePeerDependencies:\n      - supports-color\n\n  jest-serializer@27.5.1:\n    dependencies:\n      '@types/node': 22.14.1\n      graceful-fs: 4.2.11\n\n  jest-snapshot@27.5.1:\n    dependencies:\n      '@babel/core': 7.26.10\n      '@babel/generator': 7.27.0\n      '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.10)\n      '@babel/traverse': 7.27.0\n      '@babel/types': 7.27.0\n      '@jest/transform': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/babel__traverse': 7.20.7\n      '@types/prettier': 2.7.3\n      babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.10)\n      chalk: 4.1.2\n      expect: 27.5.1\n      graceful-fs: 4.2.11\n      jest-diff: 27.5.1\n      jest-get-type: 27.5.1\n      jest-haste-map: 27.5.1\n      jest-matcher-utils: 27.5.1\n      jest-message-util: 27.5.1\n      jest-util: 27.5.1\n      natural-compare: 1.4.0\n      pretty-format: 27.5.1\n      semver: 7.7.1\n    transitivePeerDependencies:\n      - supports-color\n\n  jest-util@27.5.1:\n    dependencies:\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      chalk: 4.1.2\n      ci-info: 3.9.0\n      graceful-fs: 4.2.11\n      picomatch: 2.3.1\n\n  jest-validate@27.5.1:\n    dependencies:\n      '@jest/types': 27.5.1\n      camelcase: 6.3.0\n      chalk: 4.1.2\n      jest-get-type: 27.5.1\n      leven: 3.1.0\n      pretty-format: 27.5.1\n\n  jest-watcher@27.5.1:\n    dependencies:\n      '@jest/test-result': 27.5.1\n      '@jest/types': 27.5.1\n      '@types/node': 22.14.1\n      ansi-escapes: 4.3.2\n      chalk: 4.1.2\n      jest-util: 27.5.1\n      string-length: 4.0.2\n\n  jest-worker@27.5.1:\n    dependencies:\n      '@types/node': 22.14.1\n      merge-stream: 2.0.0\n      supports-color: 8.1.1\n\n  jest@27.2.4:\n    dependencies:\n      '@jest/core': 27.5.1\n      import-local: 3.2.0\n      jest-cli: 27.5.1\n    transitivePeerDependencies:\n      - bufferutil\n      - canvas\n      - supports-color\n      - ts-node\n      - utf-8-validate\n\n  js-tokens@4.0.0: {}\n\n  js-yaml@3.14.1:\n    dependencies:\n      argparse: 1.0.10\n      esprima: 4.0.1\n\n  jsdom@16.7.0:\n    dependencies:\n      abab: 2.0.6\n      acorn: 8.14.1\n      acorn-globals: 6.0.0\n      cssom: 0.4.4\n      cssstyle: 2.3.0\n      data-urls: 2.0.0\n      decimal.js: 10.5.0\n      domexception: 2.0.1\n      escodegen: 2.1.0\n      form-data: 3.0.3\n      html-encoding-sniffer: 2.0.1\n      http-proxy-agent: 4.0.1\n      https-proxy-agent: 5.0.1\n      is-potential-custom-element-name: 1.0.1\n      nwsapi: 2.2.20\n      parse5: 6.0.1\n      saxes: 5.0.1\n      symbol-tree: 3.2.4\n      tough-cookie: 4.1.4\n      w3c-hr-time: 1.0.2\n      w3c-xmlserializer: 2.0.0\n      webidl-conversions: 6.1.0\n      whatwg-encoding: 1.0.5\n      whatwg-mimetype: 2.3.0\n      whatwg-url: 8.7.0\n      ws: 7.5.10\n      xml-name-validator: 3.0.0\n    transitivePeerDependencies:\n      - bufferutil\n      - supports-color\n      - utf-8-validate\n\n  jsesc@3.1.0: {}\n\n  json-parse-even-better-errors@2.3.1: {}\n\n  json-schema-traverse@0.4.1: {}\n\n  json-stable-stringify-without-jsonify@1.0.1: {}\n\n  json5@2.2.3: {}\n\n  keygrip@1.1.0:\n    dependencies:\n      tsscmp: 1.0.6\n\n  kleur@3.0.3: {}\n\n  koa-compose@4.1.0: {}\n\n  koa-convert@2.0.0:\n    dependencies:\n      co: 4.6.0\n      koa-compose: 4.1.0\n\n  koa@2.16.1:\n    dependencies:\n      accepts: 1.3.8\n      cache-content-type: 1.0.1\n      content-disposition: 0.5.4\n      content-type: 1.0.5\n      cookies: 0.9.1\n      debug: 4.4.0\n      delegates: 1.0.0\n      depd: 2.0.0\n      destroy: 1.2.0\n      encodeurl: 1.0.2\n      escape-html: 1.0.3\n      fresh: 0.5.2\n      http-assert: 1.5.0\n      http-errors: 1.8.1\n      is-generator-function: 1.1.0\n      koa-compose: 4.1.0\n      koa-convert: 2.0.0\n      on-finished: 2.4.1\n      only: 0.0.2\n      parseurl: 1.3.3\n      statuses: 1.5.0\n      type-is: 1.6.18\n      vary: 1.1.2\n    transitivePeerDependencies:\n      - supports-color\n\n  leven@3.1.0: {}\n\n  levn@0.3.0:\n    dependencies:\n      prelude-ls: 1.1.2\n      type-check: 0.3.2\n\n  lines-and-columns@1.2.4: {}\n\n  load-json-file@2.0.0:\n    dependencies:\n      graceful-fs: 4.2.11\n      parse-json: 2.2.0\n      pify: 2.3.0\n      strip-bom: 3.0.0\n\n  locate-path@2.0.0:\n    dependencies:\n      p-locate: 2.0.0\n      path-exists: 3.0.0\n\n  locate-path@5.0.0:\n    dependencies:\n      p-locate: 4.1.0\n\n  lodash.flattendeep@4.4.0: {}\n\n  lodash@4.17.21: {}\n\n  lru-cache@5.1.1:\n    dependencies:\n      yallist: 3.1.1\n\n  magic-string@0.30.17:\n    dependencies:\n      '@jridgewell/sourcemap-codec': 1.5.0\n\n  make-dir@3.1.0:\n    dependencies:\n      semver: 6.3.1\n\n  make-dir@4.0.0:\n    dependencies:\n      semver: 7.7.1\n\n  makeerror@1.0.12:\n    dependencies:\n      tmpl: 1.0.5\n\n  math-intrinsics@1.1.0: {}\n\n  media-typer@0.3.0: {}\n\n  merge-descriptors@1.0.3: {}\n\n  merge-stream@2.0.0: {}\n\n  merge2@1.4.1: {}\n\n  methods@1.1.2: {}\n\n  micromatch@4.0.8:\n    dependencies:\n      braces: 3.0.3\n      picomatch: 2.3.1\n\n  mime-db@1.52.0: {}\n\n  mime-types@2.1.35:\n    dependencies:\n      mime-db: 1.52.0\n\n  mime@1.6.0: {}\n\n  mime@2.6.0: {}\n\n  mimic-fn@2.1.0: {}\n\n  minimatch@3.1.2:\n    dependencies:\n      brace-expansion: 1.1.11\n\n  minimatch@5.1.6:\n    dependencies:\n      brace-expansion: 2.0.1\n\n  minimist@1.2.8: {}\n\n  mkdirp@0.5.6:\n    dependencies:\n      minimist: 1.2.8\n\n  ms@2.0.0: {}\n\n  ms@2.1.3: {}\n\n  mute-stream@0.0.8: {}\n\n  natural-compare@1.4.0: {}\n\n  negotiator@0.6.3: {}\n\n  nice-try@1.0.5: {}\n\n  node-domexception@1.0.0: {}\n\n  node-int64@0.4.0: {}\n\n  node-preload@0.2.1:\n    dependencies:\n      process-on-spawn: 1.1.0\n\n  node-releases@2.0.19: {}\n\n  normalize-package-data@2.5.0:\n    dependencies:\n      hosted-git-info: 2.8.9\n      resolve: 1.22.10\n      semver: 5.7.2\n      validate-npm-package-license: 3.0.4\n\n  normalize-path@3.0.0: {}\n\n  npm-run-path@4.0.1:\n    dependencies:\n      path-key: 3.1.1\n\n  nwsapi@2.2.20: {}\n\n  nyc@15.1.0:\n    dependencies:\n      '@istanbuljs/load-nyc-config': 1.1.0\n      '@istanbuljs/schema': 0.1.3\n      caching-transform: 4.0.0\n      convert-source-map: 1.9.0\n      decamelize: 1.2.0\n      find-cache-dir: 3.3.2\n      find-up: 4.1.0\n      foreground-child: 2.0.0\n      get-package-type: 0.1.0\n      glob: 7.2.3\n      istanbul-lib-coverage: 3.2.2\n      istanbul-lib-hook: 3.0.0\n      istanbul-lib-instrument: 4.0.3\n      istanbul-lib-processinfo: 2.0.3\n      istanbul-lib-report: 3.0.1\n      istanbul-lib-source-maps: 4.0.1\n      istanbul-reports: 3.1.7\n      make-dir: 3.1.0\n      node-preload: 0.2.1\n      p-map: 3.0.0\n      process-on-spawn: 1.1.0\n      resolve-from: 5.0.0\n      rimraf: 3.0.2\n      signal-exit: 3.0.7\n      spawn-wrap: 2.0.0\n      test-exclude: 6.0.0\n      yargs: 15.4.1\n    transitivePeerDependencies:\n      - supports-color\n\n  object-inspect@1.13.4: {}\n\n  object-keys@1.1.1: {}\n\n  object.assign@4.1.7:\n    dependencies:\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      define-properties: 1.2.1\n      es-object-atoms: 1.1.1\n      has-symbols: 1.1.0\n      object-keys: 1.1.1\n\n  object.entries@1.1.9:\n    dependencies:\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      define-properties: 1.2.1\n      es-object-atoms: 1.1.1\n\n  object.values@1.2.1:\n    dependencies:\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      define-properties: 1.2.1\n      es-object-atoms: 1.1.1\n\n  on-finished@2.4.1:\n    dependencies:\n      ee-first: 1.1.1\n\n  once@1.4.0:\n    dependencies:\n      wrappy: 1.0.2\n\n  onetime@5.1.2:\n    dependencies:\n      mimic-fn: 2.1.0\n\n  only@0.0.2: {}\n\n  optionator@0.8.3:\n    dependencies:\n      deep-is: 0.1.4\n      fast-levenshtein: 2.0.6\n      levn: 0.3.0\n      prelude-ls: 1.1.2\n      type-check: 0.3.2\n      word-wrap: 1.2.5\n\n  os-tmpdir@1.0.2: {}\n\n  own-keys@1.0.1:\n    dependencies:\n      get-intrinsic: 1.3.0\n      object-keys: 1.1.1\n      safe-push-apply: 1.0.0\n\n  p-limit@1.3.0:\n    dependencies:\n      p-try: 1.0.0\n\n  p-limit@2.3.0:\n    dependencies:\n      p-try: 2.2.0\n\n  p-locate@2.0.0:\n    dependencies:\n      p-limit: 1.3.0\n\n  p-locate@4.1.0:\n    dependencies:\n      p-limit: 2.3.0\n\n  p-map@3.0.0:\n    dependencies:\n      aggregate-error: 3.1.0\n\n  p-try@1.0.0: {}\n\n  p-try@2.2.0: {}\n\n  package-hash@4.0.0:\n    dependencies:\n      graceful-fs: 4.2.11\n      hasha: 5.2.2\n      lodash.flattendeep: 4.4.0\n      release-zalgo: 1.0.0\n\n  parent-module@1.0.1:\n    dependencies:\n      callsites: 3.1.0\n\n  parse-json@2.2.0:\n    dependencies:\n      error-ex: 1.3.2\n\n  parse-json@5.2.0:\n    dependencies:\n      '@babel/code-frame': 7.26.2\n      error-ex: 1.3.2\n      json-parse-even-better-errors: 2.3.1\n      lines-and-columns: 1.2.4\n\n  parse5@6.0.1: {}\n\n  parseurl@1.3.3: {}\n\n  path-exists@3.0.0: {}\n\n  path-exists@4.0.0: {}\n\n  path-is-absolute@1.0.1: {}\n\n  path-key@2.0.1: {}\n\n  path-key@3.1.1: {}\n\n  path-parse@1.0.7: {}\n\n  path-to-regexp@0.1.12: {}\n\n  path-type@2.0.0:\n    dependencies:\n      pify: 2.3.0\n\n  path-type@4.0.0: {}\n\n  picocolors@1.1.1: {}\n\n  picomatch@2.3.1: {}\n\n  picomatch@4.0.2: {}\n\n  pify@2.3.0: {}\n\n  pirates@4.0.7: {}\n\n  pkg-dir@4.2.0:\n    dependencies:\n      find-up: 4.1.0\n\n  possible-typed-array-names@1.1.0: {}\n\n  prelude-ls@1.1.2: {}\n\n  prettier-linter-helpers@1.0.0:\n    dependencies:\n      fast-diff: 1.3.0\n\n  prettier-plugin-pkgjson@0.2.8(prettier@2.0.5):\n    dependencies:\n      prettier: 2.0.5\n      sort-package-json: 1.57.0\n\n  prettier@2.0.5: {}\n\n  pretty-format@27.5.1:\n    dependencies:\n      ansi-regex: 5.0.1\n      ansi-styles: 5.2.0\n      react-is: 17.0.2\n\n  process-on-spawn@1.1.0:\n    dependencies:\n      fromentries: 1.3.2\n\n  progress@2.0.3: {}\n\n  prompts@2.4.2:\n    dependencies:\n      kleur: 3.0.3\n      sisteransi: 1.0.5\n\n  proxy-addr@2.0.7:\n    dependencies:\n      forwarded: 0.2.0\n      ipaddr.js: 1.9.1\n\n  psl@1.15.0:\n    dependencies:\n      punycode: 2.3.1\n\n  punycode@2.3.1: {}\n\n  qs@6.13.0:\n    dependencies:\n      side-channel: 1.1.0\n\n  qs@6.14.0:\n    dependencies:\n      side-channel: 1.1.0\n\n  querystringify@2.2.0: {}\n\n  queue-microtask@1.2.3: {}\n\n  range-parser@1.2.1: {}\n\n  raw-body@2.5.2:\n    dependencies:\n      bytes: 3.1.2\n      http-errors: 2.0.0\n      iconv-lite: 0.4.24\n      unpipe: 1.0.0\n\n  react-is@17.0.2: {}\n\n  read-pkg-up@2.0.0:\n    dependencies:\n      find-up: 2.1.0\n      read-pkg: 2.0.0\n\n  read-pkg@2.0.0:\n    dependencies:\n      load-json-file: 2.0.0\n      normalize-package-data: 2.5.0\n      path-type: 2.0.0\n\n  readable-stream@3.6.2:\n    dependencies:\n      inherits: 2.0.4\n      string_decoder: 1.3.0\n      util-deprecate: 1.0.2\n\n  reflect.getprototypeof@1.0.10:\n    dependencies:\n      call-bind: 1.0.8\n      define-properties: 1.2.1\n      es-abstract: 1.23.9\n      es-errors: 1.3.0\n      es-object-atoms: 1.1.1\n      get-intrinsic: 1.3.0\n      get-proto: 1.0.1\n      which-builtin-type: 1.2.1\n\n  regexp.prototype.flags@1.5.4:\n    dependencies:\n      call-bind: 1.0.8\n      define-properties: 1.2.1\n      es-errors: 1.3.0\n      get-proto: 1.0.1\n      gopd: 1.2.0\n      set-function-name: 2.0.2\n\n  regexpp@2.0.1: {}\n\n  release-zalgo@1.0.0:\n    dependencies:\n      es6-error: 4.1.1\n\n  require-directory@2.1.1: {}\n\n  require-main-filename@2.0.0: {}\n\n  requires-port@1.0.0: {}\n\n  resolve-cwd@3.0.0:\n    dependencies:\n      resolve-from: 5.0.0\n\n  resolve-from@4.0.0: {}\n\n  resolve-from@5.0.0: {}\n\n  resolve.exports@1.1.1: {}\n\n  resolve@1.22.10:\n    dependencies:\n      is-core-module: 2.16.1\n      path-parse: 1.0.7\n      supports-preserve-symlinks-flag: 1.0.0\n\n  restore-cursor@3.1.0:\n    dependencies:\n      onetime: 5.1.2\n      signal-exit: 3.0.7\n\n  reusify@1.1.0: {}\n\n  rimraf@2.6.3:\n    dependencies:\n      glob: 7.2.3\n\n  rimraf@3.0.2:\n    dependencies:\n      glob: 7.2.3\n\n  rollup@3.29.5:\n    optionalDependencies:\n      fsevents: 2.3.3\n\n  run-async@2.4.1: {}\n\n  run-parallel@1.2.0:\n    dependencies:\n      queue-microtask: 1.2.3\n\n  rxjs@6.6.7:\n    dependencies:\n      tslib: 1.14.1\n\n  safe-array-concat@1.1.3:\n    dependencies:\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      get-intrinsic: 1.3.0\n      has-symbols: 1.1.0\n      isarray: 2.0.5\n\n  safe-buffer@5.2.1: {}\n\n  safe-push-apply@1.0.0:\n    dependencies:\n      es-errors: 1.3.0\n      isarray: 2.0.5\n\n  safe-regex-test@1.1.0:\n    dependencies:\n      call-bound: 1.0.4\n      es-errors: 1.3.0\n      is-regex: 1.2.1\n\n  safer-buffer@2.1.2: {}\n\n  saxes@5.0.1:\n    dependencies:\n      xmlchars: 2.2.0\n\n  semver@5.7.2: {}\n\n  semver@6.3.1: {}\n\n  semver@7.7.1: {}\n\n  send@0.19.0:\n    dependencies:\n      debug: 2.6.9\n      depd: 2.0.0\n      destroy: 1.2.0\n      encodeurl: 1.0.2\n      escape-html: 1.0.3\n      etag: 1.8.1\n      fresh: 0.5.2\n      http-errors: 2.0.0\n      mime: 1.6.0\n      ms: 2.1.3\n      on-finished: 2.4.1\n      range-parser: 1.2.1\n      statuses: 2.0.1\n    transitivePeerDependencies:\n      - supports-color\n\n  serve-static@1.16.2:\n    dependencies:\n      encodeurl: 2.0.0\n      escape-html: 1.0.3\n      parseurl: 1.3.3\n      send: 0.19.0\n    transitivePeerDependencies:\n      - supports-color\n\n  set-blocking@2.0.0: {}\n\n  set-function-length@1.2.2:\n    dependencies:\n      define-data-property: 1.1.4\n      es-errors: 1.3.0\n      function-bind: 1.1.2\n      get-intrinsic: 1.3.0\n      gopd: 1.2.0\n      has-property-descriptors: 1.0.2\n\n  set-function-name@2.0.2:\n    dependencies:\n      define-data-property: 1.1.4\n      es-errors: 1.3.0\n      functions-have-names: 1.2.3\n      has-property-descriptors: 1.0.2\n\n  set-proto@1.0.0:\n    dependencies:\n      dunder-proto: 1.0.1\n      es-errors: 1.3.0\n      es-object-atoms: 1.1.1\n\n  setprototypeof@1.2.0: {}\n\n  shebang-command@1.2.0:\n    dependencies:\n      shebang-regex: 1.0.0\n\n  shebang-command@2.0.0:\n    dependencies:\n      shebang-regex: 3.0.0\n\n  shebang-regex@1.0.0: {}\n\n  shebang-regex@3.0.0: {}\n\n  side-channel-list@1.0.0:\n    dependencies:\n      es-errors: 1.3.0\n      object-inspect: 1.13.4\n\n  side-channel-map@1.0.1:\n    dependencies:\n      call-bound: 1.0.4\n      es-errors: 1.3.0\n      get-intrinsic: 1.3.0\n      object-inspect: 1.13.4\n\n  side-channel-weakmap@1.0.2:\n    dependencies:\n      call-bound: 1.0.4\n      es-errors: 1.3.0\n      get-intrinsic: 1.3.0\n      object-inspect: 1.13.4\n      side-channel-map: 1.0.1\n\n  side-channel@1.1.0:\n    dependencies:\n      es-errors: 1.3.0\n      object-inspect: 1.13.4\n      side-channel-list: 1.0.0\n      side-channel-map: 1.0.1\n      side-channel-weakmap: 1.0.2\n\n  signal-exit@3.0.7: {}\n\n  sisteransi@1.0.5: {}\n\n  slash@3.0.0: {}\n\n  slice-ansi@2.1.0:\n    dependencies:\n      ansi-styles: 3.2.1\n      astral-regex: 1.0.0\n      is-fullwidth-code-point: 2.0.0\n\n  sort-object-keys@1.1.3: {}\n\n  sort-package-json@1.57.0:\n    dependencies:\n      detect-indent: 6.1.0\n      detect-newline: 3.1.0\n      git-hooks-list: 1.0.3\n      globby: 10.0.0\n      is-plain-obj: 2.1.0\n      sort-object-keys: 1.1.3\n\n  source-map-support@0.5.21:\n    dependencies:\n      buffer-from: 1.1.2\n      source-map: 0.6.1\n\n  source-map@0.6.1: {}\n\n  source-map@0.7.4: {}\n\n  spawn-wrap@2.0.0:\n    dependencies:\n      foreground-child: 2.0.0\n      is-windows: 1.0.2\n      make-dir: 3.1.0\n      rimraf: 3.0.2\n      signal-exit: 3.0.7\n      which: 2.0.2\n\n  spdx-correct@3.2.0:\n    dependencies:\n      spdx-expression-parse: 3.0.1\n      spdx-license-ids: 3.0.21\n\n  spdx-exceptions@2.5.0: {}\n\n  spdx-expression-parse@3.0.1:\n    dependencies:\n      spdx-exceptions: 2.5.0\n      spdx-license-ids: 3.0.21\n\n  spdx-license-ids@3.0.21: {}\n\n  sprintf-js@1.0.3: {}\n\n  stack-utils@2.0.6:\n    dependencies:\n      escape-string-regexp: 2.0.0\n\n  statuses@1.5.0: {}\n\n  statuses@2.0.1: {}\n\n  string-length@4.0.2:\n    dependencies:\n      char-regex: 1.0.2\n      strip-ansi: 6.0.1\n\n  string-width@3.1.0:\n    dependencies:\n      emoji-regex: 7.0.3\n      is-fullwidth-code-point: 2.0.0\n      strip-ansi: 5.2.0\n\n  string-width@4.2.3:\n    dependencies:\n      emoji-regex: 8.0.0\n      is-fullwidth-code-point: 3.0.0\n      strip-ansi: 6.0.1\n\n  string.prototype.trim@1.2.10:\n    dependencies:\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      define-data-property: 1.1.4\n      define-properties: 1.2.1\n      es-abstract: 1.23.9\n      es-object-atoms: 1.1.1\n      has-property-descriptors: 1.0.2\n\n  string.prototype.trimend@1.0.9:\n    dependencies:\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      define-properties: 1.2.1\n      es-object-atoms: 1.1.1\n\n  string.prototype.trimstart@1.0.8:\n    dependencies:\n      call-bind: 1.0.8\n      define-properties: 1.2.1\n      es-object-atoms: 1.1.1\n\n  string_decoder@1.3.0:\n    dependencies:\n      safe-buffer: 5.2.1\n\n  strip-ansi@5.2.0:\n    dependencies:\n      ansi-regex: 4.1.1\n\n  strip-ansi@6.0.1:\n    dependencies:\n      ansi-regex: 5.0.1\n\n  strip-bom@3.0.0: {}\n\n  strip-bom@4.0.0: {}\n\n  strip-final-newline@2.0.0: {}\n\n  strip-json-comments@3.1.1: {}\n\n  superagent@6.1.0:\n    dependencies:\n      component-emitter: 1.3.1\n      cookiejar: 2.1.4\n      debug: 4.4.0\n      fast-safe-stringify: 2.1.1\n      form-data: 3.0.3\n      formidable: 1.2.6\n      methods: 1.1.2\n      mime: 2.6.0\n      qs: 6.14.0\n      readable-stream: 3.6.2\n      semver: 7.7.1\n    transitivePeerDependencies:\n      - supports-color\n\n  supertest@6.1.6:\n    dependencies:\n      methods: 1.1.2\n      superagent: 6.1.0\n    transitivePeerDependencies:\n      - supports-color\n\n  supports-color@5.5.0:\n    dependencies:\n      has-flag: 3.0.0\n\n  supports-color@7.2.0:\n    dependencies:\n      has-flag: 4.0.0\n\n  supports-color@8.1.1:\n    dependencies:\n      has-flag: 4.0.0\n\n  supports-hyperlinks@2.3.0:\n    dependencies:\n      has-flag: 4.0.0\n      supports-color: 7.2.0\n\n  supports-preserve-symlinks-flag@1.0.0: {}\n\n  symbol-tree@3.2.4: {}\n\n  table@5.4.6:\n    dependencies:\n      ajv: 6.12.6\n      lodash: 4.17.21\n      slice-ansi: 2.1.0\n      string-width: 3.1.0\n\n  terminal-link@2.1.1:\n    dependencies:\n      ansi-escapes: 4.3.2\n      supports-hyperlinks: 2.3.0\n\n  test-exclude@6.0.0:\n    dependencies:\n      '@istanbuljs/schema': 0.1.3\n      glob: 7.2.3\n      minimatch: 3.1.2\n\n  text-table@0.2.0: {}\n\n  throat@6.0.2: {}\n\n  through@2.3.8: {}\n\n  tmp@0.0.33:\n    dependencies:\n      os-tmpdir: 1.0.2\n\n  tmpl@1.0.5: {}\n\n  to-regex-range@5.0.1:\n    dependencies:\n      is-number: 7.0.0\n\n  toidentifier@1.0.1: {}\n\n  tough-cookie@4.1.4:\n    dependencies:\n      psl: 1.15.0\n      punycode: 2.3.1\n      universalify: 0.2.0\n      url-parse: 1.5.10\n\n  tr46@2.1.0:\n    dependencies:\n      punycode: 2.3.1\n\n  tslib@1.14.1: {}\n\n  tsscmp@1.0.6: {}\n\n  type-check@0.3.2:\n    dependencies:\n      prelude-ls: 1.1.2\n\n  type-detect@4.0.8: {}\n\n  type-fest@0.21.3: {}\n\n  type-fest@0.8.1: {}\n\n  type-is@1.6.18:\n    dependencies:\n      media-typer: 0.3.0\n      mime-types: 2.1.35\n\n  typed-array-buffer@1.0.3:\n    dependencies:\n      call-bound: 1.0.4\n      es-errors: 1.3.0\n      is-typed-array: 1.1.15\n\n  typed-array-byte-length@1.0.3:\n    dependencies:\n      call-bind: 1.0.8\n      for-each: 0.3.5\n      gopd: 1.2.0\n      has-proto: 1.2.0\n      is-typed-array: 1.1.15\n\n  typed-array-byte-offset@1.0.4:\n    dependencies:\n      available-typed-arrays: 1.0.7\n      call-bind: 1.0.8\n      for-each: 0.3.5\n      gopd: 1.2.0\n      has-proto: 1.2.0\n      is-typed-array: 1.1.15\n      reflect.getprototypeof: 1.0.10\n\n  typed-array-length@1.0.7:\n    dependencies:\n      call-bind: 1.0.8\n      for-each: 0.3.5\n      gopd: 1.2.0\n      is-typed-array: 1.1.15\n      possible-typed-array-names: 1.1.0\n      reflect.getprototypeof: 1.0.10\n\n  typedarray-to-buffer@3.1.5:\n    dependencies:\n      is-typedarray: 1.0.0\n\n  unbox-primitive@1.1.0:\n    dependencies:\n      call-bound: 1.0.4\n      has-bigints: 1.1.0\n      has-symbols: 1.1.0\n      which-boxed-primitive: 1.1.1\n\n  undici-types@6.21.0: {}\n\n  universalify@0.2.0: {}\n\n  unpipe@1.0.0: {}\n\n  update-browserslist-db@1.1.3(browserslist@4.24.4):\n    dependencies:\n      browserslist: 4.24.4\n      escalade: 3.2.0\n      picocolors: 1.1.1\n\n  uri-js@4.4.1:\n    dependencies:\n      punycode: 2.3.1\n\n  url-parse@1.5.10:\n    dependencies:\n      querystringify: 2.2.0\n      requires-port: 1.0.0\n\n  util-deprecate@1.0.2: {}\n\n  utils-merge@1.0.1: {}\n\n  uuid@8.3.2: {}\n\n  v8-compile-cache@2.4.0: {}\n\n  v8-to-istanbul@8.1.1:\n    dependencies:\n      '@types/istanbul-lib-coverage': 2.0.6\n      convert-source-map: 1.9.0\n      source-map: 0.7.4\n\n  validate-npm-package-license@3.0.4:\n    dependencies:\n      spdx-correct: 3.2.0\n      spdx-expression-parse: 3.0.1\n\n  vary@1.1.2: {}\n\n  w3c-hr-time@1.0.2:\n    dependencies:\n      browser-process-hrtime: 1.0.0\n\n  w3c-xmlserializer@2.0.0:\n    dependencies:\n      xml-name-validator: 3.0.0\n\n  walker@1.0.8:\n    dependencies:\n      makeerror: 1.0.12\n\n  web-streams-polyfill@3.3.3: {}\n\n  webidl-conversions@5.0.0: {}\n\n  webidl-conversions@6.1.0: {}\n\n  whatwg-encoding@1.0.5:\n    dependencies:\n      iconv-lite: 0.4.24\n\n  whatwg-mimetype@2.3.0: {}\n\n  whatwg-url@8.7.0:\n    dependencies:\n      lodash: 4.17.21\n      tr46: 2.1.0\n      webidl-conversions: 6.1.0\n\n  which-boxed-primitive@1.1.1:\n    dependencies:\n      is-bigint: 1.1.0\n      is-boolean-object: 1.2.2\n      is-number-object: 1.1.1\n      is-string: 1.1.1\n      is-symbol: 1.1.1\n\n  which-builtin-type@1.2.1:\n    dependencies:\n      call-bound: 1.0.4\n      function.prototype.name: 1.1.8\n      has-tostringtag: 1.0.2\n      is-async-function: 2.1.1\n      is-date-object: 1.1.0\n      is-finalizationregistry: 1.1.1\n      is-generator-function: 1.1.0\n      is-regex: 1.2.1\n      is-weakref: 1.1.1\n      isarray: 2.0.5\n      which-boxed-primitive: 1.1.1\n      which-collection: 1.0.2\n      which-typed-array: 1.1.19\n\n  which-collection@1.0.2:\n    dependencies:\n      is-map: 2.0.3\n      is-set: 2.0.3\n      is-weakmap: 2.0.2\n      is-weakset: 2.0.4\n\n  which-module@2.0.1: {}\n\n  which-typed-array@1.1.19:\n    dependencies:\n      available-typed-arrays: 1.0.7\n      call-bind: 1.0.8\n      call-bound: 1.0.4\n      for-each: 0.3.5\n      get-proto: 1.0.1\n      gopd: 1.2.0\n      has-tostringtag: 1.0.2\n\n  which@1.3.1:\n    dependencies:\n      isexe: 2.0.0\n\n  which@2.0.2:\n    dependencies:\n      isexe: 2.0.0\n\n  word-wrap@1.2.5: {}\n\n  wrap-ansi@6.2.0:\n    dependencies:\n      ansi-styles: 4.3.0\n      string-width: 4.2.3\n      strip-ansi: 6.0.1\n\n  wrap-ansi@7.0.0:\n    dependencies:\n      ansi-styles: 4.3.0\n      string-width: 4.2.3\n      strip-ansi: 6.0.1\n\n  wrappy@1.0.2: {}\n\n  write-file-atomic@3.0.3:\n    dependencies:\n      imurmurhash: 0.1.4\n      is-typedarray: 1.0.0\n      signal-exit: 3.0.7\n      typedarray-to-buffer: 3.1.5\n\n  write@1.0.3:\n    dependencies:\n      mkdirp: 0.5.6\n\n  ws@7.5.10: {}\n\n  xml-name-validator@3.0.0: {}\n\n  xmlchars@2.2.0: {}\n\n  y18n@4.0.3: {}\n\n  y18n@5.0.8: {}\n\n  yallist@3.1.1: {}\n\n  yargs-parser@18.1.3:\n    dependencies:\n      camelcase: 5.3.1\n      decamelize: 1.2.0\n\n  yargs-parser@20.2.9: {}\n\n  yargs@15.4.1:\n    dependencies:\n      cliui: 6.0.0\n      decamelize: 1.2.0\n      find-up: 4.1.0\n      get-caller-file: 2.0.5\n      require-directory: 2.1.1\n      require-main-filename: 2.0.0\n      set-blocking: 2.0.0\n      string-width: 4.2.3\n      which-module: 2.0.1\n      y18n: 4.0.3\n      yargs-parser: 18.1.3\n\n  yargs@16.2.0:\n    dependencies:\n      cliui: 7.0.4\n      escalade: 3.2.0\n      get-caller-file: 2.0.5\n      require-directory: 2.1.1\n      string-width: 4.2.3\n      y18n: 5.0.8\n      yargs-parser: 20.2.9\n\n  ylru@1.4.0: {}\n"
  },
  {
    "path": "src/Formidable.js",
    "content": "/* eslint-disable class-methods-use-this */\n/* eslint-disable no-underscore-dangle */\n\nimport { init as cuid2init } from '@paralleldrive/cuid2';\nimport dezalgo from 'dezalgo';\nimport { EventEmitter } from 'node:events';\nimport fsPromises from 'node:fs/promises';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { StringDecoder } from 'node:string_decoder';\nimport once from 'once';\nimport FormidableError, * as errors from './FormidableError.js';\nimport PersistentFile from './PersistentFile.js';\nimport VolatileFile from './VolatileFile.js';\nimport DummyParser from './parsers/Dummy.js';\nimport MultipartParser from './parsers/Multipart.js';\nimport { json, multipart, octetstream, querystring } from './plugins/index.js';\n\nconst CUID2_FINGERPRINT = `${process.env.NODE_ENV}-${os.platform()}-${os.hostname()}`\nconst createId = cuid2init({ length: 25, fingerprint: CUID2_FINGERPRINT.toLowerCase() });\n\nconst DEFAULT_OPTIONS = {\n  maxFields: 1000,\n  maxFieldsSize: 20 * 1024 * 1024,\n  maxFiles: 1000,\n  maxFileSize: 200 * 1024 * 1024,\n  maxTotalFileSize: undefined,\n  minFileSize: 1,\n  allowEmptyFiles: false,\n  createDirsFromUploads: false,\n  keepExtensions: false,\n  encoding: 'utf-8',\n  hashAlgorithm: false,\n  uploadDir: os.tmpdir(),\n  enabledPlugins: [octetstream, querystring, multipart, json],\n  fileWriteStreamHandler: null,\n  defaultInvalidName: 'invalid-name',\n  filter(_part) {\n    return true;\n  },\n  filename: undefined,\n};\n\nfunction hasOwnProp(obj, key) {\n  return Object.prototype.hasOwnProperty.call(obj, key);\n}\n\n\nconst decorateForceSequential = function (promiseCreator) {\n  /* forces a function that returns a promise to be sequential\n  useful for fs  for example */\n  let lastPromise = Promise.resolve();\n  return async function (...x) {\n      const promiseWeAreWaitingFor = lastPromise;\n      let currentPromise;\n      let callback;\n      // we need to change lastPromise before await anything,\n      // otherwise 2 calls might wait the same thing\n      lastPromise = new Promise(function (resolve) {\n          callback = resolve;\n      });\n      await promiseWeAreWaitingFor;\n      currentPromise = promiseCreator(...x);\n      currentPromise.then(callback).catch(callback);\n      return currentPromise;\n  };\n};\n\nconst createNecessaryDirectoriesAsync = decorateForceSequential(function (filePath) {\n  const directoryname = path.dirname(filePath);\n  return fsPromises.mkdir(directoryname, { recursive: true });\n});\n\nconst invalidExtensionChar = (c) => {\n  const code = c.charCodeAt(0);\n  return !(\n    code === 46 || // .\n    (code >= 48 && code <= 57) ||\n    (code >= 65 && code <= 90) ||\n    (code >= 97 && code <= 122)\n  );\n};\n\nclass IncomingForm extends EventEmitter {\n  constructor(options = {}) {\n    super();\n\n    this.options = { ...DEFAULT_OPTIONS, ...options };\n    if (!this.options.maxTotalFileSize) {\n      this.options.maxTotalFileSize = this.options.maxFileSize\n    }\n\n    const dir = path.resolve(\n      this.options.uploadDir || this.options.uploaddir || os.tmpdir(),\n    );\n\n    this.uploaddir = dir;\n    this.uploadDir = dir;\n\n    // initialize with null\n    [\n      'error',\n      'headers',\n      'type',\n      'bytesExpected',\n      'bytesReceived',\n      '_parser',\n      'req',\n    ].forEach((key) => {\n      this[key] = null;\n    });\n\n    this._setUpRename();\n\n    this._flushing = 0;\n    this._fieldsSize = 0;\n    this._totalFileSize = 0;\n    this._plugins = [];\n    this.openedFiles = [];\n\n    this.options.enabledPlugins = []\n      .concat(this.options.enabledPlugins)\n      .filter(Boolean);\n\n    if (this.options.enabledPlugins.length === 0) {\n      throw new FormidableError(\n        'expect at least 1 enabled builtin plugin, see options.enabledPlugins',\n        errors.missingPlugin,\n      );\n    }\n\n    this.options.enabledPlugins.forEach((plugin) => {\n      this.use(plugin);\n    });\n\n    this._setUpMaxFields();\n    this._setUpMaxFiles();\n    this.ended = undefined;\n    this.type = undefined;\n  }\n\n  use(plugin) {\n    if (typeof plugin !== 'function') {\n      throw new FormidableError(\n        '.use: expect `plugin` to be a function',\n        errors.pluginFunction,\n      );\n    }\n    this._plugins.push(plugin.bind(this));\n    return this;\n  }\n\n  pause () {\n    try {\n      this.req.pause();\n    } catch (err) {\n      // the stream was destroyed\n      if (!this.ended) {\n        // before it was completed, crash & burn\n        this._error(err);\n      }\n      return false;\n    }\n    return true;\n  }\n\n  resume () {\n    try {\n      this.req.resume();\n    } catch (err) {\n      // the stream was destroyed\n      if (!this.ended) {\n        // before it was completed, crash & burn\n        this._error(err);\n      }\n      return false;\n    }\n\n    return true;\n  }\n\n  // returns a promise if no callback is provided\n  async parse(req, cb) {\n    this.req = req;\n    let promise;\n\n    // Setup callback first, so we don't miss anything from data events emitted immediately.\n    if (!cb) {\n      let resolveRef;\n      let rejectRef;\n      promise = new Promise((resolve, reject) => {\n        resolveRef = resolve;\n        rejectRef = reject;\n      });\n      cb = (err, fields, files) => {\n        if (err) {\n          rejectRef(err);\n        } else {\n          resolveRef([fields, files]);\n        }\n      }\n    }\n    const callback = once(dezalgo(cb));\n    this.fields = {};\n    const files = {};\n\n    this.on('field', (name, value) => {\n      if (this.type === 'multipart' || this.type === 'urlencoded') {\n        if (!hasOwnProp(this.fields, name)) {\n          this.fields[name] = [value];\n        } else {\n          this.fields[name].push(value);\n        }\n      } else {\n        this.fields[name] = value;\n      }\n    });\n    this.on('file', (name, file) => {\n      if (!hasOwnProp(files, name)) {\n        files[name] = [file];\n      } else {\n        files[name].push(file);\n      }\n    });\n    this.on('error', (err) => {\n      callback(err, this.fields, files);\n    });\n    this.on('end', () => {\n      callback(null, this.fields, files);\n    });\n\n    // Parse headers and setup the parser, ready to start listening for data.\n    await this.writeHeaders(req.headers);\n\n    let datafn = (buffer) => {\n      try {\n        this.write(buffer);\n      } catch (err) {\n        this._error(err);\n      }\n    }\n    let endfn = () => {\n      if (this.error) {\n        return;\n      }\n      if (this._parser) {\n        this._parser.end();\n      }\n    }\n    let pipe = null;\n    \n    // Start listening for data.\n    req\n      .on('error', (err) => {\n        this._error(err);\n      })\n      .on('aborted', () => {\n        this.emit('aborted');\n        this._error(new FormidableError('Request aborted', errors.aborted));\n      }) \n\n    switch (this.headers['content-encoding']) {\n      case \"gzip\":\n        pipe = require(\"zlib\").createGunzip();\n        break;\n      case \"deflate\":\n        pipe = require(\"zlib\").createInflate();\n        break;\n      case \"br\":\n        pipe = require(\"zlib\").createBrotliDecompress();\n        break;\n      case \"compress\":\n        pipe = require(\"zlib\").createUnzip();\n        break;\n      \n      default: \n        pipe = node_stream.Transform({\n          transform: function (chunk, encoding, callback)  {\n            callback(null, chunk);\n          }\n\n        })\n    }\n    pipe.on(\"data\", datafn).on('end', endfn);\n    req.pipe(pipe)\n    \n    if (promise) {\n      return promise;\n    }\n    return this;\n  }\n\n  async writeHeaders(headers) {\n    this.headers = headers;\n    this._parseContentLength();\n    await this._parseContentType();\n\n    if (!this._parser) {\n      this._error(\n        new FormidableError(\n          'no parser found',\n          errors.noParser,\n          415, // Unsupported Media Type\n        ),\n      );\n      return;\n    }\n\n    this._parser.once('error', (error) => {\n      this._error(error);\n    });\n  }\n\n  write(buffer) {\n    if (this.error) {\n      return null;\n    }\n    if (!this._parser) {\n      this._error(\n        new FormidableError('uninitialized parser', errors.uninitializedParser),\n      );\n      return null;\n    }\n\n    this.bytesReceived += buffer.length;\n    this.emit('progress', this.bytesReceived, this.bytesExpected);\n\n    this._parser.write(buffer);\n\n    return this.bytesReceived;\n  }\n\n  onPart(part) {\n    // this method can be overwritten by the user\n    return this._handlePart(part);\n  }\n\n  async _handlePart(part) {\n    if (part.originalFilename && typeof part.originalFilename !== 'string') {\n      this._error(\n        new FormidableError(\n          `the part.originalFilename should be string when it exists`,\n          errors.filenameNotString,\n        ),\n      );\n      return;\n    }\n\n    // This MUST check exactly for undefined. You can not change it to !part.originalFilename.\n\n    // todo: uncomment when switch tests to Jest\n    // console.log(part);\n\n    // ? NOTE(@tunnckocore): no it can be any falsey value, it most probably depends on what's returned\n    // from somewhere else. Where recently I changed the return statements\n    // and such thing because code style\n    // ? NOTE(@tunnckocore): or even better, if there is no mimetype, then it's for sure a field\n    // ? NOTE(@tunnckocore): originalFilename is an empty string when a field?\n    if (!part.mimetype) {\n      let value = '';\n      const decoder = new StringDecoder(\n        part.transferEncoding || this.options.encoding,\n      );\n\n      part.on('data', (buffer) => {\n        this._fieldsSize += buffer.length;\n        if (this._fieldsSize > this.options.maxFieldsSize) {\n          this._error(\n            new FormidableError(\n              `options.maxFieldsSize (${this.options.maxFieldsSize} bytes) exceeded, received ${this._fieldsSize} bytes of field data`,\n              errors.maxFieldsSizeExceeded,\n              413, // Payload Too Large\n            ),\n          );\n          return;\n        }\n        value += decoder.write(buffer);\n      });\n\n      part.on('end', () => {\n        this.emit('field', part.name, value);\n      });\n      return;\n    }\n\n    if (!this.options.filter(part)) {\n      return;\n    }\n\n    this._flushing += 1;\n\n    let fileSize = 0;\n    const newFilename = this._getNewName(part);\n    const filepath = this._joinDirectoryName(newFilename);\n    const file = await this._newFile({\n      newFilename,\n      filepath,\n      originalFilename: part.originalFilename,\n      mimetype: part.mimetype,\n    });\n    file.on('error', (err) => {\n      this._error(err);\n    });\n    this.emit('fileBegin', part.name, file);\n\n    file.open();\n    this.openedFiles.push(file);\n\n    part.on('data', (buffer) => {\n      this._totalFileSize += buffer.length;\n      fileSize += buffer.length;\n\n      if (this._totalFileSize > this.options.maxTotalFileSize) {\n        this._error(\n          new FormidableError(\n            `options.maxTotalFileSize (${this.options.maxTotalFileSize} bytes) exceeded, received ${this._totalFileSize} bytes of file data`,\n            errors.biggerThanTotalMaxFileSize,\n            413,\n          ),\n        );\n        return;\n      }\n      if (buffer.length === 0) {\n        return;\n      }\n      this.pause();\n      file.write(buffer, () => {\n        this.resume();\n      });\n    });\n\n    part.on('end', () => {\n      if (!this.options.allowEmptyFiles && fileSize === 0) {\n        this._error(\n          new FormidableError(\n            `options.allowEmptyFiles is false, file size should be greater than 0`,\n            errors.noEmptyFiles,\n            400,\n          ),\n        );\n        return;\n      }\n      if (fileSize < this.options.minFileSize) {\n        this._error(\n          new FormidableError(\n            `options.minFileSize (${this.options.minFileSize} bytes) inferior, received ${fileSize} bytes of file data`,\n            errors.smallerThanMinFileSize,\n            400,\n          ),\n        );\n        return;\n      }\n      if (fileSize > this.options.maxFileSize) {\n        this._error(\n          new FormidableError(\n            `options.maxFileSize (${this.options.maxFileSize} bytes), received ${fileSize} bytes of file data`,\n            errors.biggerThanMaxFileSize,\n            413,\n          ),\n        );\n        return;\n      }\n\n      file.end(() => {\n        this._flushing -= 1;\n        this.emit('file', part.name, file);\n        this._maybeEnd();\n      });\n    });\n  }\n\n  // eslint-disable-next-line max-statements\n  async _parseContentType() {\n    if (this.bytesExpected === 0) {\n      this._parser = new DummyParser(this, this.options);\n      return;\n    }\n\n    if (!this.headers['content-type']) {\n      this._error(\n        new FormidableError(\n          'bad content-type header, no content-type',\n          errors.missingContentType,\n          400,\n        ),\n      );\n      return;\n    }\n\n\n    new DummyParser(this, this.options);\n\n    const results = [];\n    await Promise.all(this._plugins.map(async (plugin, idx) => {\n      let pluginReturn = null;\n      try {\n        pluginReturn = await plugin(this, this.options) || this;\n      } catch (err) {\n        // directly throw from the `form.parse` method;\n        // there is no other better way, except a handle through options\n        const error = new FormidableError(\n          `plugin on index ${idx} failed with: ${err.message}`,\n          errors.pluginFailed,\n          500,\n        );\n        error.idx = idx;\n        throw error;\n      }\n      Object.assign(this, pluginReturn);\n\n      // todo: use Set/Map and pass plugin name instead of the `idx` index\n      this.emit('plugin', idx, pluginReturn);\n    }));\n    this.emit('pluginsResults', results);\n  }\n\n  _error(err, eventName = 'error') {\n    if (this.error || this.ended) {\n      return;\n    }\n\n    this.req = null;\n    this.error = err;\n    this.emit(eventName, err);\n\n    this.openedFiles.forEach((file) => {\n      file.destroy();\n    });\n  }\n\n  _parseContentLength() {\n    this.bytesReceived = 0;\n    if (this.headers['content-length']) {\n      this.bytesExpected = parseInt(this.headers['content-length'], 10);\n    } else if (this.headers['transfer-encoding'] === undefined) {\n      this.bytesExpected = 0;\n    }\n\n    if (this.bytesExpected !== null) {\n      this.emit('progress', this.bytesReceived, this.bytesExpected);\n    }\n  }\n\n  _newParser() {\n    return new MultipartParser(this.options);\n  }\n\n  async _newFile({ filepath, originalFilename, mimetype, newFilename }) {\n    if (this.options.fileWriteStreamHandler) {\n      return new VolatileFile({\n        newFilename,\n        filepath,\n        originalFilename,\n        mimetype,\n        createFileWriteStream: this.options.fileWriteStreamHandler,\n        hashAlgorithm: this.options.hashAlgorithm,\n      });\n    }\n    if (this.options.createDirsFromUploads) {\n      try {\n        await createNecessaryDirectoriesAsync(filepath);\n      } catch (errorCreatingDir) {\n        this._error(new FormidableError(\n          `cannot create directory`,\n          errors.cannotCreateDir,\n          409,\n        ));\n      }\n    }\n    return new PersistentFile({\n      newFilename,\n      filepath,\n      originalFilename,\n      mimetype,\n      hashAlgorithm: this.options.hashAlgorithm,\n    });\n  }\n\n  _getFileName(headerValue) {\n    // matches either a quoted-string or a token (RFC 2616 section 19.5.1)\n    const m = headerValue.match(\n      /\\bfilename=(\"(.*?)\"|([^()<>{}[\\]@,;:\"?=\\s/\\t]+))($|;\\s)/i,\n    );\n    if (!m) return null;\n\n    const match = m[2] || m[3] || '';\n    let originalFilename = match.substr(match.lastIndexOf('\\\\') + 1);\n    originalFilename = originalFilename.replace(/%22/g, '\"');\n    originalFilename = originalFilename.replace(/&#([\\d]{4});/g, (_, code) =>\n      String.fromCharCode(code),\n    );\n\n    return originalFilename;\n  }\n\n  // able to get composed extension with multiple dots\n  // \"a.b.c\" -> \".b.c\"\n  // as opposed to path.extname -> \".c\"\n  _getExtension(str) {\n    if (!str) {\n      return '';\n    }\n\n    const basename = path.basename(str);\n    const firstDot = basename.indexOf('.');\n    const lastDot = basename.lastIndexOf('.');\n    let rawExtname = path.extname(basename);\n\n    if (firstDot !== lastDot) {\n      rawExtname =  basename.slice(firstDot);\n    }\n\n    let filtered;\n    const firstInvalidIndex = Array.from(rawExtname).findIndex(invalidExtensionChar);\n    if (firstInvalidIndex === -1) {\n      filtered = rawExtname;\n    } else {\n      filtered = rawExtname.substring(0, firstInvalidIndex);\n    }\n    if (filtered === '.') {\n      return '';\n    }\n    return filtered;\n  }\n\n  _joinDirectoryName(name) {\n    const resolvedDir = path.resolve(this.uploadDir);\n    const resolvedPath = path.resolve(resolvedDir, name);\n\n    // prevent directory traversal attacks\n    // use resolvedDir + path.sep to avoid prefix collisions with sibling directories\n    // e.g. uploadDir \"/tmp/uploads\" should not allow writes to \"/tmp/uploads-evil/\"\n    if (resolvedPath === resolvedDir || !resolvedPath.startsWith(resolvedDir + path.sep)) {\n      return path.join(this.uploadDir, this.options.defaultInvalidName);\n    }\n\n    return resolvedPath;\n  }\n\n  _setUpRename() {\n    const hasRename = typeof this.options.filename === 'function';\n    if (hasRename) {\n      this._getNewName = (part) => {\n        let ext = '';\n        let name = this.options.defaultInvalidName;\n        if (part.originalFilename) {\n          // can be null\n          ({ ext, name } = path.parse(part.originalFilename));\n          if (this.options.keepExtensions !== true) {\n            ext = '';\n          }\n        }\n        return this.options.filename.call(this, name, ext, part, this);\n      };\n    } else {\n      this._getNewName = (part) => {\n        const name = createId();\n\n        if (part && this.options.keepExtensions) {\n          const originalFilename =\n            typeof part === 'string' ? part : part.originalFilename;\n          return `${name}${this._getExtension(originalFilename)}`;\n        }\n\n        return name;\n      };\n    }\n  }\n\n  _setUpMaxFields() {\n    if (this.options.maxFields !== Infinity) {\n      let fieldsCount = 0;\n      this.on('field', () => {\n        fieldsCount += 1;\n        if (fieldsCount > this.options.maxFields) {\n          this._error(\n            new FormidableError(\n              `options.maxFields (${this.options.maxFields}) exceeded`,\n              errors.maxFieldsExceeded,\n              413,\n            ),\n          );\n        }\n      });\n    }\n  }\n\n  _setUpMaxFiles() {\n    if (this.options.maxFiles !== Infinity) {\n      let fileCount = 0;\n      this.on('fileBegin', () => {\n        fileCount += 1;\n        if (fileCount > this.options.maxFiles) {\n          this._error(\n            new FormidableError(\n              `options.maxFiles (${this.options.maxFiles}) exceeded`,\n              errors.maxFilesExceeded,\n              413,\n            ),\n          );\n        }\n      });\n    }\n  }\n\n  _maybeEnd() {\n    if (!this.ended || this._flushing || this.error) {\n      return;\n    }\n    this.req = null;\n    this.emit('end');\n  }\n}\n\nexport default IncomingForm;\nexport { DEFAULT_OPTIONS };\n"
  },
  {
    "path": "src/FormidableError.js",
    "content": "const missingPlugin = 1000;\nconst pluginFunction = 1001;\nconst aborted = 1002;\nconst noParser = 1003;\nconst uninitializedParser = 1004;\nconst filenameNotString = 1005;\nconst maxFieldsSizeExceeded = 1006;\nconst maxFieldsExceeded = 1007;\nconst smallerThanMinFileSize = 1008;\nconst biggerThanTotalMaxFileSize = 1009;\nconst noEmptyFiles = 1010;\nconst missingContentType = 1011;\nconst malformedMultipart = 1012;\nconst missingMultipartBoundary = 1013;\nconst unknownTransferEncoding = 1014;\nconst maxFilesExceeded = 1015;\nconst biggerThanMaxFileSize = 1016;\nconst pluginFailed = 1017;\nconst cannotCreateDir = 1018;\n\nconst FormidableError = class extends Error {\n  constructor(message, internalCode, httpCode = 500) {\n    super(message);\n    this.code = internalCode;\n    this.httpCode = httpCode;\n  }\n};\n\nexport {\n  missingPlugin,\n  pluginFunction,\n  aborted,\n  noParser,\n  uninitializedParser,\n  filenameNotString,\n  maxFieldsSizeExceeded,\n  maxFieldsExceeded,\n  maxFilesExceeded,\n  smallerThanMinFileSize,\n  biggerThanMaxFileSize,\n  noEmptyFiles,\n  missingContentType,\n  malformedMultipart,\n  missingMultipartBoundary,\n  unknownTransferEncoding,\n  biggerThanTotalMaxFileSize,\n  pluginFailed,\n  cannotCreateDir,\n};\n\nexport default FormidableError;\n"
  },
  {
    "path": "src/PersistentFile.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\nimport fs from 'node:fs';\nimport crypto from 'node:crypto';\nimport { EventEmitter } from 'node:events';\n\nclass PersistentFile extends EventEmitter {\n  constructor({ filepath, newFilename, originalFilename, mimetype, hashAlgorithm }) {\n    super();\n\n    this.lastModifiedDate = null;\n    Object.assign(this, { filepath, newFilename, originalFilename, mimetype, hashAlgorithm });\n\n    this.size = 0;\n    this._writeStream = null;\n\n    if (typeof this.hashAlgorithm === 'string') {\n      this.hash = crypto.createHash(this.hashAlgorithm);\n    } else {\n      this.hash = null;\n    }\n  }\n\n  open() {\n    this._writeStream = fs.createWriteStream(this.filepath);\n    this._writeStream.on('error', (err) => {\n      this.emit('error', err);\n    });\n  }\n\n  toJSON() {\n    const json = {\n      size: this.size,\n      filepath: this.filepath,\n      newFilename: this.newFilename,\n      mimetype: this.mimetype,\n      mtime: this.lastModifiedDate,\n      length: this.length,\n      originalFilename: this.originalFilename,\n    };\n    if (this.hash && this.hash !== '') {\n      json.hash = this.hash;\n    }\n    return json;\n  }\n\n  toString() {\n    return `PersistentFile: ${this.newFilename}, Original: ${this.originalFilename}, Path: ${this.filepath}`;\n  }\n\n  write(buffer, cb) {\n    if (this.hash) {\n      this.hash.update(buffer);\n    }\n\n    if (this._writeStream.closed) {\n      cb();\n      return;\n    }\n\n    this._writeStream.write(buffer, () => {\n      this.lastModifiedDate = new Date();\n      this.size += buffer.length;\n      this.emit('progress', this.size);\n      cb();\n    });\n  }\n\n  end(cb) {\n    if (this.hash) {\n      this.hash = this.hash.digest('hex');\n    }\n    this._writeStream.end(() => {\n      this.emit('end');\n      cb();\n    });\n  }\n\n  destroy() {\n    this._writeStream.destroy();\n    const filepath = this.filepath; \n    setTimeout(function () {\n        fs.unlink(filepath, () => {});\n    }, 1)\n  }\n}\n\nexport default PersistentFile;\n"
  },
  {
    "path": "src/VolatileFile.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\nimport { createHash } from 'node:crypto';\nimport { EventEmitter } from 'node:events';\n\nclass VolatileFile extends EventEmitter {\n  constructor({ filepath, newFilename, originalFilename, mimetype, hashAlgorithm, createFileWriteStream }) {\n    super();\n\n    this.lastModifiedDate = null;\n    Object.assign(this, { filepath, newFilename, originalFilename, mimetype, hashAlgorithm, createFileWriteStream });\n\n    this.size = 0;\n    this._writeStream = null;\n\n    if (typeof this.hashAlgorithm === 'string') {\n      this.hash = createHash(this.hashAlgorithm);\n    } else {\n      this.hash = null;\n    }\n  }\n\n  open() {\n    this._writeStream = this.createFileWriteStream(this);\n    this._writeStream.on('error', (err) => {\n      this.emit('error', err);\n    });\n  }\n\n  destroy() {\n    this._writeStream.destroy();\n  }\n\n  toJSON() {\n    const json = {\n      size: this.size,\n      newFilename: this.newFilename,\n      length: this.length,\n      originalFilename: this.originalFilename,\n      mimetype: this.mimetype,\n    };\n    if (this.hash && this.hash !== '') {\n      json.hash = this.hash;\n    }\n    return json;\n  }\n\n  toString() {\n    return `VolatileFile: ${this.originalFilename}`;\n  }\n\n  write(buffer, cb) {\n    if (this.hash) {\n      this.hash.update(buffer);\n    }\n\n    if (this._writeStream.closed || this._writeStream.destroyed) {\n      cb();\n      return;\n    }\n\n    this._writeStream.write(buffer, () => {\n      this.size += buffer.length;\n      this.emit('progress', this.size);\n      cb();\n    });\n  }\n\n  end(cb) {\n    if (this.hash) {\n      this.hash = this.hash.digest('hex');\n    }\n    this._writeStream.end(() => {\n      this.emit('end');\n      cb();\n    });\n  }\n}\n\nexport default VolatileFile;\n"
  },
  {
    "path": "src/helpers/firstValues.js",
    "content": "import { multipartType } from '../plugins/multipart.js';\nimport { querystringType } from '../plugins/querystring.js';\n\nconst firstValues = (form, fields, exceptions = []) => {\n  if (form.type !== querystringType && form.type !== multipartType) {\n    return fields;\n  }\n\n  return Object.fromEntries(\n    Object.entries(fields).map(([key, value]) => {\n      if (exceptions.includes(key)) {\n        return [key, value];\n      }\n      return [key, value[0]];\n    }),\n  );\n};\n\nexport { firstValues };\n"
  },
  {
    "path": "src/helpers/readBooleans.js",
    "content": "const readBooleans = (fields, listOfBooleans) => {\n  // html forms do not send off at all\n  const fieldsWithBooleans = { ...fields };\n  listOfBooleans.forEach((key) => {\n    fieldsWithBooleans[key] = fields[key] === `on` || fields[key] === true;\n  });\n  return fieldsWithBooleans;\n};\n\nexport { readBooleans };\n"
  },
  {
    "path": "src/index.js",
    "content": "import PersistentFile from './PersistentFile.js';\nimport VolatileFile from './VolatileFile.js';\nimport Formidable, { DEFAULT_OPTIONS } from './Formidable.js';\n\n\n\n// make it available without requiring the `new` keyword\n// if you want it access `const formidable.IncomingForm` as v1\nconst formidable = (...args) => new Formidable(...args);\nconst {enabledPlugins} = DEFAULT_OPTIONS;\n\nexport default formidable;\nexport {\n  PersistentFile as File,\n  PersistentFile,\n  VolatileFile,\n  Formidable,\n  // alias\n  Formidable as IncomingForm,\n\n  // as named\n  formidable,\n\n\n  // misc\n  DEFAULT_OPTIONS as defaultOptions,\n  enabledPlugins,  \n};\n\nexport * from './parsers/index.js';\nexport * from './plugins/index.js';\nexport * as errors from './FormidableError.js';"
  },
  {
    "path": "src/parsers/Dummy.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\nimport { Transform } from 'node:stream';\n\nclass DummyParser extends Transform {\n  constructor(incomingForm, options = {}) {\n    super();\n    this.globalOptions = { ...options };\n    this.incomingForm = incomingForm;\n  }\n\n  _flush(callback) {\n    this.incomingForm.ended = true;\n    this.incomingForm._maybeEnd();\n    callback();\n  }\n}\n\nexport default DummyParser;\n"
  },
  {
    "path": "src/parsers/JSON.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\nimport { Transform } from 'node:stream';\n\nclass JSONParser extends Transform {\n  constructor(options = {}) {\n    super({ readableObjectMode: true });\n    this.chunks = [];\n    this.globalOptions = { ...options };\n  }\n\n  _transform(chunk, encoding, callback) {\n    this.chunks.push(String(chunk)); // todo consider using a string decoder\n    callback();\n  }\n\n  _flush(callback) {\n    try {\n      const fields = JSON.parse(this.chunks.join(''));\n      this.push(fields);\n    } catch (e) {\n      callback(e);\n      return;\n    }\n    this.chunks = null;\n    callback();\n  }\n}\n\nexport default JSONParser;\n"
  },
  {
    "path": "src/parsers/Multipart.js",
    "content": "/* eslint-disable no-fallthrough */\n/* eslint-disable no-bitwise */\n/* eslint-disable no-plusplus */\n/* eslint-disable no-underscore-dangle */\n\nimport { Transform } from 'node:stream';\nimport * as errors from '../FormidableError.js';\nimport FormidableError from '../FormidableError.js';\n\nlet s = 0;\nconst STATE = {\n  PARSER_UNINITIALIZED: s++,\n  START: s++,\n  START_BOUNDARY: s++,\n  HEADER_FIELD_START: s++,\n  HEADER_FIELD: s++,\n  HEADER_VALUE_START: s++,\n  HEADER_VALUE: s++,\n  HEADER_VALUE_ALMOST_DONE: s++,\n  HEADERS_ALMOST_DONE: s++,\n  PART_DATA_START: s++,\n  PART_DATA: s++,\n  PART_END: s++,\n  END: s++,\n};\n\nlet f = 1;\nconst FBOUNDARY = { PART_BOUNDARY: f, LAST_BOUNDARY: (f *= 2) };\n\nconst LF = 10;\nconst CR = 13;\nconst SPACE = 32;\nconst HYPHEN = 45;\nconst COLON = 58;\nconst A = 97;\nconst Z = 122;\n\nfunction lower(c) {\n  return c | 0x20;\n}\n\nexport const STATES = {};\n\nObject.keys(STATE).forEach((stateName) => {\n  STATES[stateName] = STATE[stateName];\n});\n\nclass MultipartParser extends Transform {\n  constructor(options = {}) {\n    super({ readableObjectMode: true });\n    this.boundary = null;\n    this.boundaryChars = null;\n    this.lookbehind = null;\n    this.bufferLength = 0;\n    this.state = STATE.PARSER_UNINITIALIZED;\n\n    this.globalOptions = { ...options };\n    this.index = null;\n    this.flags = 0;\n  }\n\n  _endUnexpected() {\n    return new FormidableError(\n      `MultipartParser.end(): stream ended unexpectedly: ${this.explain()}`,\n      errors.malformedMultipart,\n      400,\n    );\n  }\n\n  _flush(done) {\n    if (\n      (this.state === STATE.HEADER_FIELD_START && this.index === 0) ||\n      (this.state === STATE.PART_DATA && this.index === this.boundary.length)\n    ) {\n      this._handleCallback('partEnd');\n      this._handleCallback('end');\n      done();\n    } else if (this.state !== STATE.END) {\n      done(this._endUnexpected());\n    } else {\n      done();\n    }\n  }\n\n  initWithBoundary(str) {\n    this.boundary = Buffer.from(`\\r\\n--${str}`);\n    this.lookbehind = Buffer.alloc(this.boundary.length + 8);\n    this.state = STATE.START;\n    this.boundaryChars = {};\n\n    for (let i = 0; i < this.boundary.length; i++) {\n      this.boundaryChars[this.boundary[i]] = true;\n    }\n  }\n\n  // eslint-disable-next-line max-params\n  _handleCallback(name, buf, start, end) {\n    if (start !== undefined && start === end) {\n      return;\n    }\n    this.push({ name, buffer: buf, start, end });\n  }\n\n  // eslint-disable-next-line max-statements\n  _transform(buffer, _, done) {\n    let i = 0;\n    let prevIndex = this.index;\n    let { index, state, flags } = this;\n    const { lookbehind, boundary, boundaryChars } = this;\n    const boundaryLength = boundary.length;\n    const boundaryEnd = boundaryLength - 1;\n    this.bufferLength = buffer.length;\n    let c = null;\n    let cl = null;\n\n    const setMark = (name, idx) => {\n      this[`${name}Mark`] = typeof idx === 'number' ? idx : i;\n    };\n\n    const clearMarkSymbol = (name) => {\n      delete this[`${name}Mark`];\n    };\n\n    const dataCallback = (name, shouldClear) => {\n      const markSymbol = `${name}Mark`;\n      if (!(markSymbol in this)) {\n        return;\n      }\n\n      if (!shouldClear) {\n        this._handleCallback(name, buffer, this[markSymbol], buffer.length);\n        setMark(name, 0);\n      } else {\n        this._handleCallback(name, buffer, this[markSymbol], i);\n        clearMarkSymbol(name);\n      }\n    };\n\n    for (i = 0; i < this.bufferLength; i++) {\n      c = buffer[i];\n      switch (state) {\n        case STATE.PARSER_UNINITIALIZED:\n          done(this._endUnexpected());\n          return;\n        case STATE.START:\n          index = 0;\n          state = STATE.START_BOUNDARY;\n        case STATE.START_BOUNDARY:\n          if (index === boundary.length - 2) {\n            if (c === HYPHEN) {\n              flags |= FBOUNDARY.LAST_BOUNDARY;\n            } else if (c !== CR) {\n              done(this._endUnexpected());\n              return;\n            }\n            index++;\n            break;\n          } else if (index - 1 === boundary.length - 2) {\n            if (flags & FBOUNDARY.LAST_BOUNDARY && c === HYPHEN) {\n              this._handleCallback('end');\n              state = STATE.END;\n              flags = 0;\n            } else if (!(flags & FBOUNDARY.LAST_BOUNDARY) && c === LF) {\n              index = 0;\n              this._handleCallback('partBegin');\n              state = STATE.HEADER_FIELD_START;\n            } else {\n              done(this._endUnexpected());\n              return;\n            }\n            break;\n          }\n\n          if (c !== boundary[index + 2]) {\n            index = -2;\n          }\n          if (c === boundary[index + 2]) {\n            index++;\n          }\n          break;\n        case STATE.HEADER_FIELD_START:\n          state = STATE.HEADER_FIELD;\n          setMark('headerField');\n          index = 0;\n        case STATE.HEADER_FIELD:\n          if (c === CR) {\n            clearMarkSymbol('headerField');\n            state = STATE.HEADERS_ALMOST_DONE;\n            break;\n          }\n\n          index++;\n          if (c === HYPHEN) {\n            break;\n          }\n\n          if (c === COLON) {\n            if (index === 1) {\n              // empty header field\n              done(this._endUnexpected());\n              return;\n            }\n            dataCallback('headerField', true);\n            state = STATE.HEADER_VALUE_START;\n            break;\n          }\n\n          cl = lower(c);\n          if (cl < A || cl > Z) {\n            done(this._endUnexpected());\n            return;\n          }\n          break;\n        case STATE.HEADER_VALUE_START:\n          if (c === SPACE) {\n            break;\n          }\n\n          setMark('headerValue');\n          state = STATE.HEADER_VALUE;\n        case STATE.HEADER_VALUE:\n          if (c === CR) {\n            dataCallback('headerValue', true);\n            this._handleCallback('headerEnd');\n            state = STATE.HEADER_VALUE_ALMOST_DONE;\n          }\n          break;\n        case STATE.HEADER_VALUE_ALMOST_DONE:\n          if (c !== LF) {\n            done(this._endUnexpected());\nreturn;\n          }\n          state = STATE.HEADER_FIELD_START;\n          break;\n        case STATE.HEADERS_ALMOST_DONE:\n          if (c !== LF) {\n            done(this._endUnexpected());\n            return;\n          }\n\n          this._handleCallback('headersEnd');\n          state = STATE.PART_DATA_START;\n          break;\n        case STATE.PART_DATA_START:\n          state = STATE.PART_DATA;\n          setMark('partData');\n        case STATE.PART_DATA:\n          prevIndex = index;\n\n          if (index === 0) {\n            // boyer-moore derived algorithm to safely skip non-boundary data\n            i += boundaryEnd;\n            while (i < this.bufferLength && !(buffer[i] in boundaryChars)) {\n              i += boundaryLength;\n            }\n            i -= boundaryEnd;\n            c = buffer[i];\n          }\n\n          if (index < boundary.length) {\n            if (boundary[index] === c) {\n              if (index === 0) {\n                dataCallback('partData', true);\n              }\n              index++;\n            } else {\n              index = 0;\n            }\n          } else if (index === boundary.length) {\n            index++;\n            if (c === CR) {\n              // CR = part boundary\n              flags |= FBOUNDARY.PART_BOUNDARY;\n            } else if (c === HYPHEN) {\n              // HYPHEN = end boundary\n              flags |= FBOUNDARY.LAST_BOUNDARY;\n            } else {\n              index = 0;\n            }\n          } else if (index - 1 === boundary.length) {\n            if (flags & FBOUNDARY.PART_BOUNDARY) {\n              index = 0;\n              if (c === LF) {\n                // unset the PART_BOUNDARY flag\n                flags &= ~FBOUNDARY.PART_BOUNDARY;\n                this._handleCallback('partEnd');\n                this._handleCallback('partBegin');\n                state = STATE.HEADER_FIELD_START;\n                break;\n              }\n            } else if (flags & FBOUNDARY.LAST_BOUNDARY) {\n              if (c === HYPHEN) {\n                this._handleCallback('partEnd');\n                this._handleCallback('end');\n                state = STATE.END;\n                flags = 0;\n              } else {\n                index = 0;\n              }\n            } else {\n              index = 0;\n            }\n          }\n\n          if (index > 0) {\n            // when matching a possible boundary, keep a lookbehind reference\n            // in case it turns out to be a false lead\n            lookbehind[index - 1] = c;\n          } else if (prevIndex > 0) {\n            // if our boundary turned out to be rubbish, the captured lookbehind\n            // belongs to partData\n            this._handleCallback('partData', lookbehind, 0, prevIndex);\n            prevIndex = 0;\n            setMark('partData');\n\n            // reconsider the current character even so it interrupted the sequence\n            // it could be the beginning of a new sequence\n            i--;\n          }\n\n          break;\n        case STATE.END:\n          break;\n        default:\n          done(this._endUnexpected());\n          return;\n      }\n    }\n\n    dataCallback('headerField');\n    dataCallback('headerValue');\n    dataCallback('partData');\n\n    this.index = index;\n    this.state = state;\n    this.flags = flags;\n\n    done();\n    return this.bufferLength;\n  }\n\n  explain() {\n    return `state = ${MultipartParser.stateToString(this.state)}`;\n  }\n}\n\n// eslint-disable-next-line consistent-return\nMultipartParser.stateToString = (stateNumber) => {\n  // eslint-disable-next-line no-restricted-syntax, guard-for-in\n  for (const stateName in STATE) {\n    const number = STATE[stateName];\n    if (number === stateNumber) return stateName;\n  }\n};\n\nexport default Object.assign(MultipartParser, { STATES });\n"
  },
  {
    "path": "src/parsers/OctetStream.js",
    "content": "import { PassThrough } from 'node:stream';\n\nclass OctetStreamParser extends PassThrough {\n  constructor(options = {}) {\n    super();\n    this.globalOptions = { ...options };\n  }\n}\n\nexport default OctetStreamParser;\n"
  },
  {
    "path": "src/parsers/Querystring.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\nimport { Transform } from 'node:stream';\n\n// This is a buffering parser, have a look at StreamingQuerystring.js for a streaming parser\nclass QuerystringParser extends Transform {\n  constructor(options = {}) {\n    super({ readableObjectMode: true });\n    this.globalOptions = { ...options };\n    this.buffer = '';\n    this.bufferLength = 0;\n  }\n\n  _transform(buffer, encoding, callback) {\n    this.buffer += buffer.toString('ascii');\n    this.bufferLength = this.buffer.length;\n    callback();\n  }\n\n  _flush(callback) {\n    const fields = new URLSearchParams(this.buffer);\n    for (const [key, value] of fields) {\n      this.push({\n        key,\n        value,\n      });\n    }\n    this.buffer = '';\n    callback();\n  }\n}\n\nexport default QuerystringParser;\n"
  },
  {
    "path": "src/parsers/StreamingQuerystring.js",
    "content": "// not used\n/* eslint-disable no-underscore-dangle */\n\nimport { Transform } from 'node:stream';\nimport FormidableError, { maxFieldsSizeExceeded } from '../FormidableError.js';\n\nconst AMPERSAND = 38;\nconst EQUALS = 61;\n\nclass QuerystringParser extends Transform {\n  constructor(options = {}) {\n    super({ readableObjectMode: true });\n\n    const { maxFieldSize } = options;\n    this.maxFieldLength = maxFieldSize;\n    this.buffer = Buffer.from('');\n    this.fieldCount = 0;\n    this.sectionStart = 0;\n    this.key = '';\n    this.readingKey = true;\n  }\n\n  _transform(buffer, encoding, callback) {\n    let len = buffer.length;\n    if (this.buffer && this.buffer.length) {\n      // we have some data left over from the last write which we are in the middle of processing\n      len += this.buffer.length;\n      buffer = Buffer.concat([this.buffer, buffer], len);\n    }\n\n    for (let i = this.buffer.length || 0; i < len; i += 1) {\n      const c = buffer[i];\n      if (this.readingKey) {\n        // KEY, check for =\n        if (c === EQUALS) {\n          this.key = this.getSection(buffer, i);\n          this.readingKey = false;\n          this.sectionStart = i + 1;\n        } else if (c === AMPERSAND) {\n          // just key, no value. Prepare to read another key\n          this.emitField(this.getSection(buffer, i));\n          this.sectionStart = i + 1;\n        }\n        // VALUE, check for &\n      } else if (c === AMPERSAND) {\n        this.emitField(this.key, this.getSection(buffer, i));\n        this.sectionStart = i + 1;\n      }\n\n      if (\n        this.maxFieldLength &&\n        i - this.sectionStart === this.maxFieldLength\n      ) {\n        callback(\n          new FormidableError(\n            `${\n              this.readingKey ? 'Key' : `Value for ${this.key}`\n            } longer than maxFieldLength`,\n          ),\n          maxFieldsSizeExceeded,\n          413,\n        );\n      }\n    }\n\n    // Prepare the remaining key or value (from sectionStart to the end) for the next write() or for end()\n    len -= this.sectionStart;\n    if (len) {\n      // i.e. Unless the last character was a & or =\n      this.buffer = Buffer.from(this.buffer, 0, this.sectionStart);\n    } else this.buffer = null;\n\n    this.sectionStart = 0;\n    callback();\n  }\n\n  _flush(callback) {\n    // Emit the last field\n    if (this.readingKey) {\n      // we only have a key if there's something in the buffer. We definitely have no value\n      if (this.buffer && this.buffer.length) {\n        this.emitField(this.buffer.toString('ascii'));\n      }\n    } else {\n      // We have a key, we may or may not have a value\n      this.emitField(\n        this.key,\n        this.buffer && this.buffer.length && this.buffer.toString('ascii'),\n      );\n    }\n    this.buffer = '';\n    callback();\n  }\n\n  getSection(buffer, i) {\n    if (i === this.sectionStart) return '';\n\n    return buffer.toString('ascii', this.sectionStart, i);\n  }\n\n  emitField(key, val) {\n    this.key = '';\n    this.readingKey = true;\n    this.push({ key, value: val || '' });\n  }\n}\n\nexport default QuerystringParser;\n\n// const q = new QuerystringParser({maxFieldSize: 100});\n// (async function() {\n//     for await (const chunk of q) {\n//       console.log(chunk);\n//     }\n// })();\n// q.write(\"a=b&c=d\")\n// q.end()\n"
  },
  {
    "path": "src/parsers/index.js",
    "content": "import JSONParser from './JSON.js';\nimport DummyParser from './Dummy.js';\nimport MultipartParser from './Multipart.js';\nimport OctetStreamParser from './OctetStream.js';\nimport QueryStringParser from './Querystring.js';\n\nexport {\n  JSONParser,\n  DummyParser,\n  MultipartParser,\n  OctetStreamParser,\n  OctetStreamParser as OctetstreamParser,\n  QueryStringParser,\n  QueryStringParser as QuerystringParser,\n};\n"
  },
  {
    "path": "src/plugins/index.js",
    "content": "import octetstream from './octetstream.js';\nimport querystring from './querystring.js';\nimport multipart from './multipart.js';\nimport json from './json.js';\n\nexport { octetstream, querystring, multipart, json };\n"
  },
  {
    "path": "src/plugins/json.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\nimport JSONParser from '../parsers/JSON.js';\n\nexport const jsonType = 'json';\n// the `options` is also available through the `this.options` / `formidable.options`\nexport default function plugin(formidable, options) {\n  // the `this` context is always formidable, as the first argument of a plugin\n  // but this allows us to customize/test each plugin\n\n  /* istanbul ignore next */\n  const self = this || formidable;\n\n  if (/^[^;]*json/i.test(self.headers['content-type'])) {\n    init.call(self, self, options);\n  }\n\n  return self;\n};\n\n// Note that it's a good practice (but it's up to you) to use the `this.options` instead\n// of the passed `options` (second) param, because when you decide\n// to test the plugin you can pass custom `this` context to it (and so `this.options`)\nfunction init(_self, _opts) {\n  this.type = jsonType;\n\n  const parser = new JSONParser(this.options);\n\n  parser.on('data', (fields) => {\n    this.fields = fields;\n  });\n\n  parser.once('end', () => {\n    this.ended = true;\n    this._maybeEnd();\n  });\n\n  this._parser = parser;\n}\n"
  },
  {
    "path": "src/plugins/multipart.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\nimport { Stream } from 'node:stream';\nimport MultipartParser from '../parsers/Multipart.js';\nimport * as errors from '../FormidableError.js';\nimport FormidableError from '../FormidableError.js';\n\nexport const multipartType = 'multipart';\n// the `options` is also available through the `options` / `formidable.options`\nexport default function plugin(formidable, options) {\n  // the `this` context is always formidable, as the first argument of a plugin\n  // but this allows us to customize/test each plugin\n\n  /* istanbul ignore next */\n  const self = this || formidable;\n\n  // NOTE: we (currently) support both multipart/form-data and multipart/related\n  const multipart = /^[^;]*multipart/i.test(self.headers['content-type']);\n\n  if (multipart) {\n    const m = self.headers['content-type'].match(\n      /boundary=(?:\"([^\"]+)\"|([^;]+))/i,\n    );\n    if (m) {\n      const initMultipart = createInitMultipart(m[1] || m[2]);\n      initMultipart.call(self, self, options); // lgtm [js/superfluous-trailing-arguments]\n    } else {\n      const err = new FormidableError(\n        'bad content-type header, no multipart boundary',\n        errors.missingMultipartBoundary,\n        400,\n      );\n      self._error(err);\n    }\n  }\n  return self;\n}\n\n// Note that it's a good practice (but it's up to you) to use the `this.options` instead\n// of the passed `options` (second) param, because when you decide\n// to test the plugin you can pass custom `this` context to it (and so `this.options`)\nfunction createInitMultipart(boundary) {\n  return function initMultipart() {\n    this.type = multipartType;\n\n    const parser = new MultipartParser(this.options);\n    let headerField;\n    let headerValue;\n    let part;\n\n    parser.initWithBoundary(boundary);\n\n    // eslint-disable-next-line max-statements, consistent-return\n    parser.on('data', async ({ name, buffer, start, end }) => {\n      if (name === 'partBegin') {\n        part = new Stream();\n        part.readable = true;\n        part.headers = {};\n        part.name = null;\n        part.originalFilename = null;\n        part.mimetype = null;\n\n        part.transferEncoding = this.options.encoding;\n        part.transferBuffer = '';\n\n        headerField = '';\n        headerValue = '';\n      } else if (name === 'headerField') {\n        headerField += buffer.toString(this.options.encoding, start, end);\n      } else if (name === 'headerValue') {\n        headerValue += buffer.toString(this.options.encoding, start, end);\n      } else if (name === 'headerEnd') {\n        headerField = headerField.toLowerCase();\n        part.headers[headerField] = headerValue;\n\n        // matches either a quoted-string or a token (RFC 2616 section 19.5.1)\n        const m = headerValue.match(\n          // eslint-disable-next-line no-useless-escape\n          /\\bname=(\"([^\"]*)\"|([^\\(\\)<>@,;:\\\\\"\\/\\[\\]\\?=\\{\\}\\s\\t/]+))/i,\n        );\n        if (headerField === 'content-disposition') {\n          if (m) {\n            part.name = m[2] || m[3] || '';\n          }\n\n          part.originalFilename = this._getFileName(headerValue);\n        } else if (headerField === 'content-type') {\n          part.mimetype = headerValue;\n        } else if (headerField === 'content-transfer-encoding') {\n          part.transferEncoding = headerValue.toLowerCase();\n        }\n\n        headerField = '';\n        headerValue = '';\n      } else if (name === 'headersEnd') {\n        switch (part.transferEncoding) {\n          case 'binary':\n          case '7bit':\n          case '8bit':\n          case 'utf-8': {\n            const dataPropagation = (ctx) => {\n              if (ctx.name === 'partData') {\n                part.emit('data', ctx.buffer.slice(ctx.start, ctx.end));\n              }\n            };\n            const dataStopPropagation = (ctx) => {\n              if (ctx.name === 'partEnd') {\n                part.emit('end');\n                parser.off('data', dataPropagation);\n                parser.off('data', dataStopPropagation);\n              }\n            };\n            parser.on('data', dataPropagation);\n            parser.on('data', dataStopPropagation);\n            break;\n          }\n          case 'base64': {\n            const dataPropagation = (ctx) => {\n              if (ctx.name === 'partData') {\n                part.transferBuffer += ctx.buffer\n                  .slice(ctx.start, ctx.end)\n                  .toString('ascii');\n\n                /*\n                  four bytes (chars) in base64 converts to three bytes in binary\n                  encoding. So we should always work with a number of bytes that\n                  can be divided by 4, it will result in a number of bytes that\n                  can be divided vy 3.\n                  */\n                const offset = parseInt(part.transferBuffer.length / 4, 10) * 4;\n                part.emit(\n                  'data',\n                  Buffer.from(\n                    part.transferBuffer.substring(0, offset),\n                    'base64',\n                  ),\n                );\n                part.transferBuffer = part.transferBuffer.substring(offset);\n              }\n            };\n            const dataStopPropagation = (ctx) => {\n              if (ctx.name === 'partEnd') {\n                part.emit('data', Buffer.from(part.transferBuffer, 'base64'));\n                part.emit('end');\n                parser.off('data', dataPropagation);\n                parser.off('data', dataStopPropagation);\n              }\n            };\n            parser.on('data', dataPropagation);\n            parser.on('data', dataStopPropagation);\n            break;\n          }\n          default:\n            return this._error(\n              new FormidableError(\n                'unknown transfer-encoding',\n                errors.unknownTransferEncoding,\n                501,\n              ),\n            );\n        }\n        this._parser.pause();\n        await this.onPart(part);\n        this._parser.resume();\n      } else if (name === 'end') {\n        this.ended = true;\n        this._maybeEnd();\n      }\n    });\n\n    this._parser = parser;\n  };\n}\n"
  },
  {
    "path": "src/plugins/octetstream.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\nimport OctetStreamParser from '../parsers/OctetStream.js';\n\nexport const octetStreamType = 'octet-stream';\n// the `options` is also available through the `options` / `formidable.options`\nexport default async function plugin(formidable, options) {\n  // the `this` context is always formidable, as the first argument of a plugin\n  // but this allows us to customize/test each plugin\n\n  /* istanbul ignore next */\n  const self = this || formidable;\n\n  if (/^[^;]*octet-stream/i.test(self.headers['content-type'])) {\n    await init.call(self, self, options);\n  }\n  return self;\n}\n\n// Note that it's a good practice (but it's up to you) to use the `this.options` instead\n// of the passed `options` (second) param, because when you decide\n// to test the plugin you can pass custom `this` context to it (and so `this.options`)\nasync function init(_self, _opts) {\n  this.type = octetStreamType;\n  const originalFilename = this.headers['x-file-name'];\n  const mimetype = this.headers['content-type'];\n\n  const thisPart = {\n    originalFilename,\n    mimetype,\n  };\n  const newFilename = this._getNewName(thisPart);\n  const filepath = this._joinDirectoryName(newFilename);\n  const file = await this._newFile({\n    newFilename,\n    filepath,\n    originalFilename,\n    mimetype,\n  });\n\n  this.emit('fileBegin', originalFilename, file);\n  file.open();\n  this.openedFiles.push(file);\n  this._flushing += 1;\n\n  this._parser = new OctetStreamParser(this.options);\n\n  // Keep track of writes that haven't finished so we don't emit the file before it's done being written\n  let outstandingWrites = 0;\n\n  this._parser.on('data', (buffer) => {\n    this.pause();\n    outstandingWrites += 1;\n\n    file.write(buffer, () => {\n      outstandingWrites -= 1;\n      this.resume();\n\n      if (this.ended) {\n        this._parser.emit('doneWritingFile');\n      }\n    });\n  });\n\n  this._parser.on('end', () => {\n    this._flushing -= 1;\n    this.ended = true;\n\n    const done = () => {\n      file.end(() => {\n        this.emit('file', 'file', file);\n        this._maybeEnd();\n      });\n    };\n\n    if (outstandingWrites === 0) {\n      done();\n    } else {\n      this._parser.once('doneWritingFile', done);\n    }\n  });\n\n  return this;\n}\n"
  },
  {
    "path": "src/plugins/querystring.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\n\nimport QuerystringParser from '../parsers/Querystring.js';\n\nexport const querystringType = 'urlencoded';\n// the `options` is also available through the `this.options` / `formidable.options`\nexport default function plugin(formidable, options) {\n  // the `this` context is always formidable, as the first argument of a plugin\n  // but this allows us to customize/test each plugin\n\n  /* istanbul ignore next */\n  const self = this || formidable;\n\n  if (/^[^;]*urlencoded/i.test(self.headers['content-type'])) {\n    init.call(self, self, options);\n  }\n  return self;\n};\n\n// Note that it's a good practice (but it's up to you) to use the `this.options` instead\n// of the passed `options` (second) param, because when you decide\n// to test the plugin you can pass custom `this` context to it (and so `this.options`)\nfunction init(_self, _opts) {\n  this.type = querystringType;\n\n  const parser = new QuerystringParser(this.options);\n\n  parser.on('data', ({ key, value }) => {\n    this.emit('field', key, value);\n  });\n\n  parser.once('end', () => {\n    this.ended = true;\n    this._maybeEnd();\n  });\n\n  this._parser = parser;\n\n  return this;\n}\n"
  },
  {
    "path": "test/fixture/file/funkyfilename.txt",
    "content": "I am a text file with a funky name!\n"
  },
  {
    "path": "test/fixture/file/plain.txt",
    "content": "I am a simple plain text file\n"
  },
  {
    "path": "test/fixture/file/second-plaintext.txt",
    "content": "Some another plain text file, yeah!\n"
  },
  {
    "path": "test/fixture/http/encoding/beta-sticker-1.png.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\r\nContent-Length: 2483\r\n\r\n--\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\r\nContent-Disposition: form-data; name=\"sticker\"; filename=\"beta-sticker-1.png\"\r\nContent-Type: image/png\r\nContent-Transfer-Encoding: base64\r\n\r\niVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABh5JREFUeNrMmHtIHEcYwGfv5SNwaovxEanEiJKqlYCCTRo1f0SvDeof1legEcE/YttQaNOiaQjYFFtpKaJILZU8SCRUWqlJGpoWepGLTXqUEnzFxCrnK9DEelbvvPOe/WacuY7r7HmGFjrwsbNzt7u//V7zfYvQ/2xI/9K1/NyvMP9PgCTuGmmL6/0ckD9UOGmbIExUsqMkAPHJjv5QwKRtgKioqDlh5+w/7IFeCuLlxCeA2zQ0IcCwh2qoaLH09fUdTElJ2e/1elU+n0/y+9fvPz4+fvfYsWN3YOoBcXPiocLghD4mBYHhQTCErqWlZU9FRcXJqKiowyqVSk/uSEH4o8fjWVlYWDB2d3e3d3R0WGB5jYqLg/NyGgsKxMNgkDB4451NTU3vxcXF1SlBKB0tFsuVxsbGjlu3bj2GJQeIk8K5RVBqBTMxrYRfuHAh9/jx4+ejo6MPS9I6f6hHPOC6rOLi4vyVlZXf7t27Z5c5/iZfkgMxxyUwFy9ezC0tLe3V6XRJ/MOCAYjWwsLCni0oKCh98uSJaWhoyMZFn0/uT2qBqYi/1NbWxjc0NJwPFUYExc/B53R5eXk5ZrN5YH5+3slFn5+D2uBDzG90IJETExOtzGdC9RelNf78wYMH3xQWFn4Ep0sgyyCr1NmJP6kEIa5tbW3dEx8fXxeKRoJpT76OR3p6enllZWUKTCOwNalFAglWDkTCvLq6+uR2YYKZSw4GQVKNfZQCafjkqhKYTBsTE3NY/uYi2Q4MP5KTkw9QGB3VEMv6G/YioqFLly5lazQavfytxobnUW+PWTGisIyNPEL3QYLB4PPIyMi4EydO7JUBbTIZ0RDYOFPkE8t/OdHczCK6Y/qdzP8BfUTW8Tj/uQndvT1F5vOzVvTLz1PwX4cQbt++fekURsNpSNLIw16v1z/HLsRRgecsSnovm8nxs5bvUe+NN1Bz47fkfBaAXj2aA2BWEsM/3hhFX1/5Fe3NTEAfvn8NXTO+tSH68IiNjU2Qw/AmCzg2XCQp+YyhJAu9c+pl9GJ+KmhiEt38bhjpoyJQRtYudA60k3dwD6o4mouKjmSiolcy0ArRqnXz3rT+knwFEShhNKLNlmmFP7Kf8XxuehHpj0QQmLdPGch/ioYyCSAe57pMaHnJgcprctDdwUkRjKi8CUTWhipvbm7uvlJo3zFNoHJDOznPeGEXqn+9EBUf+AQZXvqU+BEG/KCpHz2flYh+ALO9++ZX5L/Mj3gfevjw4ZRoP+PzD/b4HadPn844c+aMkb0F1DqIz9byzBvquXytvr6+7vr16+Ow9CfN2njjdfFAWpo9o2FnNmm12kQMw24gcvSnhbHb7Y+huHsNlhapLNHSxK3idlq287qhhrkKlSByOBzIZrPhGyCn04ncbjfRGAMV5ZlQxvDw8E+yYi1Q3qpleYjUQlNTU5aysrJqgNBhIAwGVSDCkFj48BVFULA1eCl7XV3dx1CKYK3YqKnY7u9Ti2royclJ76FDh1YhxefgsoFpCIOtra0RuGBQwYbRaLzc1dVlpjA2ZiqmKbWsDAmEYU9Pz8Tg4OCNoqKixNTU1BQostDq6iqBcrlcRBiYfEff1KBR+OnpabPBYOikWlnhtOOWm0zUffpnZ2ednZ2dJtCYMTs7+xkA2x0eHk6gsMYwFPYr/EC1Wo2LMEWzWa1WC1QRZ8FUVgpj42ohD3umWqHjRFxf5RkZGVkCNQ9CcTWQn5+flpSUtBOiMKAt7Fek/FSAmpmZMVdVVZ0dGxv7g4PhteMVlbBIofv0sh4Lbmhtb2+/Cbv1eFpaWmJCQsJODMO0hGGgUghAAay9v7//i5KSki9lmmG+4+Jg/MHaIH6f0dCkqaNFFc5VkViam5v319TUNEDdvRubEGsNYHGqsAwMDFxta2u7DdpdpA+3c+LgWiHfVkCiFnpDw0iLqwgqO6BVKoPo00K6WIDsOzE6OrpE395FzeLgxMn5jVe0dYTa26s5jfFg4VR0nAuwNtrFda1rgmToD6VzVWq3eTPyYAxOwwH5gvT2PiWY7X4fUgJTywp1fivyyL6E+Lb6XvQ0X9AkBeeXZED+p/k+9LcAAwAXm3hBLzoZPAAAAABJRU5ErkJggg==\r\n--\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/--\r\n"
  },
  {
    "path": "test/fixture/http/encoding/binaryfile.tar.gz.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\r\nContent-Length: 676\r\n\r\n--\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\r\nContent-Disposition: form-data; name=\"file\"; filename=\"binaryfile.tar.gz\"\r\nContent-Type: application/x-gzip\r\nContent-Transfer-Encoding: base64\r\n\r\nH4sIAGiNIU8AA+3R0W6CMBQGYK59iobLZantRDG73osUOGqnFNJWM2N897UghG1ZdmWWLf93U/jP4bRAq8q92hJ/dY1J7kQEqyyLq8yXYrp2ltkqkTKXYiEykYc++ZTLVcLEvQ40dXReWcYSV1pdnL/v+6n+R11mjKVG1ZQ+s3TT2FpXqjhQ+hjzE1mnGxNLkgu+7tOKWjIVmVKTC6XL9ZaeXj4VQhwKWzL+cI4zwgQuuhkh3mhTad/Hkssh3im3027X54JnQ360R/M19OT8kC7SEN7Ooi2VvrEfznHQRWzl83gxttZKmzGehzPRW/+W8X+3fvL8sFet9sS6m3EIma02071MU3Uf9KHrmV1/+y8DAAAAAAAAAAAAAAAAAAAAAMB/9A6txIuJACgAAA==\r\n--\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/--\r\n"
  },
  {
    "path": "test/fixture/http/encoding/blank.gif.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\r\nContent-Length: 323\r\n\r\n--\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\r\nContent-Disposition: form-data; name=\"file\"; filename=\"blank.gif\"\r\nContent-Type: image/gif\r\nContent-Transfer-Encoding: base64\r\n\r\nR0lGODlhAQABAJH/AP///wAAAMDAwAAAACH5BAEAAAIALAAAAAABAAEAAAICVAEAOw==\r\n--\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/--\r\n"
  },
  {
    "path": "test/fixture/http/encoding/menu_separator.png.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\r\nContent-Length: 1509\r\n\r\n--\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\r\nContent-Disposition: form-data; name=\"image\"; filename=\"menu_separator.png\"\r\nContent-Type: image/png\r\nContent-Transfer-Encoding: base64\r\n\r\niVBORw0KGgoAAAANSUhEUgAAAAIAAAAYCAIAAABfmbuOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDcxODNBNzJERDcyMTFFMUFBOEVFNDQzOTA0MDJDMjQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDcxODNBNzNERDcyMTFFMUFBOEVFNDQzOTA0MDJDMjQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowNzE4M0E3MERENzIxMUUxQUE4RUU0NDM5MDQwMkMyNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowNzE4M0E3MURENzIxMUUxQUE4RUU0NDM5MDQwMkMyNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pmvhbb8AAAAXSURBVHjaYnHk9PON8WJiAIPBSwEEGAAPrgG+VozFWgAAAABJRU5ErkJggg==\r\n--\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/--\r\n"
  },
  {
    "path": "test/fixture/http/encoding/plain.txt.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Length: 221\r\n\r\n------TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Disposition: form-data; name=\"file\"; filename=\"plain.txt\"\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: 7bit\r\n\r\nI am a plain text file\n\r\n------TLV0SrKD4z1TRxRhAPUvZ--\r\n"
  },
  {
    "path": "test/fixture/http/misc/boundary-substring-json.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=uj05Dyqd7Fd5aqAJnK1j9WeJSONmNy5vSGbM1oLf\r\nContent-Length: 211\r\n\r\n--uj05Dyqd7Fd5aqAJnK1j9WeJSONmNy5vSGbM1oLf\r\nContent-Disposition: form-data; filename=\"plain.txt\"; name=\"upload\"\r\nContent-Type: text/plain\r\n\r\nI am a plain text file\r\n\r\n--uj05Dyqd7Fd5aqAJnK1j9WeJSONmNy5vSGbM1oLf--\r\n\r\n"
  },
  {
    "path": "test/fixture/http/misc/empty-multipart.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Length: 0\r\n\r\n"
  },
  {
    "path": "test/fixture/http/misc/empty-multipart2.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Length: 31\r\n\r\n------TLV0SrKD4z1TRxRhAPUvZ--\r\n"
  },
  {
    "path": "test/fixture/http/misc/empty-urlencoded.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Length: 0\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n"
  },
  {
    "path": "test/fixture/http/misc/empty.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Length: 0\r\n\r\n"
  },
  {
    "path": "test/fixture/http/misc/minimal.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\n\r\n"
  },
  {
    "path": "test/fixture/http/no-filename/filename-name.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG\r\nContent-Length: 1000\r\n\r\n------WebKitFormBoundarytyE4wkKlZ5CQJVTG\r\nContent-Disposition: form-data; filename=\"plain.txt\"; name=\"upload\"\r\nContent-Type: text/plain\r\n\r\nI am a plain text file\r\n\r\n------WebKitFormBoundarytyE4wkKlZ5CQJVTG--\r\n\r\n"
  },
  {
    "path": "test/fixture/http/no-filename/generic.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG\r\nContent-Length: 1000\r\n\r\n------WebKitFormBoundarytyE4wkKlZ5CQJVTG\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"\"\r\nContent-Type: text/plain\r\n\r\nI am a plain text file\n\r\n------WebKitFormBoundarytyE4wkKlZ5CQJVTG--\r\n\n"
  },
  {
    "path": "test/fixture/http/preamble/crlf.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Length: 184\r\n\r\n\r\n------TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"plain.txt\"\r\nContent-Type: text/plain\r\n\r\nI am a plain text file\n\r\n------TLV0SrKD4z1TRxRhAPUvZ--\r\n"
  },
  {
    "path": "test/fixture/http/preamble/preamble.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Length: 226\r\n\r\nThis is a preamble which should be ignored\r\n------TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"plain.txt\"\r\nContent-Type: text/plain\r\n\r\nI am a plain text file\r\n\r\n------TLV0SrKD4z1TRxRhAPUvZ--\r\n"
  },
  {
    "path": "test/fixture/http/special-chars-in-filename/info.md",
    "content": "- Opera does not allow submitting this file, it shows a warning to the\n  user that the file could not be found instead. Tested in 9.8, 11.51 on OSX.\n  Reported to Opera on 08.09.2011 (tracking email DSK-346009@bugs.opera.com).\n"
  },
  {
    "path": "test/fixture/http/special-chars-in-filename/line-separator.http",
    "content": "POST /upload HTTP/1.1\nHost: localhost:8080\nReferer: http://localhost:8080/\nContent-Length: 383\nOrigin: http://localhost:8080\nUser-Agent: Mozilla/5.0 \nContent-Type: multipart/form-data; boundary=----SEPARATOR\nAccept: text/html\n\n------SEPARATOR\nContent-Disposition: form-data; name=\"title\"\n\nWeird filename\n------SEPARATOR\nContent-Disposition: form-data; name=\"upload\"; filename=\" .txt\"\nContent-Type: text/plain\n\nI am a text file with a funky name!\n\n------SEPARATOR--\n"
  },
  {
    "path": "test/fixture/http/special-chars-in-filename/osx-chrome-13.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nConnection: keep-alive\r\nReferer: http://localhost:8080/\r\nContent-Length: 383\r\nCache-Control: max-age=0\r\nOrigin: http://localhost:8080\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.220 Safari/535.1\r\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundarytyE4wkKlZ5CQJVTG\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Encoding: gzip,deflate,sdch\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\nCookie: jqCookieJar_tablesorter=%7B%22showListTable%22%3A%5B%5B5%2C1%5D%2C%5B1%2C0%5D%5D%7D\r\n\r\n------WebKitFormBoundarytyE4wkKlZ5CQJVTG\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nWeird filename\r\n------WebKitFormBoundarytyE4wkKlZ5CQJVTG\r\nContent-Disposition: form-data; name=\"upload\"; filename=\": \\ ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt\"\r\nContent-Type: text/plain\r\n\r\nI am a text file with a funky name!\n\r\n------WebKitFormBoundarytyE4wkKlZ5CQJVTG--\r\n"
  },
  {
    "path": "test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.22) Gecko/20110902 Firefox/3.6.22\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 115\r\nConnection: keep-alive\r\nReferer: http://localhost:8080/\r\nContent-Type: multipart/form-data; boundary=---------------------------9849436581144108930470211272\r\nContent-Length: 438\r\n\r\n-----------------------------9849436581144108930470211272\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nWeird filename\r\n-----------------------------9849436581144108930470211272\r\nContent-Disposition: form-data; name=\"upload\"; filename=\": \\ ? % * | \" < > . &#9731; ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt\"\r\nContent-Type: text/plain\r\n\r\nI am a text file with a funky name!\n\r\n-----------------------------9849436581144108930470211272--\r\n"
  },
  {
    "path": "test/fixture/http/special-chars-in-filename/osx-safari-5.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nOrigin: http://localhost:8080\r\nContent-Length: 383\r\nUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1\r\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundaryQJZ1gvhvdgfisJPJ\r\nAccept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nReferer: http://localhost:8080/\r\nAccept-Language: en-us\r\nAccept-Encoding: gzip, deflate\r\nConnection: keep-alive\r\n\r\n------WebKitFormBoundaryQJZ1gvhvdgfisJPJ\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nWeird filename\r\n------WebKitFormBoundaryQJZ1gvhvdgfisJPJ\r\nContent-Disposition: form-data; name=\"upload\"; filename=\": \\ ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt\"\r\nContent-Type: text/plain\r\n\r\nI am a text file with a funky name!\n\r\n------WebKitFormBoundaryQJZ1gvhvdgfisJPJ--\r\n"
  },
  {
    "path": "test/fixture/http/special-chars-in-filename/xp-chrome-12.http",
    "content": "POST /upload HTTP/1.1\r\nHost: 192.168.56.1:8080\r\nConnection: keep-alive\r\nReferer: http://192.168.56.1:8080/\r\nContent-Length: 344\r\nCache-Control: max-age=0\r\nOrigin: http://192.168.56.1:8080\r\nUser-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.122 Safari/534.30\r\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundaryEvqBNplR3ByrwQPa\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Encoding: gzip,deflate,sdch\r\nAccept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n\r\n------WebKitFormBoundaryEvqBNplR3ByrwQPa\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nWeird filename\r\n------WebKitFormBoundaryEvqBNplR3ByrwQPa\r\nContent-Disposition: form-data; name=\"upload\"; filename=\" ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n------WebKitFormBoundaryEvqBNplR3ByrwQPa--\r\n"
  },
  {
    "path": "test/fixture/http/special-chars-in-filename/xp-ie-7.http",
    "content": "POST /upload HTTP/1.1\r\nAccept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */*\r\nReferer: http://192.168.56.1:8080/\r\nAccept-Language: de\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)\r\nContent-Type: multipart/form-data; boundary=---------------------------7db1fe232017c\r\nAccept-Encoding: gzip, deflate\r\nHost: 192.168.56.1:8080\r\nContent-Length: 368\r\nConnection: Keep-Alive\r\nCache-Control: no-cache\r\n\r\n-----------------------------7db1fe232017c\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nWeird filename\r\n-----------------------------7db1fe232017c\r\nContent-Disposition: form-data; name=\"upload\"; filename=\" ? % * | \" < > . &#9731; ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----------------------------7db1fe232017c--\r\n"
  },
  {
    "path": "test/fixture/http/special-chars-in-filename/xp-ie-8.http",
    "content": "POST /upload HTTP/1.1\r\nAccept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, */*\r\nReferer: http://192.168.56.1:8080/\r\nAccept-Language: de\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)\r\nContent-Type: multipart/form-data; boundary=---------------------------7db3a8372017c\r\nAccept-Encoding: gzip, deflate\r\nHost: 192.168.56.1:8080\r\nContent-Length: 368\r\nConnection: Keep-Alive\r\nCache-Control: no-cache\r\n\r\n-----------------------------7db3a8372017c\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nWeird filename\r\n-----------------------------7db3a8372017c\r\nContent-Disposition: form-data; name=\"upload\"; filename=\" ? % * | \" < > . &#9731; ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----------------------------7db3a8372017c--\r\n"
  },
  {
    "path": "test/fixture/http/special-chars-in-filename/xp-safari-5.http",
    "content": "POST /upload HTTP/1.1\r\nHost: 192.168.56.1:8080\r\nReferer: http://192.168.56.1:8080/\r\nAccept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nAccept-Language: en-US\r\nOrigin: http://192.168.56.1:8080\r\nUser-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4\r\nAccept-Encoding: gzip, deflate\r\nContent-Type: multipart/form-data; boundary=----WebKitFormBoundarykmaWSUbu697WN9TM\r\nContent-Length: 344\r\nConnection: keep-alive\r\n\r\n------WebKitFormBoundarykmaWSUbu697WN9TM\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nWeird filename\r\n------WebKitFormBoundarykmaWSUbu697WN9TM\r\nContent-Disposition: form-data; name=\"upload\"; filename=\" ? % * | %22 < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt\"\r\nContent-Type: text/plain\r\n\r\n\r\n------WebKitFormBoundarykmaWSUbu697WN9TM--\r\n"
  },
  {
    "path": "test/fixture/http/workarounds/missing-hyphens1.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=----TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Length: 189\r\n\r\n------TLV0SrKD4z1TRxRhAPUvZ\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"plain.txt\"\r\nContent-Type: text/plain\r\n\r\nI am a simple plain text file\r\n\r\n------TLV0SrKD4z1TRxRhAPUvZ\r\n"
  },
  {
    "path": "test/fixture/http/workarounds/missing-hyphens2.http",
    "content": "POST /upload HTTP/1.1\r\nHost: localhost:8080\r\nContent-Type: multipart/form-data; boundary=----TLVx0SrKD4z1TRxRhAPUvZx\r\nContent-Length: 209\r\n\r\n------TLVx0SrKD4z1TRxRhAPUvZx\r\nContent-Disposition: form-data; name=\"upload\"; filename=\"second-plaintext.txt\"\r\nContent-Type: text/plain\r\n\r\nSome another plain text file, yeah!\r\n\r\n------TLVx0SrKD4z1TRxRhAPUvZx\r\n"
  },
  {
    "path": "test/fixture/js/encoding.js",
    "content": "const menu_separator_png_http = [\n  {\n    type: 'file',\n    name: 'image',\n    originalFilename: 'menu_separator.png',\n    fixture: 'menu_separator.png',\n    sha1: 'c845ca3ea794be298f2a1b79769b71939eaf4e54',\n  },\n];\n\nconst beta_sticker_1_png_http = [\n  {\n    type: 'file',\n    name: 'sticker',\n    originalFilename: 'beta-sticker-1.png',\n    fixture: 'beta-sticker-1.png',\n    sha1: '6abbcffd12b4ada5a6a084fe9e4584f846331bc4',\n  },\n];\n\nconst blank_gif_http = [\n  {\n    type: 'file',\n    name: 'file',\n    originalFilename: 'blank.gif',\n    fixture: 'blank.gif',\n    sha1: 'a1fdee122b95748d81cee426d717c05b5174fe96',\n  },\n];\n\nconst binaryfile_tar_gz_http = [\n  {\n    type: 'file',\n    name: 'file',\n    originalFilename: 'binaryfile.tar.gz',\n    fixture: 'binaryfile.tar.gz',\n    sha1: 'cfabe13b348e5e69287d677860880c52a69d2155',\n  },\n];\n\nconst plain_txt_http = [\n  {\n    type: 'file',\n    name: 'file',\n    originalFilename: 'plain.txt',\n    fixture: 'plain.txt',\n    sha1: 'b31d07bac24ac32734de88b3687dddb10e976872',\n  },\n];\n\nexport {\n  menu_separator_png_http,\n  beta_sticker_1_png_http,\n  blank_gif_http,\n  binaryfile_tar_gz_http,\n  plain_txt_http,\n};\n"
  },
  {
    "path": "test/fixture/js/misc.js",
    "content": "const boundary_substring_json = [\n  {\n    type: 'file',\n    name: 'upload',\n    originalFilename: 'plain.txt',\n    fixture: 'boundary-substring-json',\n  },\n];\n\nconst empty_http = [];\nconst empty_urlencoded_http = [];\nconst empty_multipart_http = [];\nconst empty_multipart2_http = [];\nconst _minimal_http = [];\n\nexport {\n  boundary_substring_json,\n  empty_http,\n  empty_urlencoded_http,\n  empty_multipart_http,\n  empty_multipart2_http,\n  _minimal_http,\n};\n"
  },
  {
    "path": "test/fixture/js/no-filename.js",
    "content": "const generic_http = [\n  {\n    type: 'file',\n    name: 'upload',\n    originalFilename: '',\n    fixture: 'generic',\n    sha1: 'b31d07bac24ac32734de88b3687dddb10e976872',\n  },\n];\n\nconst filename_name_http = [\n  {\n    type: 'file',\n    name: 'upload',\n    originalFilename: 'plain.txt',\n    fixture: 'filename-name',\n    sha1: 'a47f7a8a7959f36c3f151ba8b0bd28f2d6b606e2',\n  },\n];\n\nexport { generic_http, filename_name_http };\n"
  },
  {
    "path": "test/fixture/js/preamble.js",
    "content": "const crlf_http = [\n  {\n    type: 'file',\n    name: 'upload',\n    originalFilename: 'plain.txt',\n    fixture: 'crlf',\n    sha1: 'b31d07bac24ac32734de88b3687dddb10e976872',\n  },\n];\n\nconst preamble_http = [\n  {\n    type: 'file',\n    name: 'upload',\n    originalFilename: 'plain.txt',\n    fixture: 'preamble',\n    sha1: 'a47f7a8a7959f36c3f151ba8b0bd28f2d6b606e2',\n  },\n];\n\nexport { crlf_http, preamble_http };\n"
  },
  {
    "path": "test/fixture/js/special-chars-in-filename.js",
    "content": "const properFilename = 'funkyfilename.txt';\n\nfunction expect(originalFilename, fixtureName) {\n  return [\n    {\n      type: 'field',\n      name: 'title',\n      originalFilename: properFilename,\n      fixture: fixtureName,\n    },\n    {\n      type: 'file',\n      name: 'upload',\n      originalFilename,\n      fixture: fixtureName,\n    },\n  ];\n}\n\nconst osx_chrome_13_http = expect(' ? % * | \" < > . ? ; \\' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt', 'osx-chrome-13');\nconst osx_firefox_3_6_http = expect(' ? % * | \" < > . ☃ ; \\' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt', 'osx-firefox-3.6');\n\nconst xp_ie_7_http = expect(' ? % * | \" < > . ☃ ; \\' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt', 'xp-ie-7');\nconst xp_ie_8_http = expect(' ? % * | \" < > . ☃ ; \\' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt', 'xp-ie-8');\nconst lineSeparator = expect(null, 'line-separator');\n\nexport {\n  osx_chrome_13_http,\n  osx_firefox_3_6_http,\n  // webkit as osx_firefox_3_6_http,\n  // webkit as osx_safari_5_http,\n  // webkit as xp_chrome_12_http,\n  // webkit as xp_safari_5_http,\n\n  // xp_ie_7_http,\n  // xp_ie_8_http,\n  // lineSeparator,\n};\n"
  },
  {
    "path": "test/fixture/js/workarounds.js",
    "content": "const missing_hyphens1_http = [\n  {\n    type: 'file',\n    name: 'upload',\n    originalFilename: 'plain.txt',\n    fixture: 'missing-hyphens1',\n    sha1: '8c26b82ec9107e99b3486844644e92558efe0c73',\n  },\n];\n\nconst missing_hyphens2_http = [\n  {\n    type: 'file',\n    name: 'upload',\n    originalFilename: 'second-plaintext.txt',\n    fixture: 'missing-hyphens2',\n    sha1: '798e39a4a1034232ed26e0aadd67f5d1ff10b966',\n  },\n];\n\nexport { missing_hyphens1_http, missing_hyphens2_http };\n"
  },
  {
    "path": "test/fixture/multipart.js",
    "content": "exports.rfc1867 = {\n  boundary: 'AaB03x',\n  raw:\n    '--AaB03x\\r\\n' +\n    'content-disposition: form-data; name=\"field1\"\\r\\n' +\n    '\\r\\n' +\n    'Joe Blow\\r\\nalmost tricked you!\\r\\n' +\n    '--AaB03x\\r\\n' +\n    'content-disposition: form-data; name=\"pics\"; filename=\"file1.txt\"\\r\\n' +\n    'Content-Type: text/plain\\r\\n' +\n    '\\r\\n' +\n    '... contents of file1.txt ...\\r\\r\\n' +\n    '--AaB03x--\\r\\n',\n  parts: [\n    {\n      headers: {\n        'content-disposition': 'form-data; name=\"field1\"',\n      },\n      data: 'Joe Blow\\r\\nalmost tricked you!',\n    },\n    {\n      headers: {\n        'content-disposition': 'form-data; name=\"pics\"; filename=\"file1.txt\"',\n        'Content-Type': 'text/plain',\n      },\n      data: '... contents of file1.txt ...\\r',\n    },\n  ],\n};\n\nexports['noTrailing\\r\\n'] = {\n  boundary: 'AaB03x',\n  raw:\n    '--AaB03x\\r\\n' +\n    'content-disposition: form-data; name=\"field1\"\\r\\n' +\n    '\\r\\n' +\n    'Joe Blow\\r\\nalmost tricked you!\\r\\n' +\n    '--AaB03x\\r\\n' +\n    'content-disposition: form-data; name=\"pics\"; filename=\"file1.txt\"\\r\\n' +\n    'Content-Type: text/plain\\r\\n' +\n    '\\r\\n' +\n    '... contents of file1.txt ...\\r\\r\\n' +\n    '--AaB03x--',\n  parts: [\n    {\n      headers: {\n        'content-disposition': 'form-data; name=\"field1\"',\n      },\n      data: 'Joe Blow\\r\\nalmost tricked you!',\n    },\n    {\n      headers: {\n        'content-disposition': 'form-data; name=\"pics\"; filename=\"file1.txt\"',\n        'Content-Type': 'text/plain',\n      },\n      data: '... contents of file1.txt ...\\r',\n    },\n  ],\n};\n\nexports.emptyHeader = {\n  boundary: 'AaB03x',\n  raw:\n    '--AaB03x\\r\\n' +\n    'content-disposition: form-data; name=\"field1\"\\r\\n' +\n    ': foo\\r\\n' +\n    '\\r\\n' +\n    'Joe Blow\\r\\nalmost tricked you!\\r\\n' +\n    '--AaB03x\\r\\n' +\n    'content-disposition: form-data; name=\"pics\"; filename=\"file1.txt\"\\r\\n' +\n    'Content-Type: text/plain\\r\\n' +\n    '\\r\\n' +\n    '... contents of file1.txt ...\\r\\r\\n' +\n    '--AaB03x--\\r\\n',\n  expectError: true,\n};\n"
  },
  {
    "path": "test/integration/file-write-stream-handler-option.test.js",
    "content": "import { existsSync, mkdirSync, createWriteStream, readdirSync, statSync, unlinkSync, createReadStream } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { createServer, request as _request } from 'node:http';\nimport path, { join, dirname } from 'node:path';\nimport url from 'node:url';\nimport assert, { strictEqual, ok } from 'node:assert';\n\nimport formidable from '../../src/index.js';\n\nconst __filename = url.fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst PORT = 13533;\nconst DEFAULT_UPLOAD_DIR = join(\n  tmpdir(),\n  'test-store-files-option-default',\n);\nconst CUSTOM_UPLOAD_DIR = join(\n  tmpdir(),\n  'test-store-files-option-custom',\n);\nconst CUSTOM_UPLOAD_FILE_PATH = join(CUSTOM_UPLOAD_DIR, 'test-file');\nconst testFilePath = join(\n  dirname(__dirname),\n  'fixture',\n  'file',\n  'binaryfile.tar.gz',\n);\n\nconst createDirs = (dirs) => {\n  dirs.forEach((dir) => {\n    if (!existsSync(dir)) {\n      mkdirSync(dir);\n    }\n  });\n};\n\ntest('file write stream handler', (done) => {\n  const server = createServer((req, res) => {\n    createDirs([DEFAULT_UPLOAD_DIR, CUSTOM_UPLOAD_DIR]);\n    const form = formidable({\n      uploadDir: DEFAULT_UPLOAD_DIR,\n      fileWriteStreamHandler: () =>\n        createWriteStream(CUSTOM_UPLOAD_FILE_PATH),\n    });\n\n    form.parse(req, (err, fields, files) => {\n      strictEqual(Object.keys(files).length, 1);\n      const file = files.file[0];\n\n      strictEqual(file.size, 301);\n      strictEqual(typeof file.filepath, 'string');\n\n      const dirFiles = readdirSync(DEFAULT_UPLOAD_DIR);\n      ok(dirFiles.length === 0);\n\n      const uploadedFileStats = statSync(CUSTOM_UPLOAD_FILE_PATH);\n      ok(uploadedFileStats.size === file.size);\n\n      unlinkSync(CUSTOM_UPLOAD_FILE_PATH);\n      res.end();\n      server.close();\n      done();\n    });\n  });\n\n  server.listen(PORT, (err) => {\n    assert(!err, 'should not have error, but be falsey');\n\n    const request = _request({\n      port: PORT,\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/octet-stream',\n      },\n    });\n\n    createReadStream(testFilePath).pipe(request);\n  });\n});\n"
  },
  {
    "path": "test/integration/fixtures.test.js",
    "content": "/* eslint-disable global-require */\n/* eslint-disable import/no-dynamic-require */\n\nimport { createReadStream } from 'node:fs';\nimport { createConnection } from 'node:net';\nimport { join } from 'node:path';\nimport { createServer } from 'node:http';\nimport { strictEqual } from 'node:assert';\n\nimport formidable from '../../src/index.js';\n\nconst PORT = 13534;\nconst CWD = process.cwd();\nconst FIXTURES_HTTP = join(CWD, 'test', 'fixture', 'http');\nconst UPLOAD_DIR = join(CWD, 'test', 'tmp');\nimport * as encoding from \"../fixture/js/encoding.js\";\nimport * as misc from \"../fixture/js/misc.js\";\nimport * as noFilename from \"../fixture/js/no-filename.js\";\nimport * as preamble from \"../fixture/js/preamble.js\";\nimport * as workarounds from \"../fixture/js/workarounds.js\";\nimport * as specialCharsInFilename from \"../fixture/js/special-chars-in-filename.js\";\n\nconst fixtures= {\n  encoding,\n  misc,\n  [`no-filename`]: noFilename,\n  preamble,\n  [`special-chars-in-filename`]: specialCharsInFilename,\n  // workarounds, // todo uncomment this and make it work\n};\n\ntest('fixtures', (done) => {\n  const server = createServer();\n  server.listen(PORT, findFixtures);\n\n  function findFixtures() {\n      const results = Object.entries(fixtures).map(([fixtureGroup, fixture]) => {\n        return Object.entries(fixture).map(([k, v]) => {\n          return v.map(details => {\n            return {\n              fixture: v,\n              name: `${fixtureGroup}/${details.fixture}.http`\n            };\n          });\n        });\n      }).flat(Infinity);\n      testNext(results);\n  }\n\n  function testNext(results) {\n    const fixtureWithName = results.shift();\n    if (!fixtureWithName) {\n      server.close();\n      done();\n      return;\n    }\n    const fixtureName = fixtureWithName.name;\n    const fixture = fixtureWithName.fixture;\n\n    uploadFixture(fixtureName, (err, parts) => {\n      try {\n        if (err) {\n          err.fixtureName = fixtureName;\n          throw err;\n        }\n\n        fixture.forEach((expectedPart, i) => {\n          const parsedPart = parts[i];\n          strictEqual(parsedPart.type, expectedPart.type);\n          strictEqual(parsedPart.name, expectedPart.name);\n\n          if (parsedPart.type === 'file') {\n            const file = parsedPart.value;\n            strictEqual(file.originalFilename, expectedPart.originalFilename,\n              `${JSON.stringify([expectedPart, file])}`);\n\n            if (expectedPart.sha1) {\n              strictEqual(\n                file.hash,\n                expectedPart.sha1,\n                `SHA1 error ${file.originalFilename} on ${file.filepath} ${JSON.stringify([expectedPart, file])}`,\n              );\n            }\n          }\n        });\n      } catch (e) {\n        server.close();\n        done(e);\n        throw e;\n      }\n\n      testNext(results);\n    });\n  }\n\n  function uploadFixture(fixtureName, cb) {\n    server.once('request', (req, res) => {\n      const form = formidable({\n        uploadDir: UPLOAD_DIR,\n        hashAlgorithm: 'sha1',\n      });\n\n      function callback(...args) {\n        const realCallback = cb;\n        // eslint-disable-next-line no-param-reassign\n        cb = function callbackFn() {};\n\n        realCallback(...args);\n      }\n\n      const parts = [];\n      form\n        .on('error', callback)\n        .on('fileBegin', (name, value) => {\n          parts.push({ type: 'file', name, value });\n        })\n        .on('field', (name, value) => {\n          parts.push({ type: 'field', name, value });\n        })\n        .on('end', () => {\n          res.end();\n          callback(null, parts);\n        });\n\n      form.parse(req);\n    });\n\n    const socket = createConnection(PORT);\n    const fixturePath = join(FIXTURES_HTTP, fixtureName);\n    const file = createReadStream(fixturePath);\n\n    file.pipe(socket, { end: false });\n\n    socket.on('data', () => {\n      socket.end();\n    });\n  }\n});\n"
  },
  {
    "path": "test/integration/json.test.js",
    "content": "import { createServer, request as _request } from 'node:http';\nimport assert, { deepStrictEqual } from 'node:assert';\nimport formidable from '../../src/index.js';\n\nconst testData = {\n  numbers: [1, 2, 3, 4, 5],\n  nested: { key: 'val' },\n};\n\nconst PORT = 13535;\ntest('json', (done) => {\n  const server = createServer((req, res) => {\n    const form = formidable({ });\n\n    form.parse(req, (err, fields) => {\n      deepStrictEqual(fields, {\n        numbers: [1, 2, 3, 4, 5],\n        nested: { key: 'val' },\n      });\n\n      res.end();\n      server.close();\n      done();\n    });\n  });\n\n  server.listen(PORT, (err) => {\n    assert(!err, 'should not have error, but be falsey');\n\n    const request = _request({\n      port: PORT,\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n      },\n    });\n\n    request.write(JSON.stringify(testData));\n    request.end();\n  });\n});\n"
  },
  {
    "path": "test/integration/octet-stream.test.js",
    "content": "import { readFileSync, createReadStream } from 'node:fs';\nimport { createServer, request as _request } from 'node:http';\nimport path, { join, dirname } from 'node:path';\nimport url from 'node:url';\nimport assert, { strictEqual, deepStrictEqual } from 'node:assert';\n\nimport formidable from '../../src/index.js';\n\nconst __filename = url.fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst PORT = 13536;\nconst testFilePath = join(\n  dirname(__dirname),\n  'fixture',\n  'file',\n  'binaryfile.tar.gz',\n);\n\ntest('octet stream', (done) => {\n  const server = createServer((req, res) => {\n    const form = formidable();\n\n    form.parse(req, (err, fields, files) => {\n      strictEqual(Object.keys(files).length, 1);\n      const file = files.file[0];\n\n      strictEqual(file.size, 301);\n\n      const uploaded = readFileSync(file.filepath);\n      const original = readFileSync(testFilePath);\n\n      deepStrictEqual(uploaded, original);\n\n      res.end();\n      server.close();\n      done();\n    });\n  });\n\n  server.listen(PORT, (err) => {\n    assert(!err, 'should not have error, but be falsey');\n\n    const request = _request({\n      port: PORT,\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/octet-stream',\n      },\n    });\n\n    createReadStream(testFilePath).pipe(request);\n  });\n});\n"
  },
  {
    "path": "test/integration/store-files-option.test.js",
    "content": "import { existsSync, mkdirSync, WriteStream, statSync, unlinkSync, createReadStream } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { createServer, request as _request } from 'http';\nimport assert, { strictEqual, ok } from 'node:assert';\n\nimport path, { join, dirname } from 'node:path';\nimport url from 'node:url';\n\nimport formidable from '../../src/index.js';\n\nconst __filename = url.fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\nconst PORT = 13537;\nconst DEFAULT_UPLOAD_DIR = join(\n  tmpdir(),\n  'test-store-files-option-default',\n);\nconst CUSTOM_UPLOAD_FILE_PATH = join(DEFAULT_UPLOAD_DIR, 'test-file');\nconst testFilePath = join(\n  dirname(__dirname),\n  'fixture',\n  'file',\n  'binaryfile.tar.gz',\n);\n\ntest('store files option', (done) => {\n  const server = createServer((req, res) => {\n    if (!existsSync(DEFAULT_UPLOAD_DIR)) {\n      mkdirSync(DEFAULT_UPLOAD_DIR);\n    }\n    const form = formidable({\n      uploadDir: DEFAULT_UPLOAD_DIR,\n      fileWriteStreamHandler: () => new WriteStream(CUSTOM_UPLOAD_FILE_PATH),\n    });\n\n    form.parse(req, (err, fields, files) => {\n      strictEqual(Object.keys(files).length, 1);\n      const file = files.file[0];\n\n      strictEqual(file.size, 301);\n      strictEqual(typeof file.filepath, 'string');\n\n      const uploadedFileStats = statSync(CUSTOM_UPLOAD_FILE_PATH);\n      ok(uploadedFileStats.size === file.size);\n\n      unlinkSync(CUSTOM_UPLOAD_FILE_PATH);\n      res.end();\n      server.close();\n      done();\n    });\n  });\n\n  server.listen(PORT, (err) => {\n    assert(!err, 'should not have error, but be falsey');\n\n    const request = _request({\n      port: PORT,\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/octet-stream',\n      },\n    });\n\n    createReadStream(testFilePath).pipe(request);\n  });\n});\n"
  },
  {
    "path": "test/standalone/connection-aborted.test.js",
    "content": "import assert from 'node:assert';\nimport { createServer } from 'node:http';\nimport { connect } from 'node:net';\nimport formidable from '../../src/index.js';\n\nlet server;\nlet port = 13540;\n\nbeforeEach(() => {\n  server = createServer();\n  port += 1;\n});\n\nafterEach(() => {\n  return new Promise((resolve) => {\n    if (server.listening) {\n      server.close(() => resolve());\n    } else {\n      resolve();\n    }\n  });\n});\n\ntest('connection aborted', (done) => {\n  server.on('request', (req) => {\n    const form = formidable();\n\n    let abortedReceived = false;\n    form.on('aborted', () => {\n      abortedReceived = true;\n    });\n    form.on('error', () => {\n      assert(abortedReceived, 'Error event should follow aborted');\n    });\n    form.on('end', () => {\n      throw new Error('Unexpected \"end\" event');\n    });\n    form.parse(req, () => {\n      assert(\n        abortedReceived,\n        'from .parse() callback: Error event should follow aborted',\n      );\n      done();\n    });\n  });\n\n  server.listen(port, 'localhost', () => {\n    const client = connect(port);\n\n    client.write(\n      'POST / HTTP/1.1\\r\\n' +\n        'Host: localhost\\r\\n' +\n        'Content-Length: 70\\r\\n' +\n        'Content-Type: multipart/form-data; boundary=foo\\r\\n\\r\\n',\n    );\n    client.end();\n  });\n});\n"
  },
  {
    "path": "test/standalone/content-transfer-encoding.test.js",
    "content": "import { join } from 'node:path';\nimport { createServer, request } from 'node:http';\nimport { strictEqual } from 'node:assert';\n\nimport formidable from '../../src/index.js';\n\nconst UPLOAD_DIR = join(process.cwd(), 'test', 'tmp');\n\n// OS choosing port\nconst PORT = 13530;\ntest('content transfer encoding', (done) => {\n  const server = createServer(async (req, res) => {\n    const form = formidable({\n      uploadDir: UPLOAD_DIR\n    });\n    form.on('end', () => {\n      throw new Error('Unexpected \"end\" event');\n    });\n    form.on('error', (e) => {\n      res.writeHead(500);\n      res.end(e.message);\n    });\n    try {\n      await form.parse(req);\n    } catch (formidableError) {\n    }\n  });\n\n  server.listen(PORT, () => {\n    const chosenPort = server.address().port;\n\n    const body =\n      '--foo\\r\\n' +\n      'Content-Disposition: form-data; name=\"file1\"; filename=\"file1\"\\r\\n' +\n      'Content-Type: application/octet-stream\\r\\n' +\n      '\\r\\nThis is the first file\\r\\n' +\n      '--foo\\r\\n' +\n      'Content-Type: application/octet-stream\\r\\n' +\n      'Content-Disposition: form-data; name=\"file2\"; filename=\"file2\"\\r\\n' +\n      'Content-Transfer-Encoding: unknown\\r\\n' +\n      '\\r\\nThis is the second file\\r\\n' +\n      '--foo--\\r\\n';\n\n    const req = request({\n      method: 'POST',\n      port: chosenPort,\n      headers: {\n        'Content-Length': body.length,\n        'Content-Type': 'multipart/form-data; boundary=foo',\n      },\n    });\n\n    req.on('response', (res) => {\n      strictEqual(res.statusCode, 500);\n      res.on('data', () => {});\n      res.on('end', () => {\n        server.close();\n        done();\n      });\n    });\n    req.end(body);\n  });\n});\n"
  },
  {
    "path": "test/standalone/issue-46.test.js",
    "content": "import { createServer, request } from \"node:http\";\nimport { ok, strictEqual } from \"node:assert\";\nimport { Buffer } from 'node:buffer';\nimport formidable from \"../../src/index.js\";\n\n// OS choosing port\nconst PORT = 13531;\nconst type = \"multipart/related; boundary=a7a65b99-8a61-4e2c-b149-f73a3b35f923\"\nconst body = \"LS1hN2E2NWI5OS04YTYxLTRlMmMtYjE0OS1mNzNhM2IzNWY5MjMNCmNvbnRlbnQtZGlzcG9zaXRpb246IGZvcm0tZGF0YTsgbmFtZT0iZm9vIg0KDQpiYXJyeQ0KLS1hN2E2NWI5OS04YTYxLTRlMmMtYjE0OS1mNzNhM2IzNWY5MjMtLQ\";\nconst buffer = Buffer.from(body, 'base64url');\n\ntest(\"issue 46\", (done) => {\n  const server = createServer(async (req, res) => {\n    // Parse form and write results to response.\n    const form = formidable();\n    const [fields] = await form.parse(req);\n    ok(fields.foo, 'should have fields.foo === barry');\n    strictEqual(fields.foo[0], 'barry');\n    res.end();\n    server.close(() => {\n      done();\n    });\n  });\n\n  server.listen(PORT, () => {\n    const chosenPort = server.address().port;\n    const url = `http://localhost:${chosenPort}`;\n\n    const req = request(url, {\n      method: \"POST\",\n      headers: {\n        \"Content-Type\": type,\n        \"Content-Length\": buffer.byteLength\n      }\n    });\n\n    req.write(buffer);\n    req.end();\n    \n  });\n});\n"
  },
  {
    "path": "test/standalone/keep-alive-error.test.js",
    "content": "/* eslint-disable max-nested-callbacks */\n\nimport assert from 'node:assert/strict';\nimport { createServer } from 'node:http';\nimport { createConnection } from 'node:net';\nimport formidable from '../../src/index.js';\n\nlet server;\nlet port = 13539;\nlet ok = 0;\nlet errors = 0;\n\nbeforeEach(() => {\n  server = createServer();\n  ok = 0;\n  errors = 0;\n  port += 1;\n});\n\nafterEach(() => {\n  return new Promise((resolve) => {\n    if (server.listening) {\n      server.close(() => resolve());\n    } else {\n      resolve();\n    }\n  });\n});\n\ntest('keep alive error', (done) => {\n  server.on('request', async (req, res) => {\n    const form = formidable();\n    form.on('error', () => {\n      errors += 1;\n      res.writeHead(500);\n      res.end();\n    });\n    form.on('end', () => {\n      ok += 1;\n      res.writeHead(200);\n      res.end();\n    });\n    try {\n      await form.parse(req);\n      // for client two\n      assert.strictEqual(ok, 1, `should \"ok\" count === 1, has: ${ok}`);\n      done();\n    } catch (formidableError) {\n      assert.strictEqual(errors, 1, `should \"errors\" === 1, has: ${errors}`);\n\n      const clientTwo = createConnection(port);\n\n      // correct post upload (with hyphens)\n      clientTwo.write(\n        'POST /upload-test HTTP/1.1\\r\\n' +\n          'Host: localhost\\r\\n' +\n          'Connection: keep-alive\\r\\n' +\n          'Content-Type: multipart/form-data; boundary=----aaa\\r\\n' +\n          'Content-Length: 13\\r\\n\\r\\n' +\n          '------aaa--\\r\\n',\n      );\n      clientTwo.end();\n    }\n  });\n\n  server.listen(port, () => {\n    const client = createConnection(port);\n\n    // first send malformed (boundary / hyphens) post upload\n    client.write(\n      'POST /upload-test HTTP/1.1\\r\\n' +\n        'Host: localhost\\r\\n' +\n        'Connection: keep-alive\\r\\n' +\n        'Content-Type: multipart/form-data; boundary=----aaa\\r\\n' +\n        'Content-Length: 10011\\r\\n\\r\\n' +\n        '------XXX\\n\\r',\n    );\n\n    setTimeout(() => {\n      const buf = Buffer.alloc(10000);\n      buf.fill('a');\n      client.write(buf);\n      client.end();\n    }, 150);\n  });\n});\n"
  },
  {
    "path": "test/tools/base64.html",
    "content": "<html>\n  <head>\n    <title>Convert a file to a base64 request</title>\n\n    <script type=\"text/javascript\">\n      function form_submit(e) {\n        console.log(e);\n\n        var resultOutput = document.getElementById('resultOutput');\n        var fileInput = document.getElementById('fileInput');\n        var fieldInput = document.getElementById('fieldInput');\n\n        makeRequestBase64(fileInput.files[0], fieldInput.value, function (\n          err,\n          result,\n        ) {\n          resultOutput.value = result;\n        });\n\n        return false;\n      }\n\n      function makeRequestBase64(file, fieldName, cb) {\n        var boundary =\n          '\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/\\\\/';\n        var crlf = '\\r\\n';\n\n        var reader = new FileReader();\n        reader.onload = function (e) {\n          var body = '';\n\n          body += '--' + boundary + crlf;\n          body +=\n            'Content-Disposition: form-data; name=\"' +\n            fieldName +\n            '\"; filename=\"' +\n            escape(file.name) +\n            '\"' +\n            crlf;\n          body += 'Content-Type: ' + file.type + '' + crlf;\n          body += 'Content-Transfer-Encoding: base64' + crlf;\n          body += crlf;\n          body +=\n            e.target.result.substring(e.target.result.indexOf(',') + 1) + crlf;\n\n          body += '--' + boundary + '--';\n\n          var head = '';\n          head += 'POST /upload HTTP/1.1' + crlf;\n          head += 'Host: localhost:8080' + crlf;\n          head +=\n            'Content-Type: multipart/form-data; boundary=' +\n            boundary +\n            '' +\n            crlf;\n          head += 'Content-Length: ' + body.length + '' + crlf;\n\n          cb(null, head + crlf + body);\n        };\n\n        reader.readAsDataURL(file);\n      }\n    </script>\n  </head>\n\n  <body>\n    <form action=\"\" onsubmit=\"return form_submit();\">\n      <label>File: <input id=\"fileInput\" type=\"file\" /></label><br />\n      <label>Field: <input id=\"fieldInput\" type=\"text\" value=\"file\" /></label\n      ><br />\n      <button type=\"submit\">Ok!</button><br />\n      <label\n        >Request:\n        <textarea\n          id=\"resultOutput\"\n          readonly=\"readonly\"\n          rows=\"20\"\n          cols=\"80\"\n        ></textarea></label\n      ><br />\n    </form>\n    <p>\n      Don't forget to save the output with windows (CRLF) line endings!\n    </p>\n  </body>\n</html>\n"
  },
  {
    "path": "test/unit/custom-plugins.test.js",
    "content": "/* eslint-disable no-underscore-dangle */\n\nimport { join } from 'node:path';\n\nimport Koa from 'koa';\nimport request from 'supertest';\n\nimport { formidable, json, octetstream, multipart, errors } from '../../src/index.js';\n\nfunction createServer(options, handler) {\n  const app = new Koa();\n\n  app.use(async (ctx, next) => {\n    const form = formidable(options);\n    await handler(ctx, form);\n    await next();\n  });\n\n  return app;\n}\n\nfunction fromFixtures(...args) {\n  return join(process.cwd(), 'test', 'fixture', ...args);\n}\n\n// function makeRequest(server, options) {\n//   server.listen(0, () => {\n//     const chosenPort = server.address().port;\n//     const url = `http://localhost:${chosenPort}`;\n\n//     const method = 'POST';\n\n//     const opts = {\n//       ...options,\n//       port: chosenPort,\n//       url,\n//       method,\n//     };\n\n//     return http.request(opts);\n//   });\n// }\n\n// function onDone({ server, form, req, res }) {\n//   form.parse(req, (err, fields) => {\n//     assert.strictEqual(fields.qux, 'zaz');\n\n//     setTimeout(() => {\n//       res.end();\n//       server.close();\n//     }, 200);\n//   });\n// }\n\n// ! tests\n\ntest('should call 3 custom and 1 builtin plugins, when .parse() is called', async () => {\n  const server = createServer({ enabledPlugins: [json] }, (ctx, form) => {\n    form.on('plugin', () => {\n      ctx.__pluginsCount = ctx.__pluginsCount || 0;\n      ctx.__pluginsCount += 1;\n    });\n    form.on('end', () => {\n      ctx.__ends = 1;\n      expect(ctx.__customPlugin1).toBe(111);\n      expect(ctx.__customPlugin2).toBe(222);\n      expect(ctx.__customPlugin3).toBe(333);\n      ctx.__ends = 2;\n\n      const len = form._plugins.length;\n      expect(len).toBe(4);\n    });\n\n    form.use(() => {\n      ctx.__customPlugin1 = 111;\n    });\n    form.use(() => {\n      ctx.__customPlugin2 = 222;\n    });\n    form.use(() => {\n      ctx.__customPlugin3 = 333;\n    });\n\n    form.parse(ctx.req, (err, fields) => {\n      expect(fields.qux).toBe('zaz');\n      expect(fields.a).toBe('bbb');\n      expect(ctx.__pluginsCount).toBe(4);\n    });\n  });\n\n  await new Promise((resolve, reject) => {\n    request(server.callback())\n      .post('/')\n      .type('application/json')\n      .send({ qux: 'zaz', a: 'bbb' })\n      .end((err) => (err ? reject(err) : resolve()));\n  });\n});\n\ntest('.parse throw error when some plugin fail', async () => {\n  const server = createServer(\n    { enabledPlugins: [octetstream, json] },\n    async (ctx, form) => {\n      // const failedIsOkay = false;\n      // ! not emitted?\n      // form.on('file', () => {\n      //   ctx.__onFileCalled = ctx.__onFileCalled || 0;\n      //   ctx.__onFileCalled += 1;\n      // });\n\n      form.on('plugin', () => {\n        ctx.__pluginsCount = ctx.__pluginsCount || 0;\n        ctx.__pluginsCount += 1;\n      });\n\n      form.once('error', () => {\n        throw new Error('error event should not be fired when plugin throw');\n      });\n\n      form.use(() => {\n        throw new Error('custom plugin err');\n      });\n\n      let res = null;\n      try {\n        await form.parse(ctx.req);\n      } catch (err) {\n        expect(err.code).toBe(errors.pluginFailed);\n        expect(err.httpCode).toBe(500);\n\n        expect(form._plugins.length).toBe(3);\n        expect(ctx.__pluginsCount).toBe(2);\n        expect(ctx.__pluginsResults).toBe(undefined);\n\n        res = err;\n      }\n\n      if (!res) {\n        throw new Error(\n          '^ .parse should throw & be caught with the try/catch ^',\n        );\n      }\n    },\n  );\n\n  return new Promise((resolve, reject) => {\n    request(server.callback())\n      .post('/')\n      .type('application/octet-stream')\n      .attach('bin', fromFixtures('file', 'binaryfile.tar.gz'))\n      .end((err) => (err ? reject(err) : resolve()));\n  });\n});\n\ntest('multipart plugin fire `error` event when malformed boundary', async () => {\n  const server = createServer(\n    { enabledPlugins: [json, multipart] },\n    (ctx, form) => {\n      let failedIsOkay = false;\n\n      form.once('error', (err) => {\n        expect(form._plugins.length).toBe(2);\n        expect(err).toBeTruthy();\n        expect(err.message).toMatch(/bad content-type header/);\n        expect(err.message).toMatch(/no multipart boundary/);\n        failedIsOkay = true;\n      });\n\n      // Should never be called when `error`\n      form.on('end', () => {\n        throw new Error('should not fire `end` event when error');\n      });\n\n      form.parse(ctx.req, (err) => {\n        expect(err).toBeTruthy();\n        expect(failedIsOkay).toBe(true);\n      });\n    },\n  );\n\n  // 'Content-Length': 1111111,\n  // 'content-Disposition': 'form-data; bouZndary=',\n  // 'Content-Type': 'multipart/form-data; bouZndary=',\n  await new Promise((resolve, reject) => {\n    request(server.callback())\n      .post('/')\n      .type('multipart/form-data')\n      .set('Content-Length', 11111111)\n      .set('Content-Disposition', 'form-data; bouZndary=')\n      .set('Content-Type', 'multipart/form-data; bouZndary=')\n      .end((err) => (err ? reject(err) : resolve()));\n  });\n});\n\ntest('formidable() throw if not at least 1 built-in plugin in options.enabledPlugins', () => {\n  try {\n    formidable({ enabledPlugins: [] });\n  } catch (err) {\n    expect(err).toBeTruthy();\n    expect(err.message).toMatch(/expect at least 1 enabled builtin/);\n  }\n});\n"
  },
  {
    "path": "test/unit/formidable.test.js",
    "content": "/* eslint-disable max-statements */\n/* eslint-disable no-underscore-dangle */\n\nimport {jest} from '@jest/globals';\nimport Stream from 'node:stream';\nimport http from 'node:http';\nimport path from 'node:path';\n\nimport formidable from '../../src/index.js';\nimport * as mod from '../../src/index.js';\n\n\nfunction requestStub() {\n  return Object.assign(new Stream (), {\n    pause() {},\n    resume() {},\n  });\n}\n\nfunction getForm(name, opts) {\n  return name === 'formidable' ? formidable(opts) : new mod[name](opts);\n}\nfunction makeHeader(originalFilename) {\n  return `Content-Disposition: form-data; name=\"upload\"; filename=\"${originalFilename}\"`;\n}\n\n['IncomingForm', 'Formidable', 'formidable'].forEach((name) => {\n  test(`${name}#_getFileName with regular characters`, () => {\n    const originalFilename = 'foo.txt';\n    const form = getForm(name);\n\n    expect(form._getFileName(makeHeader(originalFilename))).toBe('foo.txt');\n  });\n\n  test(`${name}#_getFileName with unescaped quote`, () => {\n    const originalFilename = 'my\".txt';\n    const form = getForm(name);\n\n    expect(form._getFileName(makeHeader(originalFilename))).toBe('my\".txt');\n  });\n\n  test(`${name}#_getFileName with escaped quote`, () => {\n    const originalFilename = 'my%22.txt';\n    const form = getForm(name);\n\n    expect(form._getFileName(makeHeader(originalFilename))).toBe('my\".txt');\n  });\n\n  test(`${name}#_getFileName with bad quote and additional sub-header`, () => {\n    const originalFilename = 'my\".txt';\n    const form = getForm(name);\n\n    const header = `${makeHeader(originalFilename)}; foo=\"bar\"`;\n    expect(form._getFileName(header)).toBe(originalFilename);\n  });\n\n  test(`${name}#_getFileName with semicolon`, () => {\n    const originalFilename = 'my;.txt';\n    const form = getForm(name);\n\n    expect(form._getFileName(makeHeader(originalFilename))).toBe('my;.txt');\n  });\n\n  test(`${name}#_getFileName with utf8 character`, () => {\n    const originalFilename = 'my&#9731;.txt';\n    const form = getForm(name);\n\n    expect(form._getFileName(makeHeader(originalFilename))).toBe('my☃.txt');\n  });\n\n  test(`${name}#_getNewName strips harmful characters from extension when keepExtensions`, () => {\n    const form = getForm(name, { keepExtensions: true });\n\n    const getBasename = (part) => path.basename(form._getNewName(part));\n\n    // tests below assume baseline hexoid 25 chars + a few more for the extension\n    let basename = getBasename('fine.jpg?foo=bar');\n    expect(basename).toHaveLength(29);\n    let ext = path.extname(basename);\n    expect(ext).toBe('.jpg');\n\n    basename = getBasename('fine-no-ext?foo=qux');\n    expect(basename).toHaveLength(25);\n    ext = path.extname(basename);\n    expect(ext).toBe('');\n\n    basename = getBasename({ originalFilename: 'super.cr2+dsad' });\n    expect(basename).toHaveLength(29);\n    ext = path.extname(basename);\n    expect(ext).toBe('.cr2');\n\n    basename = getBasename({ originalFilename: 'super.gz' });\n    expect(basename).toHaveLength(28);\n    ext = path.extname(basename);\n    expect(ext).toBe('.gz');\n\n    basename = getBasename('file.aAa');\n    expect(basename).toHaveLength(29);\n    ext = path.extname(basename);\n    expect(ext).toBe('.aAa');\n\n    basename = getBasename('file#!@#koh.QxZs?sa=1');\n    expect(basename).toHaveLength(30);\n    ext = path.extname(basename);\n    expect(ext).toBe('.QxZs');\n\n    basename = getBasename('test.pdf.jqlnn<img src=a onerror=alert(1)>.png');\n    expect(basename).toHaveLength(35);\n    ext = path.extname(basename);\n    expect(ext).toBe('.jqlnn');\n\n    basename = getBasename('test.<a.png');\n    expect(basename).toHaveLength(25);\n    ext = path.extname(basename);\n    expect(ext).toBe('');\n  });\n\n  test(`${name}#_Array parameters support`, () => {\n    const form = getForm(name, {  });\n\n    const req = new http.ClientRequest();\n    req.headers = {\n      'content-length': '8',\n      'content-type': 'multipart/form-data; boundary=----TLVx',\n    };\n    form.parse(req, (error, fields) => {\n      expect(Array.isArray(fields.a)).toBe(true);\n      expect(fields.a[0]).toBe('1');\n      expect(fields.a[1]).toBe('2');\n    });\n    form.emit('field', 'a', '1');\n    form.emit('field', 'a', '2');\n    form.emit('end');\n  });\n\n  test(`${name}#_Nested array parameters support`, () => {\n    const form = getForm(name, {  });\n\n    const req = new http.ClientRequest();\n    req.headers = {\n      'content-length': '8',\n      'content-type': 'multipart/form-data; boundary=----TLVx',\n    };\n    form.parse(req, (error, fields) => {\n      expect(Array.isArray(fields[`a[0]`])).toBe(true);\n      expect(fields[`a[0]`][0]).toBe('a');\n      expect(fields[`a[0]`][1]).toBe('b');\n      expect(fields[`a[1]`][0]).toBe('c');\n    });\n    form.emit('field', 'a[0]', 'a');\n    form.emit('field', 'a[0]', 'b');\n    form.emit('field', 'a[1]', 'c');\n    form.emit('end');\n  });\n\n  test(`${name}#_Object parameters support`, () => {\n    const form = getForm(name, {  });\n\n    const req = new http.ClientRequest();\n    req.headers = {\n      'content-length': '8',\n      'content-type': 'multipart/form-data; boundary=----TLVx',\n    };\n    form.parse(req, (error, fields) => {\n      expect(fields[`a[x]`][0]).toBe('1');\n      expect(fields[`a[y]`][0]).toBe('2');\n    });\n    form.emit('field', 'a[x]', '1');\n    form.emit('field', 'a[y]', '2');\n    form.emit('end');\n  });\n\n  xtest(`${name}#_Nested object parameters support`, () => {\n    const form = getForm(name, {  });\n\n    const req = new http.ClientRequest();\n    req.headers = {\n      'content-length': '8',\n      'content-type': 'multipart/form-data; boundary=----TLVx',\n    };\n    form.parse(req, (error, fields) => {\n      expect(fields.a.l1.k1).toBe('2');\n      expect(fields.a.l1.k2).toBe('3');\n      expect(fields.a.l2.k3).toBe('5');\n    });\n    form.emit('field', 'a[l1][k1]', '2');\n    form.emit('field', 'a[l1][k2]', '3');\n    form.emit('field', 'a[l2][k3]', '5');\n    form.emit('end');\n  });\n\n  describe(`${name}#_onPart`, () => {\n    describe('when not allow empty files', () => {\n      describe('when file is empty', () => {\n        test('emits error when part is received', (done) => {\n          const form = getForm(name, {\n            allowEmptyFiles: false,\n          });\n          form.req = requestStub();\n\n          const part = new Stream();\n          part.mimetype = 'text/plain';\n          // eslint-disable-next-line max-nested-callbacks\n          form.on('error', (error) => {\n            expect(error.message).toBe(\n              'options.allowEmptyFiles is false, file size should be greater than 0',\n            );\n            done();\n          });\n          form.onPart(part).then (function () {\n            part.emit('end');\n            form.emit('end');\n          });\n        });\n      });\n\n      describe('when file is not empty', () => {\n        test('not emits error when part is received', () => {\n          const form = getForm(name, {\n            allowEmptyFiles: false,\n          });\n          const formEmitSpy = jest.spyOn(form, 'emit');\n\n          const part = new Stream();\n          part.mimetype = 'text/plain';\n          form.onPart(part);\n          part.emit('data', Buffer.alloc(1));\n          part.emit('end');\n          form.emit('end');\n          expect(formEmitSpy).not.toBeCalledWith('error');\n        });\n      });\n    });\n\n    describe('when allow empty files', () => {\n      test('not emits error when part is received', () => {\n        const form = getForm(name, {  });\n        const formEmitSpy = jest.spyOn(form, 'emit');\n\n        const part = new Stream();\n        part.mimetype = 'text/plain';\n        form.onPart(part);\n        part.emit('end');\n        form.emit('end');\n        expect(formEmitSpy).not.toBeCalledWith('error');\n      });\n    });\n\n    describe('when file uploaded size is inferior than minFileSize option', () => {\n      test('emits error when part is received', (done) => {\n        const form = getForm(name, { minFileSize: 5 });\n\n        const part = new Stream();\n        const req = requestStub();\n        part.mimetype = 'text/plain';\n        form.on('error', (error) => {\n          expect(error.message).toBe(\n            'options.minFileSize (5 bytes) inferior, received 4 bytes of file data',\n          );\n          done();\n        });\n        form.req = req;\n        form.onPart(part).then(function () {\n          part.emit('data', Buffer.alloc(4));\n          part.emit('end');\n          form.emit('end');\n        });\n\n      });\n    });\n\n    describe('when file uploaded size is superior than minFileSize option', () => {\n      test('not emits error when part is received', () => {\n        const form = getForm(name, { minFileSize: 10 });\n        const formEmitSpy = jest.spyOn(form, 'emit');\n\n        const part = new Stream();\n        part.mimetype = 'text/plain';\n        form.onPart(part);\n        part.emit('data', Buffer.alloc(11));\n        part.emit('end');\n        form.emit('end');\n        expect(formEmitSpy).not.toBeCalledWith('error');\n      });\n    });\n\n    describe('when there are more fields than maxFields', () => {\n      test('emits error', (done) => {\n        const form = getForm(name, {\n          maxFields: 1,\n        });\n\n        form.on('error', (error) => {\n          expect(error.message.includes('maxFields')).toBe(true);\n          done();\n        });\n\n        form.emit('field', 'a', '1');\n        form.emit('field', 'b', '2');\n        form.emit('end');\n      });\n    });\n  });\n\n  test(`${name}: maxFiles exceeded emits error`, (done) => {\n    const form = getForm(name, { maxFiles: 1 });\n    form.req = requestStub();\n\n    form.on('error', (error) => {\n      expect(error.message.includes('maxFiles')).toBe(true);\n      done();\n    });\n\n    const part1 = new Stream();\n    part1.mimetype = 'text/plain';\n    const part2 = new Stream();\n    part2.mimetype = 'text/plain';\n\n    form.onPart(part1).then(() => {\n      part1.emit('data', Buffer.alloc(1));\n      part1.emit('end');\n      form.onPart(part2);\n    });\n  });\n\n  test(`${name}: maxFiles defaults to 1000`, () => {\n    const form = getForm(name);\n    expect(form.options.maxFiles).toBe(1000);\n  });\n\n  // test(`${name}: use custom options.originalFilename instead of form._uploadPath`, () => {\n  //   const form = getForm(name, {\n  //     originalFilename: (_) => path.join(__dirname, 'sasa'),\n  //   });\n  // });\n\n  test(`${name}#_joinDirectoryName blocks standard directory traversal`, () => {\n    const form = getForm(name, { uploadDir: '/tmp/uploads' });\n    const result = form._joinDirectoryName('../../../etc/passwd');\n    expect(result).toBe(path.join('/tmp/uploads', 'invalid-name'));\n  });\n\n  test(`${name}#_joinDirectoryName blocks sibling directory prefix collision`, () => {\n    const form = getForm(name, { uploadDir: '/tmp/uploads' });\n    const result = form._joinDirectoryName('../uploads-evil/payload.sh');\n    expect(result).toBe(path.join('/tmp/uploads', 'invalid-name'));\n  });\n\n  test(`${name}#_joinDirectoryName allows subdirectories within uploadDir`, () => {\n    const form = getForm(name, { uploadDir: '/tmp/uploads' });\n    const result = form._joinDirectoryName('images/photo.jpg');\n    expect(result).toBe(path.resolve('/tmp/uploads', 'images/photo.jpg'));\n  });\n\n  test(`${name}#_joinDirectoryName blocks name resolving to uploadDir itself`, () => {\n    const form = getForm(name, { uploadDir: '/tmp/uploads' });\n    const result = form._joinDirectoryName('.');\n    expect(result).toBe(path.join('/tmp/uploads', 'invalid-name'));\n  });\n});\n"
  },
  {
    "path": "test/unit/multipart-parser.test.js",
    "content": "import { MultipartParser } from '../../src/index.js';\n\ntest('on constructor', () => {\n  const parser = new MultipartParser();\n  expect(parser.boundary).toBeNull();\n  expect(parser.state).toBe(0);\n  expect(parser.flags).toBe(0);\n  expect(parser.boundaryChars).toBeNull();\n  expect(parser.index).toBeNull();\n  expect(parser.lookbehind).toBeNull();\n  expect(parser.constructor.name).toBe('MultipartParser');\n});\n\ntest('initWithBoundary', () => {\n  const boundary = 'abc';\n  const parser = new MultipartParser();\n  parser.initWithBoundary(boundary);\n\n  expect(Array.prototype.slice.call(parser.boundary)).toMatchObject([\n    13,\n    10,\n    45,\n    45,\n    97,\n    98,\n    99,\n  ]);\n  expect(parser.state).toBe(MultipartParser.STATES.START);\n\n  expect(parser.boundaryChars).toMatchObject({\n    10: true,\n    13: true,\n    45: true,\n    97: true,\n    98: true,\n    99: true,\n  });\n});\n\ntest('initWithBoundary failing', () => {\n  const parser = new MultipartParser();\n  const boundary = 'abc';\n  const buffer = Buffer.alloc(5);\n\n  parser.initWithBoundary(boundary);\n  buffer.write('--ad', 0);\n  expect(parser.bufferLength).toBe(0);\n\n  parser.write(buffer);\n  expect(parser.bufferLength).toBe(5);\n});\n\ntest('on .end() throwing', () => {\n  const parser = new MultipartParser();\n  parser.once('error', () => {});\n\n  const res = parser.end();\n  expect(res.state).toBe(0);\n\n  // expect(() => { parser.end() }).toThrow(/MultipartParser/);\n  // expect(() => { parser.end() }).toThrow(/stream ended unexpectedly/);\n  // expect(() => { parser.end() }).toThrow(parser.explain());\n});\n\ntest('on .end() successful', () => {\n  const parser = new MultipartParser();\n  parser.state = MultipartParser.STATES.END;\n\n  const res = parser.end();\n  expect(res.state).toBe(12);\n});\n"
  },
  {
    "path": "test/unit/persistent-file.disabled-test.js",
    "content": "import {jest} from '@jest/globals';\nimport fs from 'node:fs';\nimport PersistentFile from '../../src/PersistentFile.js';\n\nconst mockFs = fs;\nconst now = new Date();\nconst file = new PersistentFile({\n  size: 1024,\n  filepath: '/tmp/cat.png',\n  name: 'cat.png',\n  type: 'image/png',\n  lastModifiedDate: now,\n  originalFilename: 'cat.png',\n  newFilename: 'dff1d2eaab9752165764dcd00',\n  mimetype: 'image/png',\n});\n\nconst mockFn = jest.fn();\njest.mock('fs', () => {\n  return {\n    ...mockFs,\n    unlink: mockFn,\n  };\n});\n\ndescribe('PersistentFile', () => {\n  test('toJSON()', () => {\n    const obj = file.toJSON();\n    const len = Object.keys(obj).length;\n\n    expect(obj.filepath).toBe('/tmp/cat.png');\n    expect(obj.mimetype).toBe('image/png');\n    expect(obj.originalFilename).toBe('cat.png');\n  });\n\n  test('toString()', () => {\n    const result = file.toString();\n    expect(result).toBe('PersistentFile: dff1d2eaab9752165764dcd00, Original: cat.png, Path: /tmp/cat.png')\n  });\n\n  test('destroy()', () => {\n    file.open();\n    file.destroy();\n    // eslint-disable-next-line global-require\n    expect(mockFn).toBeCalled();\n  });\n});\n"
  },
  {
    "path": "test/unit/querystring-parser.test.js",
    "content": "import { QuerystringParser } from '../../src/index.js';\n\ntest('on constructor', () => {\n  const parser = new QuerystringParser();\n  expect(parser.constructor.name).toBe('QuerystringParser');\n});\n\n// ! skip\n// test(function end =>\n//   const FIELDS = { a: ['b', { c: 'd' }], e: 'f' };\n\n//   gently.expect(GENTLY.hijacked.querystring, 'parse', (str) => {\n//     assert.equal(str, parser.buffer);\n//     return FIELDS;\n//   });\n\n//   gently.expect(parser, 'onField', Object.keys(FIELDS).length, (key, val) => {\n//     assert.deepEqual(FIELDS[key], val);\n//   });\n\n//   gently.expect(parser, 'onEnd');\n\n//   parser.buffer = 'my buffer';\n//   parser.end();\n//   assert.equal(parser.buffer, '');\n// });\n"
  },
  {
    "path": "test/unit/volatile-file.test.js",
    "content": "import {jest} from '@jest/globals';\nimport VolatileFile from '../../src/VolatileFile.js';\n\n\ndescribe('VolatileFile', () => {\n  let file;\n  let writeStreamInstanceMock;\n  let writeStreamMock;\n\n  beforeEach(() => {\n    writeStreamInstanceMock = {\n      on: jest.fn(),\n      destroy: jest.fn(),\n      end: jest.fn(),\n      write: jest.fn(),\n    };\n    writeStreamMock = jest.fn(() => writeStreamInstanceMock);\n\n    file = new VolatileFile({\n      xname: 'cat.png',\n      originalFilename: 'cat.png',\n      mimetype: 'image/png',\n      createFileWriteStream: writeStreamMock,\n    });\n\n    file.open();\n  });\n\n  test('open()', (done) => {\n    const error = new Error('test');\n    file.on('error', (err) => {\n      expect(err).toBe(error);\n      done();\n    });\n\n    file.emit('error', error);\n\n    expect(writeStreamMock).toBeCalled();\n    expect(writeStreamInstanceMock.on).toBeCalledWith(\n      'error',\n      expect.any(Function),\n    );\n  });\n\n  test('toJSON()', () => {\n    const obj = file.toJSON();\n\n    expect(obj.mimetype).toBe('image/png');\n    expect(obj.originalFilename).toBe('cat.png');\n  });\n\n  test('toString()', () => {\n    expect(file.toString()).toBe('VolatileFile: cat.png');\n  });\n\n  test('write()', (done) => {\n    const buffer = Buffer.alloc(5);\n    writeStreamInstanceMock.write.mockImplementationOnce((writeBuffer, cb) => {\n      expect(buffer).toBe(writeBuffer);\n      cb();\n    });\n\n    file.write(buffer, () => {\n      done();\n    });\n  });\n\n  test('end()', (done) => {\n    writeStreamInstanceMock.end.mockImplementationOnce((cb) => {\n      cb();\n    });\n    const fileEmitSpy = jest.spyOn(file, 'emit');\n\n    file.end(() => done());\n\n    expect(fileEmitSpy).toBeCalledWith('end');\n  });\n\n  test('destroy()', () => {\n    file.destroy();\n    expect(writeStreamInstanceMock.destroy).toBeCalled();\n  });\n});\n"
  },
  {
    "path": "test-legacy/README.md",
    "content": "These tests were deleted due to failures when removing the gently lib.\npreviously in `test/legacy`\n"
  },
  {
    "path": "test-legacy/common.js",
    "content": "const path = require('path');\nconst fs = require('fs');\n\nexports.lib = path.join(__dirname, '../../lib');\n\nglobal.assert = require('assert');\n\nglobal.TEST_PORT = 13532;\nglobal.TEST_FIXTURES = path.join(__dirname, '../fixture');\nglobal.TEST_TMP = path.join(__dirname, '../tmp');\n\n// Stupid new feature in node that complains about gently attaching too many\n// listeners to process 'exit'. This is a workaround until I can think of a\n// better way to deal with this.\nif (process.setMaxListeners) {\n  process.setMaxListeners(10000);\n}\n"
  },
  {
    "path": "test-legacy/integration/test-multipart-parser.js",
    "content": "const common = require('../common');\n\nconst CHUNK_LENGTH = 10;\nconst multipartParser = require(`${common.lib}/multipart_parser`);\nconst { MultipartParser } = multipartParser;\nconst parser = new MultipartParser();\nconst fixtures = require(`${TEST_FIXTURES}/multipart`);\n\nObject.keys(fixtures).forEach(function(name) {\n  const fixture = fixtures[name];\n  const buffer = Buffer.alloc(Buffer.byteLength(fixture.raw, 'binary'));\n  let offset = 0;\n  let chunk;\n  let nparsed;\n\n  const parts = [];\n  let part = null;\n  let headerField;\n  let headerValue;\n  let endCalled = '';\n\n  parser.initWithBoundary(fixture.boundary);\n  parser.onPartBegin = function() {\n    part = { headers: {}, data: '' };\n    parts.push(part);\n    headerField = '';\n    headerValue = '';\n  };\n\n  parser.onHeaderField = function(b, start, end) {\n    headerField += b.toString('ascii', start, end);\n  };\n\n  parser.onHeaderValue = function(b, start, end) {\n    headerValue += b.toString('ascii', start, end);\n  };\n\n  parser.onHeaderEnd = function() {\n    part.headers[headerField] = headerValue;\n    headerField = '';\n    headerValue = '';\n  };\n\n  parser.onPartData = function(b, start, end) {\n    const str = b.toString('ascii', start, end);\n    part.data += b.slice(start, end);\n  };\n\n  parser.onEnd = function() {\n    endCalled = true;\n  };\n\n  buffer.write(fixture.raw, 0, undefined, 'binary');\n\n  while (offset < buffer.length) {\n    if (offset + CHUNK_LENGTH < buffer.length) {\n      chunk = buffer.slice(offset, offset + CHUNK_LENGTH);\n    } else {\n      chunk = buffer.slice(offset, buffer.length);\n    }\n    offset += CHUNK_LENGTH;\n\n    nparsed = parser.write(chunk);\n    if (nparsed != chunk.length) {\n      if (fixture.expectError) {\n        return;\n      }\n      puts('-- ERROR --');\n      p(chunk.toString('ascii'));\n      throw new Error(\n        `${chunk.length} bytes written, but only ${nparsed} bytes parsed!`,\n      );\n    }\n  }\n\n  if (fixture.expectError) {\n    throw new Error('expected parse error did not happen');\n  }\n\n  assert.ok(endCalled);\n  assert.deepEqual(parts, fixture.parts);\n});\n"
  },
  {
    "path": "test-legacy/simple/test-file.js",
    "content": "const common = require('../common');\n\nconst WriteStreamStub = GENTLY.stub('fs', 'WriteStream');\n\nconst File = require(`${common.lib}/file`);\nconst { EventEmitter } = require('events');\n\nlet file;\nlet gently;\n\nfunction test(test) {\n  gently = new Gently();\n  file = new File();\n  test();\n  gently.verify(test.name);\n}\n\ntest(function constructor() {\n  assert.ok(file instanceof EventEmitter);\n  assert.strictEqual(file.size, 0);\n  assert.strictEqual(file.path, null);\n  assert.strictEqual(file.name, null);\n  assert.strictEqual(file.type, null);\n  assert.strictEqual(file.lastModifiedDate, null);\n\n  assert.strictEqual(file._writeStream, null);\n\n  (function testSetProperties() {\n    const file2 = new File({ foo: 'bar' });\n    assert.equal(file2.foo, 'bar');\n  })();\n});\n\ntest(function open() {\n  let WRITE_STREAM;\n  file.path = '/foo';\n\n  gently.expect(WriteStreamStub, 'new', function(path) {\n    WRITE_STREAM = this;\n    assert.strictEqual(path, file.path);\n  });\n\n  file.open();\n  assert.strictEqual(file._writeStream, WRITE_STREAM);\n});\n\ntest(function write() {\n  const BUFFER = { length: 10 };\n  let CB_STUB;\n  const CB = function() {\n    CB_STUB.apply(this, arguments);\n  };\n\n  file._writeStream = {};\n\n  gently.expect(file._writeStream, 'write', function(buffer, cb) {\n    assert.strictEqual(buffer, BUFFER);\n\n    gently.expect(file, 'emit', function(event, bytesWritten) {\n      assert.ok(file.lastModifiedDate instanceof Date);\n      assert.equal(event, 'progress');\n      assert.equal(bytesWritten, file.size);\n    });\n\n    CB_STUB = gently.expect(function writeCb() {\n      assert.equal(file.size, 10);\n    });\n\n    cb();\n\n    gently.expect(file, 'emit', function(event, bytesWritten) {\n      assert.equal(event, 'progress');\n      assert.equal(bytesWritten, file.size);\n    });\n\n    CB_STUB = gently.expect(function writeCb() {\n      assert.equal(file.size, 20);\n    });\n\n    cb();\n  });\n\n  file.write(BUFFER, CB);\n});\n\ntest(function end() {\n  let CB_STUB;\n  const CB = function() {\n    CB_STUB.apply(this, arguments);\n  };\n\n  file._writeStream = {};\n\n  gently.expect(file._writeStream, 'end', function(cb) {\n    gently.expect(file, 'emit', function(event) {\n      assert.equal(event, 'end');\n    });\n\n    CB_STUB = gently.expect(function endCb() {});\n\n    cb();\n  });\n\n  file.end(CB);\n});\n"
  },
  {
    "path": "test-legacy/simple/test-incoming-form.js",
    "content": "const common = require('../common');\n\nconst MultipartParserStub = GENTLY.stub(\n  './multipart_parser',\n  'MultipartParser',\n);\nconst QuerystringParserStub = GENTLY.stub(\n  './querystring_parser',\n  'QuerystringParser',\n);\nconst EventEmitterStub = GENTLY.stub('events', 'EventEmitter');\nconst StreamStub = GENTLY.stub('stream', 'Stream');\nconst FileStub = GENTLY.stub('./file');\n\nconst formidable = require(`${common.lib}/index`);\nconst { IncomingForm } = formidable;\nconst events = require('events');\nconst fs = require('fs');\nconst path = require('path');\n\nconst fixtures = require(`${TEST_FIXTURES}/multipart`);\nlet form;\nlet gently;\n\nfunction test(test) {\n  gently = new Gently();\n  gently.expect(EventEmitterStub, 'call');\n  form = new IncomingForm();\n  test();\n  gently.verify(test.name);\n}\n\ntest(function constructor() {\n  assert.strictEqual(form.error, null);\n  assert.strictEqual(form.ended, false);\n  assert.strictEqual(form.type, null);\n  assert.strictEqual(form.headers, null);\n  assert.strictEqual(form.keepExtensions, false);\n  // Can't assume dir === '/tmp' for portability\n  // assert.strictEqual(form.uploadDir, '/tmp');\n  // Make sure it is a directory instead\n  assert.doesNotThrow(function() {\n    assert(fs.statSync(form.uploadDir).isDirectory());\n  });\n  assert.strictEqual(form.encoding, 'utf-8');\n  assert.strictEqual(form.bytesReceived, null);\n  assert.strictEqual(form.bytesExpected, null);\n  assert.strictEqual(form.maxFieldsSize, 20 * 1024 * 1024);\n  assert.strictEqual(form._parser, null);\n  assert.strictEqual(form._flushing, 0);\n  assert.strictEqual(form._fieldsSize, 0);\n  assert.ok(form instanceof EventEmitterStub);\n  assert.equal(form.constructor.name, 'IncomingForm');\n\n  (function testSimpleConstructor() {\n    gently.expect(EventEmitterStub, 'call');\n    const form = IncomingForm();\n    assert.ok(form instanceof IncomingForm);\n  })();\n\n  (function testSimpleConstructorShortcut() {\n    gently.expect(EventEmitterStub, 'call');\n    const form = formidable();\n    assert.ok(form instanceof IncomingForm);\n  })();\n});\n\ntest(function parse() {\n  const REQ = { headers: {} };\n  const emit = {};\n\n  gently.expect(form, 'writeHeaders', function(headers) {\n    assert.strictEqual(headers, REQ.headers);\n  });\n\n  const EVENTS = ['error', 'aborted', 'data', 'end'];\n  gently.expect(REQ, 'on', EVENTS.length, function(event, fn) {\n    assert.equal(event, EVENTS.shift());\n    emit[event] = fn;\n    return this;\n  });\n\n  form.parse(REQ);\n\n  (function testPause() {\n    gently.expect(REQ, 'pause');\n    assert.strictEqual(form.pause(), true);\n  })();\n\n  (function testPauseCriticalException() {\n    form.ended = false;\n\n    const ERR = new Error('dasdsa');\n    gently.expect(REQ, 'pause', function() {\n      throw ERR;\n    });\n\n    gently.expect(form, '_error', function(err) {\n      assert.strictEqual(err, ERR);\n    });\n\n    assert.strictEqual(form.pause(), false);\n  })();\n\n  (function testPauseHarmlessException() {\n    form.ended = true;\n\n    const ERR = new Error('dasdsa');\n    gently.expect(REQ, 'pause', function() {\n      throw ERR;\n    });\n\n    assert.strictEqual(form.pause(), false);\n  })();\n\n  (function testResume() {\n    gently.expect(REQ, 'resume');\n    assert.strictEqual(form.resume(), true);\n  })();\n\n  (function testResumeCriticalException() {\n    form.ended = false;\n\n    const ERR = new Error('dasdsa');\n    gently.expect(REQ, 'resume', function() {\n      throw ERR;\n    });\n\n    gently.expect(form, '_error', function(err) {\n      assert.strictEqual(err, ERR);\n    });\n\n    assert.strictEqual(form.resume(), false);\n  })();\n\n  (function testResumeHarmlessException() {\n    form.ended = true;\n\n    const ERR = new Error('dasdsa');\n    gently.expect(REQ, 'resume', function() {\n      throw ERR;\n    });\n\n    assert.strictEqual(form.resume(), false);\n  })();\n\n  (function testEmitError() {\n    const ERR = new Error('something bad happened');\n    gently.expect(form, '_error', function(err) {\n      assert.strictEqual(err, ERR);\n    });\n    emit.error(ERR);\n  })();\n\n  (function testEmitAborted() {\n    gently.expect(form, 'emit', function(event) {\n      assert.equal(event, 'aborted');\n    });\n    gently.expect(form, '_error');\n\n    emit.aborted();\n  })();\n\n  (function testEmitData() {\n    const BUFFER = [1, 2, 3];\n    gently.expect(form, 'write', function(buffer) {\n      assert.strictEqual(buffer, BUFFER);\n    });\n    emit.data(BUFFER);\n  })();\n\n  (function testEmitEnd() {\n    form._parser = {};\n\n    (function testWithError() {\n      const ERR = new Error('haha');\n      gently.expect(form._parser, 'end', function() {\n        return ERR;\n      });\n\n      gently.expect(form, '_error', function(err) {\n        assert.strictEqual(err, ERR);\n      });\n\n      emit.end();\n    })();\n\n    (function testWithoutError() {\n      gently.expect(form._parser, 'end');\n      emit.end();\n    })();\n\n    (function testAfterError() {\n      form.error = true;\n      emit.end();\n    })();\n  })();\n\n  (function testWithCallback() {\n    gently.expect(EventEmitterStub, 'call');\n    const form = new IncomingForm();\n    const REQ = { headers: {} };\n    const parseCalled = 0;\n\n    gently.expect(form, 'on', 4, function(event, fn) {\n      if (event == 'field') {\n        fn('field1', 'foo');\n        fn('field1', 'bar');\n        fn('field2', 'nice');\n      }\n\n      if (event == 'file') {\n        fn('file1', '1');\n        fn('file1', '2');\n        fn('file2', '3');\n      }\n\n      if (event == 'end') {\n        fn();\n      }\n      return this;\n    });\n\n    gently.expect(form, 'writeHeaders');\n\n    gently.expect(REQ, 'on', 4, function() {\n      return this;\n    });\n\n    const parseCbOk = function(err, fields, files) {\n      // assert.deepEqual(fields, {field1: ['foo', 'bar'], field2: 'nice'});\n      assert.deepEqual(files, { file1: '2', file2: '3' });\n    };\n    form.parse(REQ, parseCbOk);\n\n    const ERR = new Error('test');\n    gently.expect(form, 'on', 3, function(event, fn) {\n      if (event == 'field') {\n        fn('foo', 'bar');\n      }\n\n      if (event == 'error') {\n        fn(ERR);\n        gently.expect(form, 'on');\n        gently.expect(form, 'writeHeaders');\n        gently.expect(REQ, 'on', 4, function() {\n          return this;\n        });\n      }\n      return this;\n    });\n\n    form.parse(REQ, function parseCbErr(err, fields, files) {\n      assert.strictEqual(err, ERR);\n      assert.deepEqual(fields, { foo: 'bar' });\n    });\n  })();\n\n  (function testWriteOrder() {\n    gently.expect(EventEmitterStub, 'call');\n    const form = new IncomingForm();\n    const REQ = new events.EventEmitter();\n    const BUF = {};\n    const DATACB = null;\n\n    REQ.on('newListener', function(event, fn) {\n      if (event === 'data') fn(BUF);\n    });\n\n    gently.expect(form, 'writeHeaders');\n    gently.expect(form, 'write', function(buf) {\n      assert.strictEqual(buf, BUF);\n    });\n\n    form.parse(REQ);\n  })();\n});\n\ntest(function pause() {\n  assert.strictEqual(form.pause(), false);\n});\n\ntest(function resume() {\n  assert.strictEqual(form.resume(), false);\n});\n\ntest(function writeHeaders() {\n  const HEADERS = {};\n  gently.expect(form, '_parseContentLength');\n  gently.expect(form, '_parseContentType');\n\n  form.writeHeaders(HEADERS);\n  assert.strictEqual(form.headers, HEADERS);\n});\n\ntest(function write() {\n  const parser = {};\n  const BUFFER = [1, 2, 3];\n\n  form._parser = parser;\n  form.bytesExpected = 523423;\n\n  (function testBasic() {\n    gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {\n      assert.equal(event, 'progress');\n      assert.equal(bytesReceived, BUFFER.length);\n      assert.equal(bytesExpected, form.bytesExpected);\n    });\n\n    gently.expect(parser, 'write', function(buffer) {\n      assert.strictEqual(buffer, BUFFER);\n      return buffer.length;\n    });\n\n    assert.equal(form.write(BUFFER), BUFFER.length);\n    assert.equal(form.bytesReceived, BUFFER.length);\n  })();\n\n  (function testParserError() {\n    gently.expect(form, 'emit');\n\n    gently.expect(parser, 'write', function(buffer) {\n      assert.strictEqual(buffer, BUFFER);\n      return buffer.length - 1;\n    });\n\n    gently.expect(form, '_error', function(err) {\n      assert.ok(err.message.match(/parser error/i));\n    });\n\n    assert.equal(form.write(BUFFER), BUFFER.length - 1);\n    assert.equal(form.bytesReceived, BUFFER.length + BUFFER.length);\n  })();\n\n  (function testUninitialized() {\n    delete form._parser;\n\n    gently.expect(form, '_error', function(err) {\n      assert.ok(err.message.match(/uninitialized parser/i));\n    });\n    form.write(BUFFER);\n  })();\n});\n\ntest(function parseContentType() {\n  const HEADERS = {};\n\n  form.headers = { 'content-type': 'application/x-www-form-urlencoded' };\n  gently.expect(form, '_initUrlencoded');\n  form._parseContentType();\n\n  // accept anything that has 'urlencoded' in it\n  form.headers = { 'content-type': 'broken-client/urlencoded-stupid' };\n  gently.expect(form, '_initUrlencoded');\n  form._parseContentType();\n\n  const BOUNDARY = '---------------------------57814261102167618332366269';\n  form.headers = {\n    'content-type': `multipart/form-data; boundary=${BOUNDARY}`,\n  };\n\n  gently.expect(form, '_initMultipart', function(boundary) {\n    assert.equal(boundary, BOUNDARY);\n  });\n  form._parseContentType();\n\n  (function testQuotedBoundary() {\n    form.headers = {\n      'content-type': `multipart/form-data; boundary=\"${BOUNDARY}\"`,\n    };\n\n    gently.expect(form, '_initMultipart', function(boundary) {\n      assert.equal(boundary, BOUNDARY);\n    });\n    form._parseContentType();\n  })();\n\n  (function testNoBoundary() {\n    form.headers = { 'content-type': 'multipart/form-data' };\n\n    gently.expect(form, '_error', function(err) {\n      assert.ok(err.message.match(/no multipart boundary/i));\n    });\n    form._parseContentType();\n  })();\n\n  (function testNoContentType() {\n    form.headers = {};\n\n    gently.expect(form, '_error', function(err) {\n      assert.ok(err.message.match(/no content-type/i));\n    });\n    form._parseContentType();\n  })();\n\n  (function testUnknownContentType() {\n    form.headers = { 'content-type': 'invalid' };\n\n    gently.expect(form, '_error', function(err) {\n      assert.ok(err.message.match(/unknown content-type/i));\n    });\n    form._parseContentType();\n  })();\n});\n\ntest(function parseContentLength() {\n  const HEADERS = {};\n\n  form.headers = {};\n  gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {\n    assert.equal(event, 'progress');\n    assert.equal(bytesReceived, 0);\n    assert.equal(bytesExpected, 0);\n  });\n  form._parseContentLength();\n\n  form.headers['content-length'] = '8';\n  gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {\n    assert.equal(event, 'progress');\n    assert.equal(bytesReceived, 0);\n    assert.equal(bytesExpected, 8);\n  });\n  form._parseContentLength();\n  assert.strictEqual(form.bytesReceived, 0);\n  assert.strictEqual(form.bytesExpected, 8);\n\n  // JS can be evil, lets make sure we are not\n  form.headers['content-length'] = '08';\n  gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {\n    assert.equal(event, 'progress');\n    assert.equal(bytesReceived, 0);\n    assert.equal(bytesExpected, 8);\n  });\n  form._parseContentLength();\n  assert.strictEqual(form.bytesExpected, 8);\n});\n\ntest(function _initMultipart() {\n  const BOUNDARY = '123';\n  let PARSER;\n\n  gently.expect(MultipartParserStub, 'new', function() {\n    PARSER = this;\n  });\n\n  gently.expect(MultipartParserStub.prototype, 'initWithBoundary', function(\n    boundary,\n  ) {\n    assert.equal(boundary, BOUNDARY);\n  });\n\n  form._initMultipart(BOUNDARY);\n  assert.equal(form.type, 'multipart');\n  assert.strictEqual(form._parser, PARSER);\n\n  (function testRegularField() {\n    let PART;\n    gently.expect(StreamStub, 'new', function() {\n      PART = this;\n    });\n\n    gently.expect(form, 'onPart', function(part) {\n      assert.strictEqual(part, PART);\n      assert.deepEqual(part.headers, {\n        'content-disposition': 'form-data; name=\"field1\"',\n        foo: 'bar',\n      });\n      assert.equal(part.name, 'field1');\n\n      const strings = ['hello', ' world'];\n      gently.expect(part, 'emit', 2, function(event, b) {\n        assert.equal(event, 'data');\n        assert.equal(b.toString(), strings.shift());\n      });\n\n      gently.expect(part, 'emit', function(event, b) {\n        assert.equal(event, 'end');\n      });\n    });\n\n    PARSER.onPartBegin();\n    PARSER.onHeaderField(Buffer.from('content-disposition'), 0, 10);\n    PARSER.onHeaderField(Buffer.from('content-disposition'), 10, 19);\n    PARSER.onHeaderValue(Buffer.from('form-data; name=\"field1\"'), 0, 14);\n    PARSER.onHeaderValue(Buffer.from('form-data; name=\"field1\"'), 14, 24);\n    PARSER.onHeaderEnd();\n    PARSER.onHeaderField(Buffer.from('foo'), 0, 3);\n    PARSER.onHeaderValue(Buffer.from('bar'), 0, 3);\n    PARSER.onHeaderEnd();\n    PARSER.onHeadersEnd();\n    PARSER.onPartData(Buffer.from('hello world'), 0, 5);\n    PARSER.onPartData(Buffer.from('hello world'), 5, 11);\n    PARSER.onPartEnd();\n  })();\n\n  (function testFileField() {\n    let PART;\n    gently.expect(StreamStub, 'new', function() {\n      PART = this;\n    });\n\n    gently.expect(form, 'onPart', function(part) {\n      assert.deepEqual(part.headers, {\n        'content-disposition':\n          'form-data; name=\"field2\"; filename=\"C:\\\\Documents and Settings\\\\IE\\\\Must\\\\Die\\\\Sun\"et.jpg\"',\n        'content-type': 'text/plain',\n      });\n      assert.equal(part.name, 'field2');\n      assert.equal(part.filename, 'Sun\"et.jpg');\n      assert.equal(part.mime, 'text/plain');\n\n      gently.expect(part, 'emit', function(event, b) {\n        assert.equal(event, 'data');\n        assert.equal(b.toString(), '... contents of file1.txt ...');\n      });\n\n      gently.expect(part, 'emit', function(event, b) {\n        assert.equal(event, 'end');\n      });\n    });\n\n    PARSER.onPartBegin();\n    PARSER.onHeaderField(Buffer.from('content-disposition'), 0, 19);\n    PARSER.onHeaderValue(\n      Buffer.from(\n        'form-data; name=\"field2\"; filename=\"C:\\\\Documents and Settings\\\\IE\\\\Must\\\\Die\\\\Sun\"et.jpg\"',\n      ),\n      0,\n      85,\n    );\n    PARSER.onHeaderEnd();\n    PARSER.onHeaderField(Buffer.from('Content-Type'), 0, 12);\n    PARSER.onHeaderValue(Buffer.from('text/plain'), 0, 10);\n    PARSER.onHeaderEnd();\n    PARSER.onHeadersEnd();\n    PARSER.onPartData(Buffer.from('... contents of file1.txt ...'), 0, 29);\n    PARSER.onPartEnd();\n  })();\n\n  (function testEnd() {\n    gently.expect(form, '_maybeEnd');\n    PARSER.onEnd();\n    assert.ok(form.ended);\n  })();\n});\n\ntest(function _fileName() {\n  // TODO\n});\n\ntest(function _initUrlencoded() {\n  let PARSER;\n\n  gently.expect(QuerystringParserStub, 'new', function() {\n    PARSER = this;\n  });\n\n  form._initUrlencoded();\n  assert.equal(form.type, 'urlencoded');\n  assert.strictEqual(form._parser, PARSER);\n\n  (function testOnField() {\n    const KEY = 'KEY';\n    const VAL = 'VAL';\n    gently.expect(form, 'emit', function(field, key, val) {\n      assert.equal(field, 'field');\n      assert.equal(key, KEY);\n      assert.equal(val, VAL);\n    });\n\n    PARSER.onField(KEY, VAL);\n  })();\n\n  (function testOnEnd() {\n    gently.expect(form, '_maybeEnd');\n\n    PARSER.onEnd();\n    assert.equal(form.ended, true);\n  })();\n});\n\ntest(function _error() {\n  const ERR = new Error('bla');\n\n  gently.expect(form, 'emit', function(event, err) {\n    assert.equal(event, 'error');\n    assert.strictEqual(err, ERR);\n  });\n\n  form._error(ERR);\n  assert.strictEqual(form.error, ERR);\n\n  // make sure _error only does its thing once\n  form._error(ERR);\n});\n\ntest(function onPart() {\n  const PART = {};\n  gently.expect(form, 'handlePart', function(part) {\n    assert.strictEqual(part, PART);\n  });\n\n  form.onPart(PART);\n});\n\ntest(function handlePart() {\n  (function testUtf8Field() {\n    const PART = new events.EventEmitter();\n    PART.name = 'my_field';\n\n    gently.expect(form, 'emit', function(event, field, value) {\n      assert.equal(event, 'field');\n      assert.equal(field, 'my_field');\n      assert.equal(value, 'hello world: €');\n    });\n\n    form.handlePart(PART);\n    PART.emit('data', Buffer.from('hello'));\n    PART.emit('data', Buffer.from(' world: '));\n    PART.emit('data', Buffer.from([0xe2]));\n    PART.emit('data', Buffer.from([0x82, 0xac]));\n    PART.emit('end');\n  })();\n\n  (function testBinaryField() {\n    const PART = new events.EventEmitter();\n    PART.name = 'my_field2';\n\n    gently.expect(form, 'emit', function(event, field, value) {\n      assert.equal(event, 'field');\n      assert.equal(field, 'my_field2');\n      assert.equal(\n        value,\n        `hello world: ${Buffer.from([0xe2, 0x82, 0xac]).toString('binary')}`,\n      );\n    });\n\n    form.encoding = 'binary';\n    form.handlePart(PART);\n    PART.emit('data', Buffer.from('hello'));\n    PART.emit('data', Buffer.from(' world: '));\n    PART.emit('data', Buffer.from([0xe2]));\n    PART.emit('data', Buffer.from([0x82, 0xac]));\n    PART.emit('end');\n  })();\n\n  (function testFieldSize() {\n    form.maxFieldsSize = 8;\n    const PART = new events.EventEmitter();\n    PART.name = 'my_field';\n\n    gently.expect(form, '_error', function(err) {\n      assert.equal(\n        err.message,\n        'maxFieldsSize exceeded, received 9 bytes of field data',\n      );\n    });\n\n    form.handlePart(PART);\n    form._fieldsSize = 1;\n    PART.emit('data', Buffer.alloc(7));\n    PART.emit('data', Buffer.alloc(1));\n  })();\n\n  (function testFilePart() {\n    const PART = new events.EventEmitter();\n    let FILE = new events.EventEmitter();\n    const PATH = '/foo/bar';\n\n    PART.name = 'my_file';\n    PART.filename = 'sweet.txt';\n    PART.mime = 'sweet.txt';\n\n    gently.expect(form, '_uploadPath', function(filename) {\n      assert.equal(filename, PART.filename);\n      return PATH;\n    });\n\n    gently.expect(FileStub, 'new', function(properties) {\n      assert.equal(properties.path, PATH);\n      assert.equal(properties.name, PART.filename);\n      assert.equal(properties.type, PART.mime);\n      FILE = this;\n\n      gently.expect(form, 'emit', function(event, field, file) {\n        assert.equal(event, 'fileBegin');\n        assert.strictEqual(field, PART.name);\n        assert.strictEqual(file, FILE);\n      });\n\n      gently.expect(FILE, 'open');\n    });\n\n    form.handlePart(PART);\n    assert.equal(form._flushing, 1);\n\n    let BUFFER;\n    gently.expect(form, 'pause');\n    gently.expect(FILE, 'write', function(buffer, cb) {\n      assert.strictEqual(buffer, BUFFER);\n      gently.expect(form, 'resume');\n      // @todo handle cb(new Err)\n      cb();\n    });\n\n    PART.emit('data', (BUFFER = Buffer.from('test')));\n\n    gently.expect(FILE, 'end', function(cb) {\n      gently.expect(form, 'emit', function(event, field, file) {\n        assert.equal(event, 'file');\n        assert.strictEqual(file, FILE);\n      });\n\n      gently.expect(form, '_maybeEnd');\n\n      cb();\n      assert.equal(form._flushing, 0);\n    });\n\n    PART.emit('end');\n  })();\n});\n\ntest(function _uploadPath() {\n  (function testUniqueId() {\n    let UUID_A;\n    let UUID_B;\n    gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) {\n      assert.equal(uploadDir, form.uploadDir);\n      UUID_A = uuid;\n    });\n    form._uploadPath();\n\n    gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) {\n      UUID_B = uuid;\n    });\n    form._uploadPath();\n\n    assert.notEqual(UUID_A, UUID_B);\n  })();\n\n  (function testFileExtension() {\n    form.keepExtensions = true;\n    const FILENAME = 'foo.jpg';\n    const EXT = '.bar';\n\n    gently.expect(GENTLY.hijacked.path, 'extname', function(filename) {\n      assert.equal(filename, FILENAME);\n      gently.restore(path, 'extname');\n\n      return EXT;\n    });\n\n    gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, name) {\n      assert.equal(path.extname(name), EXT);\n    });\n    form._uploadPath(FILENAME);\n  })();\n});\n\ntest(function _maybeEnd() {\n  gently.expect(form, 'emit', 0);\n  form._maybeEnd();\n\n  form.ended = true;\n  form._flushing = 1;\n  form._maybeEnd();\n\n  gently.expect(form, 'emit', function(event) {\n    assert.equal(event, 'end');\n  });\n\n  form.ended = true;\n  form._flushing = 0;\n  form._maybeEnd();\n});\n"
  },
  {
    "path": "test-legacy/system/test-multi-video-upload.js",
    "content": "const common = require('../common');\n\nconst BOUNDARY = '---------------------------10102754414578508781458777923';\nconst FIXTURE = `${TEST_FIXTURES}/multi_video.upload`;\nconst fs = require('fs');\nconst http = require('http');\n\nconst formidable = require(`${common.lib}/index`);\nconst server = http.createServer();\n\nserver.on('request', function(req, res) {\n  const form = new formidable.IncomingForm();\n  const uploads = {};\n\n  form.uploadDir = TEST_TMP;\n  form.hash = 'sha1';\n  form.parse(req);\n\n  form\n    .on('fileBegin', function(field, file) {\n      assert.equal(field, 'upload');\n\n      const tracker = { file, progress: [], ended: false };\n      uploads[file.name] = tracker;\n      file\n        .on('progress', function(bytesReceived) {\n          tracker.progress.push(bytesReceived);\n          assert.equal(bytesReceived, file.size);\n        })\n        .on('end', function() {\n          tracker.ended = true;\n        });\n    })\n    .on('field', function(field, value) {\n      assert.equal(field, 'title');\n      assert.equal(value, '');\n    })\n    .on('file', function(field, file) {\n      assert.equal(field, 'upload');\n      assert.strictEqual(uploads[file.name].file, file);\n    })\n    .on('end', function() {\n      assert.ok(uploads['shortest_video.flv']);\n      assert.ok(uploads['shortest_video.flv'].ended);\n      assert.ok(uploads['shortest_video.flv'].progress.length > 3);\n      assert.equal(\n        uploads['shortest_video.flv'].file.hash,\n        'd6a17616c7143d1b1438ceeef6836d1a09186b3a',\n      );\n      assert.equal(\n        uploads['shortest_video.flv'].progress.slice(-1),\n        uploads['shortest_video.flv'].file.size,\n      );\n      assert.ok(uploads['shortest_video.mp4']);\n      assert.ok(uploads['shortest_video.mp4'].ended);\n      assert.ok(uploads['shortest_video.mp4'].progress.length > 3);\n      assert.equal(\n        uploads['shortest_video.mp4'].file.hash,\n        '937dfd4db263f4887ceae19341dcc8d63bcd557f',\n      );\n\n      server.close();\n      res.writeHead(200);\n      res.end('good');\n    });\n});\n\nserver.listen(TEST_PORT, function() {\n  let stat;\n  let headers;\n  let request;\n  let fixture;\n\n  stat = fs.statSync(FIXTURE);\n  request = http.request({\n    port: TEST_PORT,\n    path: '/',\n    method: 'POST',\n    headers: {\n      'content-type': `multipart/form-data; boundary=${BOUNDARY}`,\n      'content-length': stat.size,\n    },\n  });\n  fs.createReadStream(FIXTURE).pipe(request);\n});\n"
  },
  {
    "path": "test-node/standalone/createDirsFromUploads.test.js",
    "content": "import {strictEqual, deepEqual} from 'node:assert';\nimport { createServer, request } from 'node:http';\nimport formidable from '../../src/index.js';\nimport test from 'node:test';\nimport fs from 'node:fs';\n\nconst PORT = 13539;\nconst uploads = './uploads';\n\ntest('folder created', (t,done) => {\n  const server = createServer((req, res) => {\n    const form = formidable({\n      createDirsFromUploads: true,\n      uploadDir: uploads,\n      filename: (x) => {\n        return 'x/y/z.txt'\n      }\n    });\n\n    form.parse(req, () => {\n      res.writeHead(200);\n      res.end(\"ok\")\n    });\n  });\n\n  server.listen(PORT, () => {\n    const chosenPort = server.address().port;\n    const  body = `----13068458571765726332503797717\\r\nContent-Disposition: form-data; name=\"title\"\\r\n\\r\na\\r\n----13068458571765726332503797717\\r\nContent-Disposition: form-data; name=\"multipleFiles\"; filename=\"x.txt\"\\r\nContent-Type: application/x-javascript\\r\n\\r\n\\r\n\\r\na\\r\nb\\r\nc\\r\nd\\r\n\\r\n----13068458571765726332503797717--\\r\n`;\n    fetch(String(new URL(`http:localhost:${chosenPort}/`)), {\n      method: 'POST',\n      \n      headers: {\n        'Content-Length': body.length,\n        Host: `localhost:${chosenPort}`,\n        'Content-Type': 'multipart/form-data; boundary=--13068458571765726332503797717',\n      },\n      body\n    }).then(res => {\n      //may also contain tests from other tests\n      deepEqual(fs.readdirSync(uploads).includes('x'), true);\n      deepEqual(fs.readdirSync(`${uploads}/x`), ['y']);\n      deepEqual(fs.readdirSync(`${uploads}/x/y`), ['z.txt']);\n      strictEqual(res.status, 200);\n      server.close();\n      done();\n    });\n   \n  });\n});\n"
  },
  {
    "path": "test-node/standalone/end-event-emitted-twice.test.js",
    "content": "import {strictEqual} from 'node:assert';\nimport { createServer, request } from 'node:http';\nimport formidable from '../../src/index.js';\nimport test from 'node:test';\n\nconst PORT = 13540;\n\ntest('end event emitted twice', (t,done) => {\n  const server = createServer((req, res) => {\n    const form = formidable();\n\n    let i = 0;\n    form.on('end', () => {\n      i += 1;\n      strictEqual(i, 1, 'end should be emitted once  (on end)');\n    });\n    form.parse(req, () => {\n      try {\n        strictEqual(i, 1, 'end should be emitted once (callback)');\n      } catch (e) {\n        done(e);\n      }\n      res.writeHead(200);\n      res.end(\"ok\")\n    });\n  });\n\n  server.listen(PORT, () => {\n    const chosenPort = server.address().port;\n    const  body = `----13068458571765726332503797717\\r\nContent-Disposition: form-data; name=\"title\"\\r\n\\r\na\\r\n----13068458571765726332503797717\\r\nContent-Disposition: form-data; name=\"multipleFiles\"; filename=\"x.txt\"\\r\nContent-Type: application/x-javascript\\r\n\\r\n\\r\n\\r\na\\r\nb\\r\nc\\r\nd\\r\n\\r\n----13068458571765726332503797717--\\r\n`;\n    fetch(String(new URL(`http:localhost:${chosenPort}/`)), {\n      method: 'POST',\n      \n      headers: {\n        'Content-Length': body.length,\n        Host: `localhost:${chosenPort}`,\n        'Content-Type': 'multipart/form-data; boundary=--13068458571765726332503797717',\n      },\n      body\n    }).then(res => {\n      strictEqual(res.status, 200);\n        server.close();\n        done();\n    });\n   \n  });\n});\n"
  },
  {
    "path": "test-node/standalone/multipart_parser.test.js",
    "content": "import {Readable} from 'node:stream';\nimport MultipartParser from '../../src/parsers/Multipart.js';\nimport {malformedMultipart} from '../../src/FormidableError.js';\n\nimport test from 'node:test';\nimport assert, { deepEqual } from 'node:assert';\n\n\n\ntest('MultipartParser does not hang', async (t) => {\n    const mime = `--_\\r\\n--_--\\r\\n`;\n    const parser = new MultipartParser();\n    parser.initWithBoundary('_');\n    try {\n        for await (const {name, buffer, start, end} of Readable.from(mime).pipe(parser)) {\n            console.log(name, buffer ? buffer.subarray(start, end).toString() : '');\n        }\n\n    } catch (e) {\n        deepEqual(e.code, malformedMultipart)\n        return;\n        // console.error('error');\n        // console.error(e);\n\n    }\n    assert(false, 'should catch error');\n});"
  },
  {
    "path": "test-node/standalone/promise.test.js",
    "content": "import { ok, strictEqual } from 'node:assert';\nimport { createServer } from 'node:http';\nimport test from 'node:test';\nimport formidable, { errors } from '../../src/index.js';\n\nconst isPromise = (x) => {\n  return x && typeof x === `object` && typeof x.then === `function`;\n};\n\nlet server;\nlet port = 13540;\n\ntest.beforeEach(() => {\n  // Increment port to avoid conflicts between tests\n  port += 1;\n  server = createServer();\n});\n\ntest.afterEach(() => {\n  return new Promise((resolve) => {\n    if (server.listening) {\n      server.close(() => resolve());\n    } else {\n      resolve();\n    }\n  });\n});\n\ntest('parse returns promise if no callback is provided', async (t) => {\n  server.on('request', (req, res) => {\n    const form = formidable();\n\n    const promise = form.parse(req);\n    strictEqual(isPromise(promise), true);\n    promise.then(([fields, files]) => {\n      ok(typeof fields === 'object');\n      ok(typeof files === 'object');\n      res.writeHead(200);\n      res.end(\"ok\");\n    }).catch(e => {\n      res.writeHead(500);\n      res.end(String(e));\n    });\n  });\n\n  await new Promise(resolve => server.listen(port, resolve));\n\n  const body = `----13068458571765726332503797717\\r\nContent-Disposition: form-data; name=\"title\"\\r\n\\r\na\\r\n----13068458571765726332503797717\\r\nContent-Disposition: form-data; name=\"multipleFiles\"; filename=\"x.txt\"\\r\nContent-Type: application/x-javascript\\r\n\\r\n\\r\n\\r\na\\r\nb\\r\nc\\r\nd\\r\n\\r\n----13068458571765726332503797717--\\r\n`;\n\n  const res = await fetch(String(new URL(`http:localhost:${port}/`)), {\n    method: 'POST',\n    headers: {\n      'Content-Length': body.length,\n      Host: `localhost:${port}`,\n      'Content-Type': 'multipart/form-data; boundary=--13068458571765726332503797717',\n    },\n    body\n  });\n\n  strictEqual(res.status, 200);\n});\n\ntest('parse rejects with promise if it fails', async (t) => {\n  server.on('request', (req, res) => {\n    const form = formidable({minFileSize: 10 ** 6}); // create condition to fail\n\n    const promise = form.parse(req);\n    strictEqual(isPromise(promise), true);\n    promise.then(() => {\n      res.writeHead(500);\n      res.end('should have failed');\n    }).catch(e => {\n      res.writeHead(e.httpCode);\n      strictEqual(e.code, errors.smallerThanMinFileSize);\n      res.end(String(e));\n    });\n  });\n\n  await new Promise(resolve => server.listen(port, resolve));\n\n  const body = `----13068458571765726332503797717\\r\nContent-Disposition: form-data; name=\"title\"\\r\n\\r\na\\r\n----13068458571765726332503797717\\r\nContent-Disposition: form-data; name=\"multipleFiles\"; filename=\"x.txt\"\\r\nContent-Type: application/x-javascript\\r\n\\r\n\\r\n\\r\na\\r\nb\\r\nc\\r\nd\\r\n\\r\n----13068458571765726332503797717--\\r\n`;\n\n  const res = await fetch(String(new URL(`http:localhost:${port}/`)), {\n    method: 'POST',\n    headers: {\n      'Content-Length': body.length,\n      Host: `localhost:${port}`,\n      'Content-Type': 'multipart/form-data; boundary=--13068458571765726332503797717',\n    },\n    body\n  });\n\n  strictEqual(res.status, 400);\n});\n"
  },
  {
    "path": "tool/record.js",
    "content": "/* eslint-disable no-param-reassign */\nconst http = require('http');\nconst fs = require('fs');\n\nlet connections = 0;\n\nconst server = http.createServer((req, res) => {\n  const { socket } = req;\n  console.log('Request: %s %s -> %s', req.method, req.url, socket.filename);\n\n  req.on('end', () => {\n    if (req.url !== '/') {\n      res.end(\n        JSON.stringify({\n          method: req.method,\n          url: req.url,\n          filename: socket.filename,\n        }),\n      );\n      return;\n    }\n\n    res.writeHead(200, { 'Content-Type': 'text/html' });\n    res.end(\n      '<form action=\"/upload\" enctype=\"multipart/form-data\" method=\"post\">' +\n        '<input type=\"text\" name=\"title\"><br>' +\n        '<input type=\"file\" name=\"upload\" multiple=\"multiple\"><br>' +\n        '<input type=\"submit\" value=\"Upload\">' +\n        '</form>',\n    );\n  });\n});\n\nserver.on('connection', (socket) => {\n  connections += 1;\n\n  socket.id = connections;\n  socket.filename = `connection-${socket.id}.http`;\n  socket.file = fs.createWriteStream(socket.filename);\n  socket.pipe(socket.file);\n\n  console.log('--> %s', socket.filename);\n  socket.on('close', () => {\n    console.log('<-- %s', socket.filename);\n  });\n});\n\nconst port = process.env.PORT || 8080;\nserver.listen(port, () => {\n  console.log('Recording connections on port %s', port);\n});\n"
  },
  {
    "path": "tool/rollup.config.js",
    "content": "/* eslint-disable */\nimport cjs from '@rollup/plugin-commonjs';\nimport { nodeResolve } from '@rollup/plugin-node-resolve';\nimport packageJson from '../package.json' with { type: \"json\" };\n\nconst {dependencies} = packageJson;\nconst plugins = [nodeResolve(), cjs()];\nconst cjsOptions = {\n  format: `cjs`,\n  exports: `named`,\n}\n\nconst external = [...Object.keys(dependencies)];\n\nexport default [\n  {\n    input: `src/index.js`,\n    output: [\n      {\n        file: `dist/index.cjs`,\n        ...cjsOptions,\n      },\n    ],\n    external,\n    plugins,\n  },\n  {\n    input: `src/helpers/firstValues.js`,\n    output: [\n      {\n        file: `dist/helpers/firstValues.cjs`,\n        ...cjsOptions,\n      },\n    ],\n    external,\n    plugins,\n  },\n  {\n    input: `src/helpers/readBooleans.js`,\n    output: [\n      {\n        file: `dist/helpers/readBooleans.cjs`,\n        ...cjsOptions,\n      },\n    ],\n    external,\n    plugins,\n  },\n  {\n    input: `src/parsers/JSON.js`,\n    output: [\n      {\n        file: `dist/parsers/JSON.cjs`,\n        ...cjsOptions,\n      },\n    ],\n    external,\n    plugins,\n  },\n  {\n    input: `src/parsers/Multipart.js`,\n    output: [\n      {\n        file: `dist/parsers/Multipart.cjs`,\n        ...cjsOptions,\n      },\n    ],\n    external,\n    plugins,\n  },\n  {\n    input: `src/parsers/Querystring.js`,\n    output: [\n      {\n        file: `dist/parsers/Querystring.cjs`,\n        ...cjsOptions,\n      },\n    ],\n    external,\n    plugins,\n  },\n  {\n    input: `src/parsers/OctetStream.js`,\n    output: [\n      {\n        file: `dist/parsers/OctetStream.cjs`,\n        ...cjsOptions,\n      },\n    ],\n    external,\n    plugins,\n  },\n  {\n    input: `src/parsers/StreamingQuerystring.js`,\n    output: [\n      {\n        file: `dist/parsers/StreamingQuerystring.cjs`,\n        ...cjsOptions,\n      },\n    ],\n    external,\n    plugins,\n  },\n];\n\n"
  }
]